/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 | | } |