Coverage Report

Created: 2026-03-26 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/swift-protobuf/Sources/SwiftProtobuf/JSONMapEncodingVisitor.swift
Line
Count
Source
1
// Sources/SwiftProtobuf/JSONMapEncodingVisitor.swift - JSON map encoding visitor
2
//
3
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
4
// Licensed under Apache License v2.0 with Runtime Library Exception
5
//
6
// See LICENSE.txt for license information:
7
// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
8
//
9
// -----------------------------------------------------------------------------
10
///
11
/// Visitor that writes out the key/value pairs for a JSON map.
12
///
13
// -----------------------------------------------------------------------------
14
15
#if canImport(FoundationEssentials)
16
import FoundationEssentials
17
#else
18
import Foundation
19
#endif
20
21
/// Visitor that serializes a message into JSON map format.
22
///
23
/// This expects to alternately visit the keys and values for a JSON
24
/// map.  It only accepts singular values.  Keys should be identified
25
/// as `fieldNumber:1`, values should be identified as `fieldNumber:2`
26
///
27
internal struct JSONMapEncodingVisitor: SelectiveVisitor {
28
    private var separator: StaticString?
29
    internal var encoder: JSONEncoder
30
    private let options: JSONEncodingOptions
31
32
529k
    init(encoder: JSONEncoder, options: JSONEncodingOptions) {
33
529k
        self.encoder = encoder
34
529k
        self.options = options
35
529k
    }
36
37
    internal var bytesResult: [UInt8] {
38
121k
        get {
39
121k
            encoder.bytesResult
40
121k
        }
41
    }
42
43
1.44M
    private mutating func startKey() {
44
1.44M
        if let s = separator {
45
884k
            encoder.append(staticText: s)
46
884k
        } else {
47
559k
            separator = ","
48
559k
        }
49
1.44M
    }
50
51
1.44M
    private mutating func startValue() {
52
1.44M
        encoder.append(staticText: ":")
53
1.44M
    }
54
55
3.66k
    mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
56
3.66k
        // Doubles/Floats can never be map keys, only values
57
3.66k
        assert(fieldNumber == 2)
58
3.66k
        startValue()
59
3.66k
        encoder.putFloatValue(value: value)
60
3.66k
    }
61
62
4.35k
    mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
63
4.35k
        // Doubles/Floats can never be map keys, only values
64
4.35k
        assert(fieldNumber == 2)
65
4.35k
        startValue()
66
4.35k
        encoder.putDoubleValue(value: value)
67
4.35k
    }
68
69
39.3k
    mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws {
70
39.3k
        if fieldNumber == 1 {
71
20.2k
            startKey()
72
20.2k
            encoder.putQuotedInt32(value: value)
73
20.2k
        } else {
74
19.0k
            startValue()
75
19.0k
            encoder.putNonQuotedInt32(value: value)
76
19.0k
        }
77
39.3k
    }
78
79
165k
    mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
80
165k
        if fieldNumber == 1 {
81
21.3k
            startKey()
82
21.3k
            encoder.putQuotedInt64(value: value)
83
144k
        } else {
84
144k
            startValue()
85
144k
            options.alwaysPrintInt64sAsNumbers
86
144k
                ? encoder.putNonQuotedInt64(value: value)
87
144k
                : encoder.putQuotedInt64(value: value)
88
144k
        }
89
165k
    }
90
91
94.0k
    mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws {
92
94.0k
        if fieldNumber == 1 {
93
85.9k
            startKey()
94
85.9k
            encoder.putQuotedUInt32(value: value)
95
85.9k
        } else {
96
8.14k
            startValue()
97
8.14k
            encoder.putNonQuotedUInt32(value: value)
98
8.14k
        }
99
94.0k
    }
100
101
156k
    mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
102
156k
        if fieldNumber == 1 {
103
145k
            startKey()
104
145k
            encoder.putQuotedUInt64(value: value)
105
145k
        } else {
106
11.0k
            startValue()
107
11.0k
            options.alwaysPrintInt64sAsNumbers
108
11.0k
                ? encoder.putNonQuotedUInt64(value: value)
109
11.0k
                : encoder.putQuotedUInt64(value: value)
110
11.0k
        }
111
156k
    }
112
113
13.7k
    mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws {
114
13.7k
        try visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
115
13.7k
    }
116
117
9.47k
    mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws {
118
9.47k
        try visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
119
9.47k
    }
120
121
83.1k
    mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
122
83.1k
        try visitSingularUInt32Field(value: value, fieldNumber: fieldNumber)
123
83.1k
    }
124
125
141k
    mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws {
126
141k
        try visitSingularUInt64Field(value: value, fieldNumber: fieldNumber)
127
141k
    }
128
129
9.51k
    mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
130
9.51k
        try visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
131
9.51k
    }
132
133
9.51k
    mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws {
134
9.51k
        try visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
135
9.51k
    }
136
137
2.98k
    mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
138
2.98k
        if fieldNumber == 1 {
139
2.98k
            startKey()
140
2.98k
            encoder.putQuotedBoolValue(value: value)
141
2.98k
        } else {
142
0
            startValue()
143
0
            encoder.putNonQuotedBoolValue(value: value)
144
0
        }
145
2.98k
    }
146
147
292k
    mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
148
292k
        if fieldNumber == 1 {
149
283k
            startKey()
150
283k
        } else {
151
9.26k
            startValue()
152
9.26k
        }
153
292k
        encoder.putStringValue(value: value)
154
292k
    }
155
156
3.27k
    mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
157
3.27k
        // Bytes can only be map values, never keys
158
4.86k
        assert(fieldNumber == 2)
159
3.27k
        startValue()
160
3.27k
        encoder.putBytesValue(value: value)
161
3.27k
    }
162
163
4.18k
    mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
164
4.18k
        // Enums can only be map values, never keys
165
4.18k
        assert(fieldNumber == 2)
166
4.18k
        startValue()
167
4.18k
        if !options.alwaysPrintEnumsAsInts, let n = value.name {
168
4.18k
            encoder.putStringValue(value: String(describing: n))
169
4.18k
        } else {
170
0
            encoder.putEnumInt(value: value.rawValue)
171
0
        }
172
4.18k
    }
173
174
587k
    mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
175
587k
        // Messages can only be map values, never keys
176
587k
        assert(fieldNumber == 2)
177
587k
        startValue()
178
587k
        let json = try value.jsonString(options: options)
179
587k
        encoder.append(text: json)
180
587k
    }
181
182
    // SelectiveVisitor will block:
183
    // - single Groups
184
    // - everything repeated
185
    // - everything packed
186
    // - all maps
187
    // - unknown fields
188
    // - extensions
189
}