/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 | 53.4k | init(encoder: JSONEncoder, options: JSONEncodingOptions) { |
33 | 53.4k | self.encoder = encoder |
34 | 53.4k | self.options = options |
35 | 53.4k | } |
36 | | |
37 | | internal var bytesResult: [UInt8] { |
38 | 12.5k | get { |
39 | 12.5k | encoder.bytesResult |
40 | 12.5k | } |
41 | | } |
42 | | |
43 | 87.6k | private mutating func startKey() { |
44 | 87.6k | if let s = separator { |
45 | 27.3k | encoder.append(staticText: s) |
46 | 60.3k | } else { |
47 | 60.3k | separator = "," |
48 | 60.3k | } |
49 | 87.6k | } |
50 | | |
51 | 87.6k | private mutating func startValue() { |
52 | 87.6k | encoder.append(staticText: ":") |
53 | 87.6k | } |
54 | | |
55 | 904 | mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws { |
56 | 904 | // Doubles/Floats can never be map keys, only values |
57 | 904 | assert(fieldNumber == 2) |
58 | 904 | startValue() |
59 | 904 | encoder.putFloatValue(value: value) |
60 | 904 | } |
61 | | |
62 | 918 | mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws { |
63 | 918 | // Doubles/Floats can never be map keys, only values |
64 | 918 | assert(fieldNumber == 2) |
65 | 918 | startValue() |
66 | 918 | encoder.putDoubleValue(value: value) |
67 | 918 | } |
68 | | |
69 | 10.5k | mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws { |
70 | 10.5k | if fieldNumber == 1 { |
71 | 5.86k | startKey() |
72 | 5.86k | encoder.putQuotedInt32(value: value) |
73 | 5.86k | } else { |
74 | 4.69k | startValue() |
75 | 4.69k | encoder.putNonQuotedInt32(value: value) |
76 | 4.69k | } |
77 | 10.5k | } |
78 | | |
79 | 9.19k | mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws { |
80 | 9.19k | if fieldNumber == 1 { |
81 | 5.81k | startKey() |
82 | 5.81k | encoder.putQuotedInt64(value: value) |
83 | 5.81k | } else { |
84 | 3.38k | startValue() |
85 | 3.38k | options.alwaysPrintInt64sAsNumbers |
86 | 3.38k | ? encoder.putNonQuotedInt64(value: value) |
87 | 3.38k | : encoder.putQuotedInt64(value: value) |
88 | 3.38k | } |
89 | 9.19k | } |
90 | | |
91 | 6.79k | mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws { |
92 | 6.79k | if fieldNumber == 1 { |
93 | 4.04k | startKey() |
94 | 4.04k | encoder.putQuotedUInt32(value: value) |
95 | 4.04k | } else { |
96 | 2.75k | startValue() |
97 | 2.75k | encoder.putNonQuotedUInt32(value: value) |
98 | 2.75k | } |
99 | 6.79k | } |
100 | | |
101 | 5.44k | mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws { |
102 | 5.44k | if fieldNumber == 1 { |
103 | 2.66k | startKey() |
104 | 2.66k | encoder.putQuotedUInt64(value: value) |
105 | 2.77k | } else { |
106 | 2.77k | startValue() |
107 | 2.77k | options.alwaysPrintInt64sAsNumbers |
108 | 2.77k | ? encoder.putNonQuotedUInt64(value: value) |
109 | 2.77k | : encoder.putQuotedUInt64(value: value) |
110 | 2.77k | } |
111 | 5.44k | } |
112 | | |
113 | 3.60k | mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws { |
114 | 3.60k | try visitSingularInt32Field(value: value, fieldNumber: fieldNumber) |
115 | 3.60k | } |
116 | | |
117 | 4.45k | mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws { |
118 | 4.45k | try visitSingularInt64Field(value: value, fieldNumber: fieldNumber) |
119 | 4.45k | } |
120 | | |
121 | 4.35k | mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws { |
122 | 4.35k | try visitSingularUInt32Field(value: value, fieldNumber: fieldNumber) |
123 | 4.35k | } |
124 | | |
125 | 2.66k | mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws { |
126 | 2.66k | try visitSingularUInt64Field(value: value, fieldNumber: fieldNumber) |
127 | 2.66k | } |
128 | | |
129 | 2.43k | mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws { |
130 | 2.43k | try visitSingularInt32Field(value: value, fieldNumber: fieldNumber) |
131 | 2.43k | } |
132 | | |
133 | 1.32k | mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws { |
134 | 1.32k | try visitSingularInt64Field(value: value, fieldNumber: fieldNumber) |
135 | 1.32k | } |
136 | | |
137 | 683 | mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws { |
138 | 683 | if fieldNumber == 1 { |
139 | 683 | startKey() |
140 | 683 | encoder.putQuotedBoolValue(value: value) |
141 | 683 | } else { |
142 | 0 | startValue() |
143 | 0 | encoder.putNonQuotedBoolValue(value: value) |
144 | 0 | } |
145 | 683 | } |
146 | | |
147 | 3.55k | mutating func visitSingularStringField(value: String, fieldNumber: Int) throws { |
148 | 3.55k | if fieldNumber == 1 { |
149 | 2.99k | startKey() |
150 | 2.99k | } else { |
151 | 564 | startValue() |
152 | 564 | } |
153 | 3.55k | encoder.putStringValue(value: value) |
154 | 3.55k | } |
155 | | |
156 | 1.33k | mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws { |
157 | 1.33k | // Bytes can only be map values, never keys |
158 | 1.97k | assert(fieldNumber == 2) |
159 | 1.33k | startValue() |
160 | 1.33k | encoder.putBytesValue(value: value) |
161 | 1.33k | } |
162 | | |
163 | 782 | mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws { |
164 | 782 | // Enums can only be map values, never keys |
165 | 782 | assert(fieldNumber == 2) |
166 | 782 | startValue() |
167 | 782 | if !options.alwaysPrintEnumsAsInts, let n = value.name { |
168 | 650 | encoder.putStringValue(value: String(describing: n)) |
169 | 650 | } else { |
170 | 132 | encoder.putEnumInt(value: value.rawValue) |
171 | 132 | } |
172 | 782 | } |
173 | | |
174 | 8.52k | mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws { |
175 | 8.52k | // Messages can only be map values, never keys |
176 | 8.52k | assert(fieldNumber == 2) |
177 | 8.52k | startValue() |
178 | 8.52k | let json = try value.jsonString(options: options) |
179 | 8.52k | encoder.append(text: json) |
180 | 8.52k | } |
181 | | |
182 | | // SelectiveVisitor will block: |
183 | | // - single Groups |
184 | | // - everything repeated |
185 | | // - everything packed |
186 | | // - all maps |
187 | | // - unknown fields |
188 | | // - extensions |
189 | | } |