TextFormatEncodingVisitor.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. // Sources/SwiftProtobuf/TextFormatEncodingVisitor.swift - Text format encoding support
  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. /// Text format serialization engine.
  12. ///
  13. // -----------------------------------------------------------------------------
  14. import Foundation
  15. private let mapNameResolver: [Int: StaticString] = [1: "key", 2: "value"]
  16. /// Visitor that serializes a message into protobuf text format.
  17. internal struct TextFormatEncodingVisitor: Visitor {
  18. private var encoder: TextFormatEncoder
  19. private var nameMap: _NameMap?
  20. private var nameResolver: [Int: StaticString]
  21. private var extensions: ExtensionFieldValueSet?
  22. private let options: TextFormatEncodingOptions
  23. /// The protobuf text produced by the visitor.
  24. var result: String {
  25. encoder.stringResult
  26. }
  27. /// Creates a new visitor that serializes the given message to protobuf text
  28. /// format.
  29. init(message: any Message, options: TextFormatEncodingOptions) {
  30. let nameMap: _NameMap?
  31. if let nameProviding = message as? (any _ProtoNameProviding) {
  32. nameMap = type(of: nameProviding)._protobuf_nameMap
  33. } else {
  34. nameMap = nil
  35. }
  36. let extensions = (message as? (any ExtensibleMessage))?._protobuf_extensionFieldValues
  37. self.nameMap = nameMap
  38. self.nameResolver = [:]
  39. self.extensions = extensions
  40. self.encoder = TextFormatEncoder()
  41. self.options = options
  42. }
  43. // TODO: This largely duplicates emitFieldName() below.
  44. // But, it's slower so we don't want to just have emitFieldName() use
  45. // formatFieldName(). Also, we need to measure whether the optimization
  46. // this provides to repeated fields is worth the effort; consider just
  47. // removing this and having repeated fields just re-run emitFieldName()
  48. // for each item.
  49. private func formatFieldName(lookingUp fieldNumber: Int) -> [UInt8] {
  50. var bytes = [UInt8]()
  51. if let protoName = nameMap?.names(for: fieldNumber)?.proto {
  52. bytes.append(contentsOf: protoName.utf8Buffer)
  53. } else if let protoName = nameResolver[fieldNumber] {
  54. let buff = UnsafeBufferPointer(start: protoName.utf8Start, count: protoName.utf8CodeUnitCount)
  55. bytes.append(contentsOf: buff)
  56. } else if let extensionName = extensions?[fieldNumber]?.protobufExtension.fieldName {
  57. bytes.append(UInt8(ascii: "["))
  58. bytes.append(contentsOf: extensionName.utf8)
  59. bytes.append(UInt8(ascii: "]"))
  60. } else {
  61. bytes.append(contentsOf: fieldNumber.description.utf8)
  62. }
  63. return bytes
  64. }
  65. private mutating func emitFieldName(lookingUp fieldNumber: Int) {
  66. if let protoName = nameMap?.names(for: fieldNumber)?.proto {
  67. encoder.emitFieldName(name: protoName.utf8Buffer)
  68. } else if let protoName = nameResolver[fieldNumber] {
  69. encoder.emitFieldName(name: protoName)
  70. } else if let extensionName = extensions?[fieldNumber]?.protobufExtension.fieldName {
  71. encoder.emitExtensionFieldName(name: extensionName)
  72. } else {
  73. encoder.emitFieldNumber(number: fieldNumber)
  74. }
  75. }
  76. mutating func visitUnknown(bytes: Data) throws {
  77. if options.printUnknownFields {
  78. try bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> Void in
  79. if let baseAddress = body.baseAddress, body.count > 0 {
  80. // All fields will be directly handled, so there is no need for
  81. // the unknown field buffering/collection (when scannings to see
  82. // if something is a message, this would be extremely wasteful).
  83. var binaryOptions = BinaryDecodingOptions()
  84. binaryOptions.discardUnknownFields = true
  85. var decoder = BinaryDecoder(
  86. forReadingFrom: baseAddress,
  87. count: body.count,
  88. options: binaryOptions
  89. )
  90. try visitUnknown(decoder: &decoder)
  91. }
  92. }
  93. }
  94. }
  95. /// Helper for printing out unknowns.
  96. ///
  97. /// The implementation tries to be "helpful" and if a length delimited field
  98. /// appears to be a submessage, it prints it as such. However, that opens the
  99. /// door to someone sending a message with an unknown field that is a stack
  100. /// bomb, i.e. - it causes this code to recurse, exhausting the stack and
  101. /// thus opening up an attack vector. To keep this "help", but avoid the
  102. /// attack, a limit is placed on how many times it will recurse before just
  103. /// treating the length delimited fields as bytes and not trying to decode
  104. /// them.
  105. private mutating func visitUnknown(
  106. decoder: inout BinaryDecoder,
  107. recursionBudget: Int = 10
  108. ) throws {
  109. // This stack serves to avoid recursion for groups within groups within
  110. // groups..., this avoid the stack attack that the message detection
  111. // hits. No limit is placed on this because there is no stack risk with
  112. // recursion, and because if a limit was hit, there is no other way to
  113. // encode the group (the message field can just print as length
  114. // delimited, groups don't have an option like that).
  115. var groupFieldNumberStack: [Int] = []
  116. while let tag = try decoder.getTag() {
  117. switch tag.wireFormat {
  118. case .varint:
  119. encoder.emitFieldNumber(number: tag.fieldNumber)
  120. var value: UInt64 = 0
  121. encoder.startRegularField()
  122. try decoder.decodeSingularUInt64Field(value: &value)
  123. encoder.putUInt64(value: value)
  124. encoder.endRegularField()
  125. case .fixed64:
  126. encoder.emitFieldNumber(number: tag.fieldNumber)
  127. var value: UInt64 = 0
  128. encoder.startRegularField()
  129. try decoder.decodeSingularFixed64Field(value: &value)
  130. encoder.putUInt64Hex(value: value, digits: 16)
  131. encoder.endRegularField()
  132. case .lengthDelimited:
  133. encoder.emitFieldNumber(number: tag.fieldNumber)
  134. var bytes = Data()
  135. try decoder.decodeSingularBytesField(value: &bytes)
  136. var encodeAsBytes = true
  137. if bytes.count > 0 && recursionBudget > 0 {
  138. bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> Void in
  139. if let baseAddress = body.baseAddress, body.count > 0 {
  140. do {
  141. // Walk all the fields to test if it looks like a message
  142. var testDecoder = BinaryDecoder(
  143. forReadingFrom: baseAddress,
  144. count: body.count,
  145. parent: decoder
  146. )
  147. while let _ = try testDecoder.nextFieldNumber() {
  148. }
  149. // No error? Output the message body.
  150. encodeAsBytes = false
  151. var subDecoder = BinaryDecoder(
  152. forReadingFrom: baseAddress,
  153. count: bytes.count,
  154. parent: decoder
  155. )
  156. encoder.startMessageField()
  157. try visitUnknown(
  158. decoder: &subDecoder,
  159. recursionBudget: recursionBudget - 1
  160. )
  161. encoder.endMessageField()
  162. } catch {
  163. encodeAsBytes = true
  164. }
  165. }
  166. }
  167. }
  168. if encodeAsBytes {
  169. encoder.startRegularField()
  170. encoder.putBytesValue(value: bytes)
  171. encoder.endRegularField()
  172. }
  173. case .startGroup:
  174. encoder.emitFieldNumber(number: tag.fieldNumber)
  175. encoder.startMessageField()
  176. groupFieldNumberStack.append(tag.fieldNumber)
  177. case .endGroup:
  178. let groupFieldNumber = groupFieldNumberStack.popLast()
  179. // Unknown data is scanned and verified by the
  180. // binary parser, so this can never fail.
  181. assert(tag.fieldNumber == groupFieldNumber)
  182. encoder.endMessageField()
  183. case .fixed32:
  184. encoder.emitFieldNumber(number: tag.fieldNumber)
  185. var value: UInt32 = 0
  186. encoder.startRegularField()
  187. try decoder.decodeSingularFixed32Field(value: &value)
  188. encoder.putUInt64Hex(value: UInt64(value), digits: 8)
  189. encoder.endRegularField()
  190. }
  191. }
  192. // Unknown data is scanned and verified by the binary parser, so this can
  193. // never fail.
  194. assert(groupFieldNumberStack.isEmpty)
  195. }
  196. // Visitor.swift defines default versions for other singular field types
  197. // that simply widen and dispatch to one of the following. Since Text format
  198. // does not distinguish e.g., Fixed64 vs. UInt64, this is sufficient.
  199. mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
  200. emitFieldName(lookingUp: fieldNumber)
  201. encoder.startRegularField()
  202. encoder.putFloatValue(value: value)
  203. encoder.endRegularField()
  204. }
  205. mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
  206. emitFieldName(lookingUp: fieldNumber)
  207. encoder.startRegularField()
  208. encoder.putDoubleValue(value: value)
  209. encoder.endRegularField()
  210. }
  211. mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
  212. emitFieldName(lookingUp: fieldNumber)
  213. encoder.startRegularField()
  214. encoder.putInt64(value: value)
  215. encoder.endRegularField()
  216. }
  217. mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
  218. emitFieldName(lookingUp: fieldNumber)
  219. encoder.startRegularField()
  220. encoder.putUInt64(value: value)
  221. encoder.endRegularField()
  222. }
  223. mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
  224. emitFieldName(lookingUp: fieldNumber)
  225. encoder.startRegularField()
  226. encoder.putBoolValue(value: value)
  227. encoder.endRegularField()
  228. }
  229. mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
  230. emitFieldName(lookingUp: fieldNumber)
  231. encoder.startRegularField()
  232. encoder.putStringValue(value: value)
  233. encoder.endRegularField()
  234. }
  235. mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
  236. emitFieldName(lookingUp: fieldNumber)
  237. encoder.startRegularField()
  238. encoder.putBytesValue(value: value)
  239. encoder.endRegularField()
  240. }
  241. mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
  242. emitFieldName(lookingUp: fieldNumber)
  243. encoder.startRegularField()
  244. encoder.putEnumValue(value: value)
  245. encoder.endRegularField()
  246. }
  247. mutating func visitSingularMessageField<M: Message>(
  248. value: M,
  249. fieldNumber: Int
  250. ) throws {
  251. emitFieldName(lookingUp: fieldNumber)
  252. // Cache old visitor configuration
  253. let oldNameMap = self.nameMap
  254. let oldNameResolver = self.nameResolver
  255. let oldExtensions = self.extensions
  256. // Update configuration for new message
  257. self.nameMap = (M.self as? any _ProtoNameProviding.Type)?._protobuf_nameMap
  258. self.nameResolver = [:]
  259. self.extensions = (value as? (any ExtensibleMessage))?._protobuf_extensionFieldValues
  260. // Encode submessage
  261. encoder.startMessageField()
  262. if let any = value as? Google_Protobuf_Any {
  263. any.textTraverse(visitor: &self)
  264. } else {
  265. try! value.traverse(visitor: &self)
  266. }
  267. encoder.endMessageField()
  268. // Restore configuration before returning
  269. self.extensions = oldExtensions
  270. self.nameResolver = oldNameResolver
  271. self.nameMap = oldNameMap
  272. }
  273. // Emit the full "verbose" form of an Any. This writes the typeURL
  274. // as a field name in `[...]` followed by the fields of the
  275. // contained message.
  276. internal mutating func visitAnyVerbose(value: any Message, typeURL: String) {
  277. encoder.emitExtensionFieldName(name: typeURL)
  278. encoder.startMessageField()
  279. // Cache old visitor configuration
  280. let oldNameMap = self.nameMap
  281. let oldNameResolver = self.nameResolver
  282. let oldExtensions = self.extensions
  283. // Update configuration for new message
  284. self.nameMap = (type(of: value) as? any _ProtoNameProviding.Type)?._protobuf_nameMap
  285. self.nameResolver = [:]
  286. self.extensions = (value as? (any ExtensibleMessage))?._protobuf_extensionFieldValues
  287. if let any = value as? Google_Protobuf_Any {
  288. any.textTraverse(visitor: &self)
  289. } else {
  290. try! value.traverse(visitor: &self)
  291. }
  292. // Restore configuration before returning
  293. self.extensions = oldExtensions
  294. self.nameResolver = oldNameResolver
  295. self.nameMap = oldNameMap
  296. encoder.endMessageField()
  297. }
  298. // Write a single special field called "#json". This
  299. // is used for Any objects with undecoded JSON contents.
  300. internal mutating func visitAnyJSONBytesField(value: Data) {
  301. encoder.indent()
  302. encoder.append(staticText: "#json: ")
  303. encoder.putBytesValue(value: value)
  304. encoder.append(staticText: "\n")
  305. }
  306. // The default implementations in Visitor.swift provide the correct
  307. // results, but we get significantly better performance by only doing
  308. // the name lookup once for the array, rather than once for each element:
  309. mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
  310. assert(!value.isEmpty)
  311. let fieldName = formatFieldName(lookingUp: fieldNumber)
  312. for v in value {
  313. encoder.emitFieldName(name: fieldName)
  314. encoder.startRegularField()
  315. encoder.putFloatValue(value: v)
  316. encoder.endRegularField()
  317. }
  318. }
  319. mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
  320. assert(!value.isEmpty)
  321. let fieldName = formatFieldName(lookingUp: fieldNumber)
  322. for v in value {
  323. encoder.emitFieldName(name: fieldName)
  324. encoder.startRegularField()
  325. encoder.putDoubleValue(value: v)
  326. encoder.endRegularField()
  327. }
  328. }
  329. mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
  330. assert(!value.isEmpty)
  331. let fieldName = formatFieldName(lookingUp: fieldNumber)
  332. for v in value {
  333. encoder.emitFieldName(name: fieldName)
  334. encoder.startRegularField()
  335. encoder.putInt64(value: Int64(v))
  336. encoder.endRegularField()
  337. }
  338. }
  339. mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
  340. assert(!value.isEmpty)
  341. let fieldName = formatFieldName(lookingUp: fieldNumber)
  342. for v in value {
  343. encoder.emitFieldName(name: fieldName)
  344. encoder.startRegularField()
  345. encoder.putInt64(value: v)
  346. encoder.endRegularField()
  347. }
  348. }
  349. mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
  350. assert(!value.isEmpty)
  351. let fieldName = formatFieldName(lookingUp: fieldNumber)
  352. for v in value {
  353. encoder.emitFieldName(name: fieldName)
  354. encoder.startRegularField()
  355. encoder.putUInt64(value: UInt64(v))
  356. encoder.endRegularField()
  357. }
  358. }
  359. mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
  360. assert(!value.isEmpty)
  361. let fieldName = formatFieldName(lookingUp: fieldNumber)
  362. for v in value {
  363. encoder.emitFieldName(name: fieldName)
  364. encoder.startRegularField()
  365. encoder.putUInt64(value: v)
  366. encoder.endRegularField()
  367. }
  368. }
  369. mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
  370. try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
  371. }
  372. mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
  373. try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
  374. }
  375. mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
  376. try visitRepeatedUInt32Field(value: value, fieldNumber: fieldNumber)
  377. }
  378. mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
  379. try visitRepeatedUInt64Field(value: value, fieldNumber: fieldNumber)
  380. }
  381. mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
  382. try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
  383. }
  384. mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
  385. try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
  386. }
  387. mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
  388. assert(!value.isEmpty)
  389. let fieldName = formatFieldName(lookingUp: fieldNumber)
  390. for v in value {
  391. encoder.emitFieldName(name: fieldName)
  392. encoder.startRegularField()
  393. encoder.putBoolValue(value: v)
  394. encoder.endRegularField()
  395. }
  396. }
  397. mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
  398. assert(!value.isEmpty)
  399. let fieldName = formatFieldName(lookingUp: fieldNumber)
  400. for v in value {
  401. encoder.emitFieldName(name: fieldName)
  402. encoder.startRegularField()
  403. encoder.putStringValue(value: v)
  404. encoder.endRegularField()
  405. }
  406. }
  407. mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
  408. assert(!value.isEmpty)
  409. let fieldName = formatFieldName(lookingUp: fieldNumber)
  410. for v in value {
  411. encoder.emitFieldName(name: fieldName)
  412. encoder.startRegularField()
  413. encoder.putBytesValue(value: v)
  414. encoder.endRegularField()
  415. }
  416. }
  417. mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
  418. assert(!value.isEmpty)
  419. let fieldName = formatFieldName(lookingUp: fieldNumber)
  420. for v in value {
  421. encoder.emitFieldName(name: fieldName)
  422. encoder.startRegularField()
  423. encoder.putEnumValue(value: v)
  424. encoder.endRegularField()
  425. }
  426. }
  427. // Messages and groups
  428. mutating func visitRepeatedMessageField<M: Message>(
  429. value: [M],
  430. fieldNumber: Int
  431. ) throws {
  432. assert(!value.isEmpty)
  433. // Look up field name against outer message encoding state
  434. let fieldName = formatFieldName(lookingUp: fieldNumber)
  435. // Cache old visitor state
  436. let oldNameMap = self.nameMap
  437. let oldNameResolver = self.nameResolver
  438. let oldExtensions = self.extensions
  439. // Update encoding state for new message type
  440. self.nameMap = (M.self as? any _ProtoNameProviding.Type)?._protobuf_nameMap
  441. self.nameResolver = [:]
  442. self.extensions = (value as? (any ExtensibleMessage))?._protobuf_extensionFieldValues
  443. // Iterate and encode each message
  444. for v in value {
  445. encoder.emitFieldName(name: fieldName)
  446. encoder.startMessageField()
  447. if let any = v as? Google_Protobuf_Any {
  448. any.textTraverse(visitor: &self)
  449. } else {
  450. try! v.traverse(visitor: &self)
  451. }
  452. encoder.endMessageField()
  453. }
  454. // Restore state
  455. self.extensions = oldExtensions
  456. self.nameResolver = oldNameResolver
  457. self.nameMap = oldNameMap
  458. }
  459. // Google's C++ implementation of Text format supports two formats
  460. // for repeated numeric fields: "short" format writes the list as a
  461. // single field with values enclosed in `[...]`, "long" format
  462. // writes a separate field name/value for each item. They provide
  463. // an option for callers to select which output version they prefer.
  464. // Since this distinction mirrors the difference in Protobuf Binary
  465. // between "packed" and "non-packed", I've chosen to use the short
  466. // format for packed fields and the long version for repeated
  467. // fields. This provides a clear visual distinction between these
  468. // fields (including proto3's default use of packed) without
  469. // introducing the baggage of a separate option.
  470. private mutating func iterateAndEncode<T>(
  471. packedValue: [T],
  472. fieldNumber: Int,
  473. encode: (T, inout TextFormatEncoder) -> Void
  474. ) throws {
  475. assert(!packedValue.isEmpty)
  476. emitFieldName(lookingUp: fieldNumber)
  477. encoder.startRegularField()
  478. var firstItem = true
  479. encoder.startArray()
  480. for v in packedValue {
  481. if !firstItem {
  482. encoder.arraySeparator()
  483. }
  484. encode(v, &encoder)
  485. firstItem = false
  486. }
  487. encoder.endArray()
  488. encoder.endRegularField()
  489. }
  490. mutating func visitPackedFloatField(value: [Float], fieldNumber: Int) throws {
  491. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  492. (v: Float, encoder: inout TextFormatEncoder) in
  493. encoder.putFloatValue(value: v)
  494. }
  495. }
  496. mutating func visitPackedDoubleField(value: [Double], fieldNumber: Int) throws {
  497. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  498. (v: Double, encoder: inout TextFormatEncoder) in
  499. encoder.putDoubleValue(value: v)
  500. }
  501. }
  502. mutating func visitPackedInt32Field(value: [Int32], fieldNumber: Int) throws {
  503. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  504. (v: Int32, encoder: inout TextFormatEncoder) in
  505. encoder.putInt64(value: Int64(v))
  506. }
  507. }
  508. mutating func visitPackedInt64Field(value: [Int64], fieldNumber: Int) throws {
  509. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  510. (v: Int64, encoder: inout TextFormatEncoder) in
  511. encoder.putInt64(value: v)
  512. }
  513. }
  514. mutating func visitPackedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
  515. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  516. (v: UInt32, encoder: inout TextFormatEncoder) in
  517. encoder.putUInt64(value: UInt64(v))
  518. }
  519. }
  520. mutating func visitPackedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
  521. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  522. (v: UInt64, encoder: inout TextFormatEncoder) in
  523. encoder.putUInt64(value: v)
  524. }
  525. }
  526. mutating func visitPackedSInt32Field(value: [Int32], fieldNumber: Int) throws {
  527. try visitPackedInt32Field(value: value, fieldNumber: fieldNumber)
  528. }
  529. mutating func visitPackedSInt64Field(value: [Int64], fieldNumber: Int) throws {
  530. try visitPackedInt64Field(value: value, fieldNumber: fieldNumber)
  531. }
  532. mutating func visitPackedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
  533. try visitPackedUInt32Field(value: value, fieldNumber: fieldNumber)
  534. }
  535. mutating func visitPackedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
  536. try visitPackedUInt64Field(value: value, fieldNumber: fieldNumber)
  537. }
  538. mutating func visitPackedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
  539. try visitPackedInt32Field(value: value, fieldNumber: fieldNumber)
  540. }
  541. mutating func visitPackedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
  542. try visitPackedInt64Field(value: value, fieldNumber: fieldNumber)
  543. }
  544. mutating func visitPackedBoolField(value: [Bool], fieldNumber: Int) throws {
  545. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  546. (v: Bool, encoder: inout TextFormatEncoder) in
  547. encoder.putBoolValue(value: v)
  548. }
  549. }
  550. mutating func visitPackedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
  551. try iterateAndEncode(packedValue: value, fieldNumber: fieldNumber) {
  552. (v: E, encoder: inout TextFormatEncoder) in
  553. encoder.putEnumValue(value: v)
  554. }
  555. }
  556. /// Helper to encapsulate the common structure of iterating over a map
  557. /// and encoding the keys and values.
  558. private mutating func iterateAndEncode<K, V>(
  559. map: [K: V],
  560. fieldNumber: Int,
  561. isOrderedBefore: (K, K) -> Bool,
  562. encode: (inout TextFormatEncodingVisitor, K, V) throws -> Void
  563. ) throws {
  564. // Cache old visitor configuration
  565. let oldNameMap = self.nameMap
  566. let oldNameResolver = self.nameResolver
  567. let oldExtensions = self.extensions
  568. for (k, v) in map.sorted(by: { isOrderedBefore($0.0, $1.0) }) {
  569. emitFieldName(lookingUp: fieldNumber)
  570. encoder.startMessageField()
  571. // Update visitor configuration for map
  572. self.nameMap = nil
  573. self.nameResolver = mapNameResolver
  574. self.extensions = nil
  575. try encode(&self, k, v)
  576. // Restore configuration before resuming containing message
  577. self.extensions = oldExtensions
  578. self.nameResolver = oldNameResolver
  579. self.nameMap = oldNameMap
  580. encoder.endMessageField()
  581. }
  582. }
  583. mutating func visitMapField<KeyType, ValueType: MapValueType>(
  584. fieldType: _ProtobufMap<KeyType, ValueType>.Type,
  585. value: _ProtobufMap<KeyType, ValueType>.BaseType,
  586. fieldNumber: Int
  587. ) throws {
  588. try iterateAndEncode(map: value, fieldNumber: fieldNumber, isOrderedBefore: KeyType._lessThan) {
  589. (visitor: inout TextFormatEncodingVisitor, key, value) throws -> Void in
  590. try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
  591. try ValueType.visitSingular(value: value, fieldNumber: 2, with: &visitor)
  592. }
  593. }
  594. mutating func visitMapField<KeyType, ValueType>(
  595. fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
  596. value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
  597. fieldNumber: Int
  598. ) throws where ValueType.RawValue == Int {
  599. try iterateAndEncode(map: value, fieldNumber: fieldNumber, isOrderedBefore: KeyType._lessThan) {
  600. (visitor: inout TextFormatEncodingVisitor, key, value) throws -> Void in
  601. try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
  602. try visitor.visitSingularEnumField(value: value, fieldNumber: 2)
  603. }
  604. }
  605. mutating func visitMapField<KeyType, ValueType>(
  606. fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
  607. value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
  608. fieldNumber: Int
  609. ) throws {
  610. try iterateAndEncode(map: value, fieldNumber: fieldNumber, isOrderedBefore: KeyType._lessThan) {
  611. (visitor: inout TextFormatEncodingVisitor, key, value) throws -> Void in
  612. try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
  613. try visitor.visitSingularMessageField(value: value, fieldNumber: 2)
  614. }
  615. }
  616. }