JSONEncodingVisitor.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. // Sources/SwiftProtobuf/JSONEncodingVisitor.swift - JSON 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 a message in JSON format.
  12. ///
  13. // -----------------------------------------------------------------------------
  14. import Foundation
  15. /// Visitor that serializes a message into JSON format.
  16. internal struct JSONEncodingVisitor: Visitor {
  17. private var encoder = JSONEncoder()
  18. private var nameMap: _NameMap
  19. private var extensions: ExtensionFieldValueSet?
  20. private let options: JSONEncodingOptions
  21. /// The JSON text produced by the visitor, as raw UTF8 bytes.
  22. var dataResult: [UInt8] {
  23. encoder.dataResult
  24. }
  25. /// The JSON text produced by the visitor, as a String.
  26. internal var stringResult: String {
  27. encoder.stringResult
  28. }
  29. /// Creates a new visitor for serializing a message of the given type to JSON
  30. /// format.
  31. init(type: any Message.Type, options: JSONEncodingOptions) throws {
  32. if let nameProviding = type as? any _ProtoNameProviding.Type {
  33. self.nameMap = nameProviding._protobuf_nameMap
  34. } else {
  35. throw JSONEncodingError.missingFieldNames
  36. }
  37. self.options = options
  38. }
  39. mutating func startArray() {
  40. encoder.startArray()
  41. }
  42. mutating func endArray() {
  43. encoder.endArray()
  44. }
  45. mutating func startObject(message: any Message) {
  46. self.extensions = (message as? (any ExtensibleMessage))?._protobuf_extensionFieldValues
  47. encoder.startObject()
  48. }
  49. mutating func startArrayObject(message: any Message) {
  50. self.extensions = (message as? (any ExtensibleMessage))?._protobuf_extensionFieldValues
  51. encoder.startArrayObject()
  52. }
  53. mutating func endObject() {
  54. encoder.endObject()
  55. }
  56. mutating func encodeField(name: String, stringValue value: String) {
  57. encoder.startField(name: name)
  58. encoder.putStringValue(value: value)
  59. }
  60. mutating func encodeField(name: String, jsonText text: String) {
  61. encoder.startField(name: name)
  62. encoder.append(text: text)
  63. }
  64. mutating func visitUnknown(bytes: Data) throws {
  65. // JSON encoding has no provision for carrying proto2 unknown fields.
  66. }
  67. mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
  68. try startField(for: fieldNumber)
  69. encoder.putFloatValue(value: value)
  70. }
  71. mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
  72. try startField(for: fieldNumber)
  73. encoder.putDoubleValue(value: value)
  74. }
  75. mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws {
  76. try startField(for: fieldNumber)
  77. encoder.putNonQuotedInt32(value: value)
  78. }
  79. mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
  80. try startField(for: fieldNumber)
  81. options.alwaysPrintInt64sAsNumbers
  82. ? encoder.putNonQuotedInt64(value: value)
  83. : encoder.putQuotedInt64(value: value)
  84. }
  85. mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws {
  86. try startField(for: fieldNumber)
  87. encoder.putNonQuotedUInt32(value: value)
  88. }
  89. mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
  90. try startField(for: fieldNumber)
  91. options.alwaysPrintInt64sAsNumbers
  92. ? encoder.putNonQuotedUInt64(value: value)
  93. : encoder.putQuotedUInt64(value: value)
  94. }
  95. mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
  96. try startField(for: fieldNumber)
  97. encoder.putNonQuotedUInt32(value: value)
  98. }
  99. mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
  100. try startField(for: fieldNumber)
  101. encoder.putNonQuotedInt32(value: value)
  102. }
  103. mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
  104. try startField(for: fieldNumber)
  105. encoder.putNonQuotedBoolValue(value: value)
  106. }
  107. mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
  108. try startField(for: fieldNumber)
  109. encoder.putStringValue(value: value)
  110. }
  111. mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
  112. try startField(for: fieldNumber)
  113. encoder.putBytesValue(value: value)
  114. }
  115. private mutating func _visitRepeated<T>(
  116. value: [T],
  117. fieldNumber: Int,
  118. encode: (inout JSONEncoder, T) throws -> Void
  119. ) throws {
  120. assert(!value.isEmpty)
  121. try startField(for: fieldNumber)
  122. var comma = false
  123. encoder.startArray()
  124. for v in value {
  125. if comma {
  126. encoder.comma()
  127. }
  128. comma = true
  129. try encode(&encoder, v)
  130. }
  131. encoder.endArray()
  132. }
  133. mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
  134. try startField(for: fieldNumber)
  135. if let e = value as? (any _CustomJSONCodable) {
  136. let json = try e.encodedJSONString(options: options)
  137. encoder.append(text: json)
  138. } else if !options.alwaysPrintEnumsAsInts, let n = value.name {
  139. encoder.appendQuoted(name: n)
  140. } else {
  141. encoder.putEnumInt(value: value.rawValue)
  142. }
  143. }
  144. mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
  145. try startField(for: fieldNumber)
  146. if let m = value as? (any _CustomJSONCodable) {
  147. let json = try m.encodedJSONString(options: options)
  148. encoder.append(text: json)
  149. } else if let newNameMap = (M.self as? any _ProtoNameProviding.Type)?._protobuf_nameMap {
  150. // Preserve outer object's name and extension maps; restore them before returning
  151. let oldNameMap = self.nameMap
  152. let oldExtensions = self.extensions
  153. // Install inner object's name and extension maps
  154. self.nameMap = newNameMap
  155. startObject(message: value)
  156. try value.traverse(visitor: &self)
  157. endObject()
  158. self.nameMap = oldNameMap
  159. self.extensions = oldExtensions
  160. } else {
  161. throw JSONEncodingError.missingFieldNames
  162. }
  163. }
  164. mutating func visitSingularGroupField<G: Message>(value: G, fieldNumber: Int) throws {
  165. try visitSingularMessageField(value: value, fieldNumber: fieldNumber)
  166. }
  167. mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
  168. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  169. (encoder: inout JSONEncoder, v: Float) in
  170. encoder.putFloatValue(value: v)
  171. }
  172. }
  173. mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
  174. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  175. (encoder: inout JSONEncoder, v: Double) in
  176. encoder.putDoubleValue(value: v)
  177. }
  178. }
  179. mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
  180. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  181. (encoder: inout JSONEncoder, v: Int32) in
  182. encoder.putNonQuotedInt32(value: v)
  183. }
  184. }
  185. mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
  186. if options.alwaysPrintInt64sAsNumbers {
  187. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  188. (encoder: inout JSONEncoder, v: Int64) in
  189. encoder.putNonQuotedInt64(value: v)
  190. }
  191. } else {
  192. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  193. (encoder: inout JSONEncoder, v: Int64) in
  194. encoder.putQuotedInt64(value: v)
  195. }
  196. }
  197. }
  198. mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
  199. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  200. (encoder: inout JSONEncoder, v: UInt32) in
  201. encoder.putNonQuotedUInt32(value: v)
  202. }
  203. }
  204. mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
  205. if options.alwaysPrintInt64sAsNumbers {
  206. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  207. (encoder: inout JSONEncoder, v: UInt64) in
  208. encoder.putNonQuotedUInt64(value: v)
  209. }
  210. } else {
  211. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  212. (encoder: inout JSONEncoder, v: UInt64) in
  213. encoder.putQuotedUInt64(value: v)
  214. }
  215. }
  216. }
  217. mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
  218. try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
  219. }
  220. mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
  221. try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
  222. }
  223. mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
  224. try visitRepeatedUInt32Field(value: value, fieldNumber: fieldNumber)
  225. }
  226. mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
  227. try visitRepeatedUInt64Field(value: value, fieldNumber: fieldNumber)
  228. }
  229. mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
  230. try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
  231. }
  232. mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
  233. try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
  234. }
  235. mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
  236. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  237. (encoder: inout JSONEncoder, v: Bool) in
  238. encoder.putNonQuotedBoolValue(value: v)
  239. }
  240. }
  241. mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
  242. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  243. (encoder: inout JSONEncoder, v: String) in
  244. encoder.putStringValue(value: v)
  245. }
  246. }
  247. mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
  248. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  249. (encoder: inout JSONEncoder, v: Data) in
  250. encoder.putBytesValue(value: v)
  251. }
  252. }
  253. mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
  254. if let _ = E.self as? any _CustomJSONCodable.Type {
  255. let options = self.options
  256. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  257. (encoder: inout JSONEncoder, v: E) throws in
  258. let e = v as! (any _CustomJSONCodable)
  259. let json = try e.encodedJSONString(options: options)
  260. encoder.append(text: json)
  261. }
  262. } else {
  263. let alwaysPrintEnumsAsInts = options.alwaysPrintEnumsAsInts
  264. try _visitRepeated(value: value, fieldNumber: fieldNumber) {
  265. (encoder: inout JSONEncoder, v: E) throws in
  266. if !alwaysPrintEnumsAsInts, let n = v.name {
  267. encoder.appendQuoted(name: n)
  268. } else {
  269. encoder.putEnumInt(value: v.rawValue)
  270. }
  271. }
  272. }
  273. }
  274. mutating func visitRepeatedMessageField<M: Message>(value: [M], fieldNumber: Int) throws {
  275. assert(!value.isEmpty)
  276. try startField(for: fieldNumber)
  277. var comma = false
  278. encoder.startArray()
  279. if let _ = M.self as? any _CustomJSONCodable.Type {
  280. for v in value {
  281. if comma {
  282. encoder.comma()
  283. }
  284. comma = true
  285. let json = try v.jsonString(options: options)
  286. encoder.append(text: json)
  287. }
  288. } else if let newNameMap = (M.self as? any _ProtoNameProviding.Type)?._protobuf_nameMap {
  289. // Preserve name and extension maps for outer object
  290. let oldNameMap = self.nameMap
  291. let oldExtensions = self.extensions
  292. self.nameMap = newNameMap
  293. for v in value {
  294. startArrayObject(message: v)
  295. try v.traverse(visitor: &self)
  296. encoder.endObject()
  297. }
  298. // Restore outer object's name and extension maps before returning
  299. self.nameMap = oldNameMap
  300. self.extensions = oldExtensions
  301. } else {
  302. throw JSONEncodingError.missingFieldNames
  303. }
  304. encoder.endArray()
  305. }
  306. mutating func visitRepeatedGroupField<G: Message>(value: [G], fieldNumber: Int) throws {
  307. try visitRepeatedMessageField(value: value, fieldNumber: fieldNumber)
  308. }
  309. // Packed fields are handled the same as non-packed fields, so JSON just
  310. // relies on the default implementations in Visitor.swift
  311. mutating func visitMapField<KeyType, ValueType: MapValueType>(
  312. fieldType: _ProtobufMap<KeyType, ValueType>.Type,
  313. value: _ProtobufMap<KeyType, ValueType>.BaseType,
  314. fieldNumber: Int
  315. ) throws {
  316. try iterateAndEncode(map: value, fieldNumber: fieldNumber, isOrderedBefore: KeyType._lessThan) {
  317. (visitor: inout JSONMapEncodingVisitor, key, value) throws -> Void in
  318. try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
  319. try ValueType.visitSingular(value: value, fieldNumber: 2, with: &visitor)
  320. }
  321. }
  322. mutating func visitMapField<KeyType, ValueType>(
  323. fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
  324. value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
  325. fieldNumber: Int
  326. ) throws where ValueType.RawValue == Int {
  327. try iterateAndEncode(map: value, fieldNumber: fieldNumber, isOrderedBefore: KeyType._lessThan) {
  328. (visitor: inout JSONMapEncodingVisitor, key, value) throws -> Void in
  329. try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
  330. try visitor.visitSingularEnumField(value: value, fieldNumber: 2)
  331. }
  332. }
  333. mutating func visitMapField<KeyType, ValueType>(
  334. fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
  335. value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
  336. fieldNumber: Int
  337. ) throws {
  338. try iterateAndEncode(map: value, fieldNumber: fieldNumber, isOrderedBefore: KeyType._lessThan) {
  339. (visitor: inout JSONMapEncodingVisitor, key, value) throws -> Void in
  340. try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
  341. try visitor.visitSingularMessageField(value: value, fieldNumber: 2)
  342. }
  343. }
  344. /// Helper to encapsulate the common structure of iterating over a map
  345. /// and encoding the keys and values.
  346. private mutating func iterateAndEncode<K, V>(
  347. map: [K: V],
  348. fieldNumber: Int,
  349. isOrderedBefore: (K, K) -> Bool,
  350. encode: (inout JSONMapEncodingVisitor, K, V) throws -> Void
  351. ) throws {
  352. try startField(for: fieldNumber)
  353. encoder.append(text: "{")
  354. var mapVisitor = JSONMapEncodingVisitor(encoder: JSONEncoder(), options: options)
  355. if options.useDeterministicOrdering {
  356. for (k, v) in map.sorted(by: { isOrderedBefore($0.0, $1.0) }) {
  357. try encode(&mapVisitor, k, v)
  358. }
  359. } else {
  360. for (k, v) in map {
  361. try encode(&mapVisitor, k, v)
  362. }
  363. }
  364. encoder.append(utf8Bytes: mapVisitor.bytesResult)
  365. encoder.append(text: "}")
  366. }
  367. /// Helper function that throws an error if the field number could not be
  368. /// resolved.
  369. private mutating func startField(for number: Int) throws {
  370. let name: _NameMap.Name?
  371. if options.preserveProtoFieldNames {
  372. name = nameMap.names(for: number)?.proto
  373. } else {
  374. name = nameMap.names(for: number)?.json
  375. }
  376. if let name = name {
  377. encoder.startField(name: name)
  378. } else if let name = extensions?[number]?.protobufExtension.fieldName {
  379. encoder.startExtensionField(name: name)
  380. } else {
  381. throw JSONEncodingError.missingFieldNames
  382. }
  383. }
  384. }