_MessageStorage+BinaryEncoding.swift 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // Sources/SwiftProtobuf/_MessageStorage+BinaryEncoding.swift - Binary encoding 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 encoding support for `_MessageStorage.`
  12. ///
  13. // -----------------------------------------------------------------------------
  14. import Foundation
  15. extension _MessageStorage {
  16. /// Serializes the message represented by this storage into binary format and returns the
  17. /// corresponding bytes.
  18. public func serializedBytes<Bytes: SwiftProtobufContiguousBytes>(
  19. partial: Bool,
  20. options: BinaryEncodingOptions
  21. ) throws -> Bytes {
  22. if !partial && !isInitialized {
  23. throw BinaryEncodingError.missingRequiredFields
  24. }
  25. // Note that this assumes `options` will not change the required size.
  26. let requiredSize = serializedBytesSize()
  27. // Messages have a 2GB limit in encoded size, the upstread C++ code
  28. // (message_lite, etc.) does this enforcement also.
  29. // https://protobuf.dev/programming-guides/encoding/#cheat-sheet
  30. //
  31. // Testing here enables the limit without adding extra conditionals to all
  32. // the places that encode message fields (or strings/bytes fields), keeping
  33. // the overhead of the check to a minimum.
  34. guard requiredSize < 0x7fff_ffff else {
  35. // Adding a new error is a breaking change.
  36. throw BinaryEncodingError.missingRequiredFields
  37. }
  38. var data = Bytes(repeating: 0, count: requiredSize)
  39. try data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
  40. var encoder = BinaryEncoder(forWritingInto: body)
  41. try serializeBytes(into: &encoder, options: options)
  42. // Currently not exposing this from the api because it really would be
  43. // an internal error in the library and should never happen.
  44. assert(encoder.remainder.count == 0)
  45. }
  46. return data
  47. }
  48. /// A recursion helper that serializes the message represented by this storage into the given
  49. /// binary encoder.
  50. private func serializeBytes(into encoder: inout BinaryEncoder, options: BinaryEncodingOptions) throws {
  51. for field in layout.fields {
  52. guard isPresent(field) else { continue }
  53. try serializeField(field, into: &encoder, options: options)
  54. }
  55. encoder.appendUnknown(data: unknownFields.data)
  56. // TODO: Support extensions.
  57. }
  58. /// Serializes a single field in the storage into the given binary encoder.
  59. private func serializeField(
  60. _ field: FieldLayout,
  61. into encoder: inout BinaryEncoder,
  62. options: BinaryEncodingOptions
  63. ) throws {
  64. let fieldNumber = Int(field.fieldNumber)
  65. let offset = field.offset
  66. switch field.fieldMode.cardinality {
  67. case .map:
  68. // TODO: Support maps.
  69. break
  70. case .array:
  71. let isPacked = field.fieldMode.isPacked
  72. switch field.rawFieldType {
  73. case .bool:
  74. let values = assumedPresentValue(at: offset, as: [Bool].self)
  75. if isPacked {
  76. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  77. $1.putBoolValue(value: $0)
  78. }
  79. } else {
  80. for value in values {
  81. serializeBoolField(value, for: fieldNumber, into: &encoder)
  82. }
  83. }
  84. case .bytes:
  85. precondition(!isPacked, "a packed bytes field should not be reachable")
  86. for value in assumedPresentValue(at: offset, as: [Data].self) {
  87. serializeBytesField(value, for: fieldNumber, into: &encoder)
  88. }
  89. case .double:
  90. let values = assumedPresentValue(at: offset, as: [Double].self)
  91. if isPacked {
  92. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  93. $1.putDoubleValue(value: $0)
  94. }
  95. } else {
  96. for value in values {
  97. serializeDoubleField(value, for: fieldNumber, into: &encoder)
  98. }
  99. }
  100. case .enum:
  101. try serializeRepeatedEnumField(for: fieldNumber, field: field, into: &encoder, isPacked: isPacked)
  102. case .fixed32:
  103. let values = assumedPresentValue(at: offset, as: [UInt32].self)
  104. if isPacked {
  105. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  106. $1.putFixedUInt32(value: $0)
  107. }
  108. } else {
  109. for value in values {
  110. serializeFixed32Field(value, for: fieldNumber, into: &encoder)
  111. }
  112. }
  113. case .fixed64:
  114. let values = assumedPresentValue(at: offset, as: [UInt64].self)
  115. if isPacked {
  116. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  117. $1.putFixedUInt64(value: $0)
  118. }
  119. } else {
  120. for value in values {
  121. serializeFixed64Field(value, for: fieldNumber, into: &encoder)
  122. }
  123. }
  124. case .float:
  125. let values = assumedPresentValue(at: offset, as: [Float].self)
  126. if isPacked {
  127. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  128. $1.putFloatValue(value: $0)
  129. }
  130. } else {
  131. for value in values {
  132. serializeFloatField(value, for: fieldNumber, into: &encoder)
  133. }
  134. }
  135. case .group:
  136. precondition(!isPacked, "a packed group field should not be reachable")
  137. try serializeGroupField(for: fieldNumber, field: field, into: &encoder, options: options)
  138. case .int32:
  139. let values = assumedPresentValue(at: offset, as: [Int32].self)
  140. if isPacked {
  141. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  142. $1.putVarInt(value: UInt64(UInt32(bitPattern: $0)))
  143. }
  144. } else {
  145. for value in values {
  146. serializeInt32Field(value, for: fieldNumber, into: &encoder)
  147. }
  148. }
  149. case .int64:
  150. let values = assumedPresentValue(at: offset, as: [Int64].self)
  151. if isPacked {
  152. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  153. $1.putVarInt(value: UInt64(bitPattern: $0))
  154. }
  155. } else {
  156. for value in values {
  157. serializeInt64Field(value, for: fieldNumber, into: &encoder)
  158. }
  159. }
  160. case .message:
  161. precondition(!isPacked, "a packed message field should not be reachable")
  162. try serializeMessageField(for: fieldNumber, field: field, into: &encoder, options: options)
  163. case .sfixed32:
  164. let values = assumedPresentValue(at: offset, as: [Int32].self)
  165. if isPacked {
  166. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  167. $1.putFixedUInt32(value: UInt32(bitPattern: $0))
  168. }
  169. } else {
  170. for value in values {
  171. serializeSFixed32Field(value, for: fieldNumber, into: &encoder)
  172. }
  173. }
  174. case .sfixed64:
  175. let values = assumedPresentValue(at: offset, as: [Int64].self)
  176. if isPacked {
  177. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  178. $1.putFixedUInt64(value: UInt64(bitPattern: $0))
  179. }
  180. } else {
  181. for value in values {
  182. serializeSFixed64Field(value, for: fieldNumber, into: &encoder)
  183. }
  184. }
  185. case .sint32:
  186. let values = assumedPresentValue(at: offset, as: [Int32].self)
  187. if isPacked {
  188. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  189. $1.putVarInt(value: UInt64(ZigZag.encoded($0)))
  190. }
  191. } else {
  192. for value in values {
  193. serializeSInt32Field(value, for: fieldNumber, into: &encoder)
  194. }
  195. }
  196. case .sint64:
  197. let values = assumedPresentValue(at: offset, as: [Int64].self)
  198. if isPacked {
  199. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  200. $1.putVarInt(value: ZigZag.encoded($0))
  201. }
  202. } else {
  203. for value in values {
  204. serializeSInt64Field(value, for: fieldNumber, into: &encoder)
  205. }
  206. }
  207. case .string:
  208. precondition(!isPacked, "a packed string field should not be reachable")
  209. for value in assumedPresentValue(at: offset, as: [String].self) {
  210. serializeStringField(value, for: fieldNumber, into: &encoder)
  211. }
  212. case .uint32:
  213. let values = assumedPresentValue(at: offset, as: [UInt32].self)
  214. if isPacked {
  215. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  216. $1.putVarInt(value: UInt64($0))
  217. }
  218. } else {
  219. for value in values {
  220. serializeUInt32Field(value, for: fieldNumber, into: &encoder)
  221. }
  222. }
  223. case .uint64:
  224. let values = assumedPresentValue(at: offset, as: [UInt64].self)
  225. if isPacked {
  226. serializePackedTrivialField(values, for: fieldNumber, into: &encoder) {
  227. $1.putVarInt(value: $0)
  228. }
  229. } else {
  230. for value in values {
  231. serializeUInt64Field(value, for: fieldNumber, into: &encoder)
  232. }
  233. }
  234. default:
  235. preconditionFailure("Unreachable")
  236. }
  237. case .scalar:
  238. switch field.rawFieldType {
  239. case .bool:
  240. serializeBoolField(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  241. case .bytes:
  242. serializeBytesField(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  243. case .double:
  244. serializeDoubleField(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  245. case .enum:
  246. serializeInt32Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  247. case .fixed32:
  248. serializeFixed32Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  249. case .fixed64:
  250. serializeFixed64Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  251. case .float:
  252. serializeFloatField(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  253. case .group:
  254. try serializeGroupField(for: fieldNumber, field: field, into: &encoder, options: options)
  255. case .int32:
  256. serializeInt32Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  257. case .int64:
  258. serializeInt64Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  259. case .message:
  260. try serializeMessageField(for: fieldNumber, field: field, into: &encoder, options: options)
  261. case .sfixed32:
  262. serializeSFixed32Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  263. case .sfixed64:
  264. serializeSFixed64Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  265. case .sint32:
  266. serializeSInt32Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  267. case .sint64:
  268. serializeSInt64Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  269. case .string:
  270. serializeStringField(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  271. case .uint32:
  272. serializeUInt32Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  273. case .uint64:
  274. serializeUInt64Field(assumedPresentValue(at: offset), for: fieldNumber, into: &encoder)
  275. default: preconditionFailure("Unreachable")
  276. }
  277. default:
  278. preconditionFailure("Unreachable")
  279. }
  280. }
  281. /// Serializes the field tag and value for a singular or unpacked `bool` field.
  282. @inline(__always)
  283. private func serializeBoolField(_ value: Bool, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  284. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  285. encoder.putVarInt(value: value ? 1 : 0)
  286. }
  287. /// Serializes the field tag and value for a singular `bytes` field.
  288. @inline(__always)
  289. private func serializeBytesField(_ value: Data, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  290. encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
  291. encoder.putBytesValue(value: value)
  292. }
  293. /// Serializes the field tag and value for a singular or unpacked `double` field.
  294. @inline(__always)
  295. private func serializeDoubleField(_ value: Double, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  296. encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed64)
  297. encoder.putDoubleValue(value: value)
  298. }
  299. /// Serializes the field tag and value for a singular or unpacked `fixed32` field.
  300. @inline(__always)
  301. private func serializeFixed32Field(_ value: UInt32, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  302. encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed32)
  303. encoder.putFixedUInt32(value: value)
  304. }
  305. /// Serializes the field tag and value for a singular or unpacked `fixed64` field.
  306. @inline(__always)
  307. private func serializeFixed64Field(_ value: UInt64, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  308. encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed64)
  309. encoder.putFixedUInt64(value: value)
  310. }
  311. /// Serializes the field tag and value for a singular or unpacked `float` field.
  312. @inline(__always)
  313. private func serializeFloatField(_ value: Float, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  314. encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed32)
  315. encoder.putFloatValue(value: value)
  316. }
  317. /// Serializes the start-group/end-group tags and contents for a `group` field.
  318. ///
  319. /// Since this function recurses via `performOnSubmessageStorage`, it supports both the singular
  320. /// case and the repeated case (i.e., calling this on a repeated field will iterate over all of
  321. /// the elements).
  322. private func serializeGroupField(
  323. for fieldNumber: Int,
  324. field: FieldLayout,
  325. into encoder: inout BinaryEncoder,
  326. options: BinaryEncodingOptions
  327. ) throws {
  328. _ = try layout.performOnSubmessageStorage(
  329. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  330. field,
  331. self,
  332. .read
  333. ) {
  334. encoder.startField(fieldNumber: fieldNumber, wireFormat: .startGroup)
  335. try $0.serializeBytes(into: &encoder, options: options)
  336. encoder.startField(fieldNumber: fieldNumber, wireFormat: .endGroup)
  337. return true
  338. }
  339. }
  340. /// Serializes the field tag and value for a singular or unpacked `int32` field.
  341. @inline(__always)
  342. private func serializeInt32Field(_ value: Int32, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  343. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  344. encoder.putVarInt(value: UInt64(bitPattern: Int64(value)))
  345. }
  346. /// Serializes the field tag and value for a singular or unpacked `int64` field.
  347. @inline(__always)
  348. private func serializeInt64Field(_ value: Int64, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  349. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  350. encoder.putVarInt(value: UInt64(bitPattern: value))
  351. }
  352. /// Serializes the tag, length prefix, and contents for a submessage field.
  353. ///
  354. /// Since this function recurses via `performOnSubmessageStorage`, it supports both the singular
  355. /// case and the repeated case (i.e., calling this on a repeated field will iterate over all of
  356. /// the elements).
  357. private func serializeMessageField(
  358. for fieldNumber: Int,
  359. field: FieldLayout,
  360. into encoder: inout BinaryEncoder,
  361. options: BinaryEncodingOptions
  362. ) throws {
  363. _ = try layout.performOnSubmessageStorage(
  364. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  365. field,
  366. self,
  367. .read
  368. ) {
  369. encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
  370. encoder.putVarInt(value: $0.serializedBytesSize())
  371. try $0.serializeBytes(into: &encoder, options: options)
  372. return true
  373. }
  374. }
  375. /// Serializes the field tag and value for a singular or unpacked `sfixed32` field.
  376. @inline(__always)
  377. private func serializeSFixed32Field(_ value: Int32, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  378. encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed32)
  379. encoder.putFixedUInt32(value: UInt32(bitPattern: value))
  380. }
  381. /// Serializes the field tag and value for a singular or unpacked `sfixed64` field.
  382. @inline(__always)
  383. private func serializeSFixed64Field(_ value: Int64, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  384. encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed64)
  385. encoder.putFixedUInt64(value: UInt64(bitPattern: value))
  386. }
  387. /// Serializes the field tag and value for a singular or unpacked `sint32` field.
  388. @inline(__always)
  389. private func serializeSInt32Field(_ value: Int32, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  390. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  391. encoder.putVarInt(value: UInt64(ZigZag.encoded(value)))
  392. }
  393. /// Serializes the field tag and value for a singular or unpacked `sint64` field.
  394. @inline(__always)
  395. private func serializeSInt64Field(_ value: Int64, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  396. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  397. encoder.putVarInt(value: ZigZag.encoded(value))
  398. }
  399. /// Serializes the field tag and value for a singular `string` field.
  400. @inline(__always)
  401. private func serializeStringField(_ value: String, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  402. encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
  403. encoder.putStringValue(value: value)
  404. }
  405. /// Serializes the field tag and value for a singular or unpacked `uint32` field.
  406. @inline(__always)
  407. private func serializeUInt32Field(_ value: UInt32, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  408. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  409. encoder.putVarInt(value: UInt64(value))
  410. }
  411. /// Serializes the field tag and value for a singular or unpacked `uint64` field.
  412. @inline(__always)
  413. private func serializeUInt64Field(_ value: UInt64, for fieldNumber: Int, into encoder: inout BinaryEncoder) {
  414. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  415. encoder.putVarInt(value: value)
  416. }
  417. /// Serializes a packed repeated field of trivial values by writing the tag and length-delimited
  418. /// prefix, then calls the given closure to encode the individual values themselves.
  419. private func serializePackedTrivialField<T>(
  420. _ values: [T],
  421. for fieldNumber: Int,
  422. into encoder: inout BinaryEncoder,
  423. encode: (T, inout BinaryEncoder) -> Void
  424. ) {
  425. encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
  426. encoder.putVarInt(value: values.count * MemoryLayout<T>.size)
  427. for value in values {
  428. encode(value, &encoder)
  429. }
  430. }
  431. /// Serializes the field tag and values for a repeated (packed or unpacked) `enum` field.
  432. private func serializeRepeatedEnumField(
  433. for fieldNumber: Int,
  434. field: FieldLayout,
  435. into encoder: inout BinaryEncoder,
  436. isPacked: Bool
  437. ) throws {
  438. if isPacked {
  439. // First, iterate over the values to compute the packed length.
  440. var length = 0
  441. _ = try layout.performOnRawEnumValues(
  442. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  443. field,
  444. self,
  445. .read
  446. ) {
  447. length += Varint.encodedSize(of: $0)
  448. return true
  449. } /*onInvalidValue*/ _: { _ in
  450. assertionFailure("invalid value handler should never be called for .read")
  451. }
  452. encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
  453. encoder.putVarInt(value: length)
  454. // Then, iterate over them again to encode the actual varints.
  455. _ = try layout.performOnRawEnumValues(
  456. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  457. field,
  458. self,
  459. .read
  460. ) {
  461. encoder.putVarInt(value: Int64($0))
  462. return true
  463. } /*onInvalidValue*/ _: { _ in
  464. assertionFailure("invalid value handler should never be called for .read")
  465. }
  466. } else {
  467. // Iterate over the raw values and encode each as its own tag and varint.
  468. _ = try layout.performOnRawEnumValues(
  469. _MessageLayout.TrampolineToken(index: field.submessageIndex),
  470. field,
  471. self,
  472. .read
  473. ) {
  474. encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
  475. encoder.putVarInt(value: Int64($0))
  476. return true
  477. } /*onInvalidValue*/ _: { _ in
  478. assertionFailure("invalid value handler should never be called for .read")
  479. }
  480. }
  481. }
  482. }