_MessageStorage+BinaryDecoding.swift 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. // Sources/SwiftProtobuf/_MessageStorage+BinaryDecoding.swift - Binary decoding for messages
  2. //
  3. // Copyright (c) 2014 - 2025 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. /// Binary decoding support for `_MessageStorage.`
  12. ///
  13. // -----------------------------------------------------------------------------
  14. import Foundation
  15. extension _MessageStorage {
  16. /// Decodes field values from the given binary-encoded buffer into this storage class.
  17. ///
  18. /// - Parameters:
  19. /// - buffer: The binary-encoded message data to decode.
  20. /// - partial: If `false` (the default), this method will check
  21. /// ``Message/isInitialized-6abgi`` after decoding to verify that all required
  22. /// fields are present. If any are missing, this method throws
  23. /// ``BinaryDecodingError/missingRequiredFields``.
  24. /// - options: The ``BinaryDecodingOptions`` to use.
  25. /// - Throws: ``BinaryDecodingError`` if decoding fails.
  26. public func merge(
  27. byReadingFrom buffer: UnsafeRawBufferPointer,
  28. partial: Bool,
  29. options: BinaryDecodingOptions
  30. ) throws {
  31. var reader = WireFormatReader(buffer: buffer, recursionBudget: options.messageDepthLimit)
  32. try merge(byReadingFrom: &reader, partial: partial, discardUnknownFields: options.discardUnknownFields)
  33. }
  34. /// Decodes field values from the given wire format reader into this storage class.
  35. ///
  36. /// - Parameters:
  37. /// - buffer: The binary-encoded message data to decode.
  38. /// - partial: If `false` (the default), this method will check
  39. /// ``Message/isInitialized-6abgi`` after decoding to verify that all required
  40. /// fields are present. If any are missing, this method throws
  41. /// ``BinaryDecodingError/missingRequiredFields``.
  42. /// - discardUnknownFields: If true, unknown fields will be discarded during
  43. /// parsing.
  44. private func merge(
  45. byReadingFrom reader: inout WireFormatReader,
  46. partial: Bool,
  47. discardUnknownFields: Bool
  48. ) throws {
  49. while reader.hasAvailableData {
  50. let tag = try reader.nextTag()
  51. let consumed = try decodeNextField(
  52. from: &reader,
  53. tag: tag,
  54. partial: partial,
  55. discardUnknownFields: discardUnknownFields
  56. )
  57. if !consumed {
  58. try decodeUnknownField(from: &reader, tag: tag, discard: discardUnknownFields)
  59. }
  60. }
  61. if reader.isTrackingGroup {
  62. // If `nextTag` saw the expected end-group tag, it would have cleared out the reader's
  63. // group tracking state. If that didn't happen, then we ran out of data too early.
  64. throw BinaryDecodingError.truncated
  65. }
  66. if !partial && !isInitialized {
  67. throw BinaryDecodingError.missingRequiredFields
  68. }
  69. }
  70. /// Decodes the next field from the binary reader, assuming that its tag has already been read.
  71. ///
  72. /// - Parameters:
  73. /// - reader: The reader from which to read the next field's data.
  74. /// - tag: The tag that was just read from the reader.
  75. /// - Returns: True if the field was consumed, or false to indicate that it should be stored in
  76. /// unknown fields (for example, because the field did not exist or the data on the wire did
  77. /// not match the expected wire format)).
  78. private func decodeNextField(
  79. from reader: inout WireFormatReader,
  80. tag: FieldTag,
  81. partial: Bool,
  82. discardUnknownFields: Bool
  83. ) throws -> Bool {
  84. guard tag.wireFormat != .endGroup else {
  85. // Just consume it; `nextTag` has already validated that it matches the last started
  86. // group.
  87. return true
  88. }
  89. guard let field = layout[fieldNumber: UInt32(tag.fieldNumber)] else {
  90. // If the field number didn't exist, return false to indicate to the caller that the
  91. // field wasn't consumed so that they can put it into unknown fields.
  92. // TODO: When we come back to support extension fields, make sure we handle those
  93. // correctly, since that might hit this code path depending on how we represent them.
  94. return false
  95. }
  96. switch field.fieldMode.cardinality {
  97. case .map:
  98. // TODO: Support map fields.
  99. break
  100. case .array:
  101. switch field.rawFieldType {
  102. case .bool:
  103. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  104. try $0.nextVarint() != 0
  105. }
  106. case .bytes:
  107. guard tag.wireFormat == .lengthDelimited else { return false }
  108. try reader.nextLengthDelimitedSlice().withMemoryRebound(to: UInt8.self) { buffer in
  109. appendValue(Data(buffer: buffer), to: field)
  110. }
  111. case .double:
  112. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .fixed64) {
  113. Double(bitPattern: try $0.nextLittleEndianUInt64())
  114. }
  115. case .enum:
  116. switch tag.wireFormat {
  117. case .varint:
  118. try updateEnumValue(of: field, from: &reader, fieldNumber: tag.fieldNumber, isRepeated: true)
  119. case .lengthDelimited:
  120. try appendPackedEnumValues(from: &reader, to: field, fieldNumber: tag.fieldNumber)
  121. default:
  122. return false
  123. }
  124. case .fixed32:
  125. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .fixed32) {
  126. try $0.nextLittleEndianUInt32()
  127. }
  128. case .fixed64:
  129. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .fixed64) {
  130. try $0.nextLittleEndianUInt64()
  131. }
  132. case .float:
  133. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .fixed32) {
  134. Float(bitPattern: try $0.nextLittleEndianUInt32())
  135. }
  136. case .group:
  137. guard tag.wireFormat == .startGroup else { return false }
  138. _ = try layout.performOnSubmessageStorage(
  139. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  140. field,
  141. self,
  142. .append
  143. ) { submessageStorage in
  144. try reader.withReaderForNextGroup(withFieldNumber: UInt32(tag.fieldNumber)) { subReader in
  145. try submessageStorage.merge(
  146. byReadingFrom: &subReader,
  147. partial: partial,
  148. discardUnknownFields: discardUnknownFields
  149. )
  150. }
  151. return true
  152. }
  153. case .int32:
  154. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  155. // If the number on the wire is larger than fits into an `Int32`, this is not an
  156. // error; we truncate it.
  157. Int32(truncatingIfNeeded: try $0.nextVarint())
  158. }
  159. case .int64:
  160. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  161. Int64(truncatingIfNeeded: try $0.nextVarint())
  162. }
  163. case .message:
  164. guard tag.wireFormat == .lengthDelimited else { return false }
  165. _ = try layout.performOnSubmessageStorage(
  166. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  167. field,
  168. self,
  169. .append
  170. ) { submessageStorage in
  171. try reader.withReaderForNextLengthDelimitedSlice { subReader in
  172. try submessageStorage.merge(
  173. byReadingFrom: &subReader,
  174. partial: partial,
  175. discardUnknownFields: discardUnknownFields
  176. )
  177. }
  178. return true
  179. }
  180. case .sfixed32:
  181. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .fixed32) {
  182. Int32(bitPattern: try $0.nextLittleEndianUInt32())
  183. }
  184. case .sfixed64:
  185. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .fixed64) {
  186. Int64(bitPattern: try $0.nextLittleEndianUInt64())
  187. }
  188. case .sint32:
  189. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  190. // If the number on the wire is larger than fits into an `Int32`, this is not an
  191. // error; we truncate it.
  192. ZigZag.decoded(UInt32(truncatingIfNeeded: try $0.nextVarint()))
  193. }
  194. case .sint64:
  195. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  196. ZigZag.decoded(try $0.nextVarint())
  197. }
  198. case .string:
  199. guard tag.wireFormat == .lengthDelimited else { return false }
  200. let buffer = try reader.nextLengthDelimitedSlice()
  201. guard let string = utf8ToString(bytes: buffer.baseAddress!, count: buffer.count) else {
  202. throw BinaryDecodingError.invalidUTF8
  203. }
  204. appendValue(string, to: field)
  205. case .uint32:
  206. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  207. // If the number on the wire is larger than fits into a `UInt32`, this is not an
  208. // error; we truncate it.
  209. UInt32(truncatingIfNeeded: try $0.nextVarint())
  210. }
  211. case .uint64:
  212. return try appendMaybePackedValues(from: &reader, to: field, tag: tag, unpackedWireFormat: .varint) {
  213. try $0.nextVarint()
  214. }
  215. default:
  216. preconditionFailure("Unreachable")
  217. }
  218. case .scalar:
  219. switch field.rawFieldType {
  220. case .bool:
  221. guard tag.wireFormat == .varint else { return false }
  222. updateValue(of: field, to: try reader.nextVarint() != 0)
  223. case .bytes:
  224. guard tag.wireFormat == .lengthDelimited else { return false }
  225. try reader.nextLengthDelimitedSlice().withMemoryRebound(to: UInt8.self) { buffer in
  226. updateValue(of: field, to: Data(buffer: buffer))
  227. }
  228. case .double:
  229. guard tag.wireFormat == .fixed64 else { return false }
  230. updateValue(of: field, to: Double(bitPattern: try reader.nextLittleEndianUInt64()))
  231. case .enum:
  232. guard tag.wireFormat == .varint else { return false }
  233. try updateEnumValue(of: field, from: &reader, fieldNumber: tag.fieldNumber, isRepeated: false)
  234. case .fixed32:
  235. guard tag.wireFormat == .fixed32 else { return false }
  236. updateValue(of: field, to: try reader.nextLittleEndianUInt32())
  237. case .fixed64:
  238. guard tag.wireFormat == .fixed64 else { return false }
  239. updateValue(of: field, to: try reader.nextLittleEndianUInt64())
  240. case .float:
  241. guard tag.wireFormat == .fixed32 else { return false }
  242. updateValue(of: field, to: Float(bitPattern: try reader.nextLittleEndianUInt32()))
  243. case .group:
  244. guard tag.wireFormat == .startGroup else { return false }
  245. _ = try layout.performOnSubmessageStorage(
  246. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  247. field,
  248. self,
  249. .mutate
  250. ) { submessageStorage in
  251. try reader.withReaderForNextGroup(withFieldNumber: UInt32(tag.fieldNumber)) { subReader in
  252. try submessageStorage.merge(
  253. byReadingFrom: &subReader,
  254. partial: partial,
  255. discardUnknownFields: discardUnknownFields
  256. )
  257. }
  258. return true
  259. }
  260. case .int32:
  261. guard tag.wireFormat == .varint else { return false }
  262. // If the number on the wire is larger than fits into an `Int32`, this is not an
  263. // error; we truncate it.
  264. updateValue(of: field, to: Int32(truncatingIfNeeded: try reader.nextVarint()))
  265. case .int64:
  266. guard tag.wireFormat == .varint else { return false }
  267. updateValue(of: field, to: Int64(bitPattern: try reader.nextVarint()))
  268. case .message:
  269. guard tag.wireFormat == .lengthDelimited else { return false }
  270. _ = try layout.performOnSubmessageStorage(
  271. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  272. field,
  273. self,
  274. .mutate
  275. ) { submessageStorage in
  276. try reader.withReaderForNextLengthDelimitedSlice { subReader in
  277. try submessageStorage.merge(
  278. byReadingFrom: &subReader,
  279. partial: partial,
  280. discardUnknownFields: discardUnknownFields
  281. )
  282. }
  283. return true
  284. }
  285. case .sfixed32:
  286. guard tag.wireFormat == .fixed32 else { return false }
  287. updateValue(of: field, to: Int32(bitPattern: try reader.nextLittleEndianUInt32()))
  288. case .sfixed64:
  289. guard tag.wireFormat == .fixed64 else { return false }
  290. updateValue(of: field, to: Int64(bitPattern: try reader.nextLittleEndianUInt64()))
  291. case .sint32:
  292. guard tag.wireFormat == .varint else { return false }
  293. // If the number on the wire is larger than fits into an `Int32`, this is not an
  294. // error; we truncate it.
  295. updateValue(of: field, to: ZigZag.decoded(UInt32(truncatingIfNeeded: try reader.nextVarint())))
  296. case .sint64:
  297. guard tag.wireFormat == .varint else { return false }
  298. updateValue(of: field, to: ZigZag.decoded(try reader.nextVarint()))
  299. case .string:
  300. guard tag.wireFormat == .lengthDelimited else { return false }
  301. let buffer = try reader.nextLengthDelimitedSlice()
  302. guard let string = utf8ToString(bytes: buffer.baseAddress!, count: buffer.count) else {
  303. throw BinaryDecodingError.invalidUTF8
  304. }
  305. updateValue(of: field, to: string)
  306. case .uint32:
  307. guard tag.wireFormat == .varint else { return false }
  308. // If the number on the wire is larger than fits into a `UInt32`, this is not an
  309. // error; we truncate it.
  310. updateValue(of: field, to: UInt32(truncatingIfNeeded: try reader.nextVarint()))
  311. case .uint64:
  312. guard tag.wireFormat == .varint else { return false }
  313. updateValue(of: field, to: try reader.nextVarint())
  314. default:
  315. preconditionFailure("Unreachable")
  316. }
  317. default:
  318. preconditionFailure("Unreachable")
  319. }
  320. return true
  321. }
  322. /// Appends either a single unpacked value or multiple packed values to the array value of the
  323. /// given field, depending on the wire format of the corresponding tag.
  324. ///
  325. /// - Parameters:
  326. /// - reader: The reader from which the values to append should be read.
  327. /// - field: The field being decoded.
  328. /// - tag: The tag that was read from the wire.
  329. /// - unpackedWireFormat: The wire format that should be expected for values of this type if
  330. /// they are unpacked.
  331. /// - decodeElement: A function that takes a `WireFormatReader` covering the slice of packed
  332. /// elements and reads and returns a single element from it.
  333. /// - Returns: True if the value was consumed properly, or false if the wire format was not
  334. /// what was expected.
  335. private func appendMaybePackedValues<T>(
  336. from reader: inout WireFormatReader,
  337. to field: FieldLayout,
  338. tag: FieldTag,
  339. unpackedWireFormat: WireFormat,
  340. decodeElement: (inout WireFormatReader) throws -> T
  341. ) throws -> Bool {
  342. assert(
  343. field.rawFieldType != .bytes && field.rawFieldType != .group && field.rawFieldType != .message
  344. && field.rawFieldType != .string,
  345. "Internal error: length-delimited singular values should not reach here"
  346. )
  347. switch tag.wireFormat {
  348. case unpackedWireFormat:
  349. appendValue(try decodeElement(&reader), to: field)
  350. return true
  351. case .lengthDelimited:
  352. try appendPackedValues(from: &reader, to: field, hasVarints: unpackedWireFormat == .varint) {
  353. try decodeElement(&$0)
  354. }
  355. return true
  356. default:
  357. return false
  358. }
  359. }
  360. /// Updates the value of the given field by reading the next varint from the reader and treating
  361. /// it as the raw value of that enum field.
  362. ///
  363. /// This method handles both the singular case (by setting the field) and the repeated unpacked
  364. /// case (by appending to it).
  365. private func updateEnumValue(
  366. of field: FieldLayout,
  367. from reader: inout WireFormatReader,
  368. fieldNumber: Int,
  369. isRepeated: Bool
  370. ) throws {
  371. var alreadyReadValue = false
  372. try layout.performOnRawEnumValues(
  373. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  374. field,
  375. self,
  376. isRepeated ? .append : .mutate
  377. ) { outRawValue in
  378. // In the singular case, this doesn't matter. In the repeated case, we need to return
  379. // true *exactly once* and then return false the next time this is called. This is
  380. // because the same trampoline function is used to handle the packed case, where it
  381. // calls the closure over and over until it returns that there is no data left.
  382. guard !alreadyReadValue else { return false }
  383. outRawValue = Int32(bitPattern: UInt32(truncatingIfNeeded: try reader.nextVarint()))
  384. alreadyReadValue = true
  385. return true
  386. } /*onInvalidValue*/ _: { rawValue in
  387. // Serialize the invalid values into a binary blob that will be passed as a single
  388. // varint field into unknown fields.
  389. //
  390. // Note that because we've already read the value, we have to put it into unknown fields
  391. // ourselves. The `decodeUnknownField` flow assumes that we've only read the tag and
  392. // are positioned at the beginning of the value.
  393. let fieldTag = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint)
  394. let fieldSize = fieldTag.encodedSize + Varint.encodedSize(of: Int64(rawValue))
  395. var field = Data(count: fieldSize)
  396. field.withUnsafeMutableBytes { body in
  397. var encoder = BinaryEncoder(forWritingInto: body)
  398. encoder.startField(tag: fieldTag)
  399. encoder.putVarInt(value: Int64(rawValue))
  400. unknownFields.append(protobufBytes: UnsafeRawBufferPointer(body))
  401. }
  402. }
  403. }
  404. /// Appends either a single enum value or multiple packed values to the array value of the
  405. /// given field, depending on the wire format of the corresponding tag.
  406. ///
  407. /// - Parameters:
  408. /// - reader: The reader from which the values to append should be read.
  409. /// - field: The field being decoded.
  410. /// - tag: The tag that was read from the wire.
  411. private func appendPackedEnumValues(
  412. from reader: inout WireFormatReader,
  413. to field: FieldLayout,
  414. fieldNumber: Int
  415. ) throws {
  416. assert(field.rawFieldType == .enum, "Internal error: should only be called for enum fields")
  417. let elementsBuffer = try reader.nextLengthDelimitedSlice()
  418. guard elementsBuffer.baseAddress != nil, elementsBuffer.count > 0 else {
  419. return
  420. }
  421. // If we see any invalid values during decode them, save them here so we can write them
  422. // into unknown fields at the end.
  423. var invalidValues: [Int32] = []
  424. // Recursion budget is irrelevant here because we're only reading enums.
  425. var elementsReader = WireFormatReader(buffer: elementsBuffer, recursionBudget: 0)
  426. try layout.performOnRawEnumValues(
  427. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  428. field,
  429. self,
  430. .append
  431. ) { outRawValue in
  432. guard elementsReader.hasAvailableData else { return false }
  433. outRawValue = Int32(bitPattern: UInt32(truncatingIfNeeded: try elementsReader.nextVarint()))
  434. return true
  435. } /*onInvalidValue*/ _: {
  436. invalidValues.append($0)
  437. }
  438. if invalidValues.isEmpty {
  439. return
  440. }
  441. // Serialize all of the invalid values into a binary blob that will be passed as a
  442. // single length-delimited field into unknown fields.
  443. //
  444. // Note that because we've already read the values, we have to put them into unknown fields
  445. // ourselves. The `decodeUnknownField` flow assumes that we've only read the tag and
  446. // are positioned at the beginning of the value.
  447. let fieldTag = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
  448. let bodySize = invalidValues.reduce(0) { $0 + Varint.encodedSize(of: Int64($1)) }
  449. let fieldSize = fieldTag.encodedSize + Varint.encodedSize(of: Int64(bodySize)) + bodySize
  450. var field = Data(count: fieldSize)
  451. field.withUnsafeMutableBytes { body in
  452. var encoder = BinaryEncoder(forWritingInto: body)
  453. encoder.startField(tag: fieldTag)
  454. encoder.putVarInt(value: Int64(bodySize))
  455. for value in invalidValues {
  456. encoder.putVarInt(value: Int64(value))
  457. }
  458. unknownFields.append(protobufBytes: UnsafeRawBufferPointer(body))
  459. }
  460. }
  461. /// Reads the next length-delimited slice from the reader and calls the given function to
  462. /// decode and append the elements, having already initialized the array (if not present) and
  463. /// reserved capacity for the expected number of new elements.
  464. ///
  465. /// - Parameters:
  466. /// - reader: The reader from which the next length-delimited slice of values should be read.
  467. /// - field: The field being decoded.
  468. /// - hasVarints: If true, determine the number of new elements by counting the varints in the
  469. /// slice; otherwise, compute them based on the element's fixed size.
  470. /// - decodeElement: A function that takes a `WireFormatReader` covering the slice of packed
  471. /// elements and reads and returns a single element from it.
  472. private func appendPackedValues<T>(
  473. from reader: inout WireFormatReader,
  474. to field: FieldLayout,
  475. hasVarints: Bool,
  476. decodeElement: (inout WireFormatReader) throws -> T
  477. ) throws {
  478. // TODO: Constrain `T` to `BitwiseCopyable` if we decide to drop Swift 5.x support.
  479. // If the field isn't already present, we need to initialize a new array first.
  480. let pointer = (buffer.baseAddress! + field.offset).bindMemory(to: [T].self, capacity: 1)
  481. if !isPresent(field) {
  482. pointer.initialize(to: [])
  483. switch field.presence {
  484. case .hasBit(let hasByteOffset, let hasMask):
  485. _ = updatePresence(hasBit: (hasByteOffset, hasMask), willBeSet: true)
  486. case .oneOfMember(let oneofOffset):
  487. _ = updatePopulatedOneofMember((oneofOffset, field.fieldNumber))
  488. }
  489. }
  490. let elementsBuffer = try reader.nextLengthDelimitedSlice()
  491. guard let elementsPointer = elementsBuffer.baseAddress, elementsBuffer.count > 0 else {
  492. return
  493. }
  494. // Reserve additional capacity for the number of values in the buffer. In the varint case,
  495. // it's still likely cheaper to do a quick pre-scan than to potentially reallocate multiple
  496. // times.
  497. let count =
  498. hasVarints
  499. ? Varint.countVarintsInBuffer(start: elementsPointer, count: elementsBuffer.count)
  500. : elementsBuffer.count / MemoryLayout<T>.size
  501. pointer.pointee.reserveCapacity(pointer.pointee.count + count)
  502. // Recursion budget is irrelevant here because we should never recurse into groups or
  503. // messages here; they're not supported as packed fields.
  504. var elementsReader = WireFormatReader(buffer: elementsBuffer, recursionBudget: 0)
  505. while elementsReader.hasAvailableData {
  506. pointer.pointee.append(try decodeElement(&elementsReader))
  507. }
  508. }
  509. /// Decodes the next field in the reader as an unknown field.
  510. ///
  511. /// - Parameters:
  512. /// - reader: The `WireFormatReader` from which to read the next field.
  513. /// - tag: The tag representing the current field that was just read from the reader.
  514. /// - discard: If true, the field's data should be skipped. Otherwise, it will be stored in
  515. /// the unknown fields storage.
  516. /// - Throws: `BinaryDecodingError` if an error occurred while reading from the buffer.
  517. private func decodeUnknownField(from reader: inout WireFormatReader, tag: FieldTag, discard: Bool) throws {
  518. let slice = try reader.sliceBySkippingField(tag: tag)
  519. if !discard {
  520. unknownFields.append(protobufBytes: slice)
  521. }
  522. }
  523. }