ProtobufBinaryEncoding.swift 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // ProtobufRuntime/Sources/Protobuf/ProtobufBinaryEncoding.swift - Binary encoding support
  2. //
  3. // This source file is part of the Swift.org open source project
  4. //
  5. // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See http://swift.org/LICENSE.txt for license information
  9. // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  10. //
  11. // -----------------------------------------------------------------------------
  12. ///
  13. /// Core support for protobuf binary encoding. Note that this is built
  14. /// on the general traversal machinery.
  15. ///
  16. // -----------------------------------------------------------------------------
  17. import Swift
  18. public struct ProtobufBinaryEncodingVisitor: ProtobufVisitor {
  19. private var encoder = ProtobufBinaryEncoder()
  20. public var buffer: [UInt8] {return encoder.buffer}
  21. public init(message: ProtobufMessageBase) throws {
  22. try withAbstractVisitor {(visitor: inout ProtobufVisitor) in
  23. try message.traverse(visitor: &visitor)
  24. }
  25. }
  26. public mutating func withAbstractVisitor(clause: (inout ProtobufVisitor) throws ->()) throws {
  27. var visitor: ProtobufVisitor = self
  28. try clause(&visitor)
  29. encoder.buffer = (visitor as! ProtobufBinaryEncodingVisitor).encoder.buffer
  30. }
  31. mutating public func visitUnknown(bytes: [UInt8]) {
  32. encoder.appendUnknown(bytes: bytes)
  33. }
  34. mutating public func visitSingularField<S: ProtobufTypeProperties>(fieldType: S.Type, value: S.BaseType, protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  35. encoder.startField(tagType: protoFieldNumber * 8 + S.protobufWireType())
  36. try S.serializeProtobufValue(encoder: &encoder, value: value)
  37. }
  38. mutating public func visitRepeatedField<S: ProtobufTypeProperties>(fieldType: S.Type, value: [S.BaseType], protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  39. for v in value {
  40. encoder.startField(tagType: protoFieldNumber * 8 + S.protobufWireType())
  41. try S.serializeProtobufValue(encoder: &encoder, value: v)
  42. }
  43. }
  44. mutating public func visitPackedField<S: ProtobufTypeProperties>(fieldType: S.Type, value: [S.BaseType], protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  45. encoder.startField(tagType: protoFieldNumber * 8 + 2)
  46. var subencoder = ProtobufBinaryEncoder()
  47. for v in value {
  48. try S.serializeProtobufValue(encoder: &subencoder, value: v)
  49. }
  50. encoder.putBytesValue(value: subencoder.buffer)
  51. }
  52. mutating public func visitSingularMessageField<M: ProtobufMessage>(value: M, protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  53. let t = try value.serializeProtobuf()
  54. encoder.startField(tagType: protoFieldNumber * 8 + M.protobufWireType())
  55. encoder.putBytesValue(value: t)
  56. }
  57. mutating public func visitRepeatedMessageField<M: ProtobufMessage>(value: [M], protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  58. for v in value {
  59. let t = try v.serializeProtobuf()
  60. encoder.startField(tagType: protoFieldNumber * 8 + M.protobufWireType())
  61. encoder.putBytesValue(value: t)
  62. }
  63. }
  64. mutating public func visitSingularGroupField<G: ProtobufGroup>(value: G, protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  65. encoder.startField(tagType: protoFieldNumber * 8 + 3) // Start of group
  66. try withAbstractVisitor {(visitor: inout ProtobufVisitor) in
  67. try value.traverse(visitor: &visitor)
  68. }
  69. encoder.startField(tagType: protoFieldNumber * 8 + 4) // End of group
  70. }
  71. mutating public func visitRepeatedGroupField<G: ProtobufGroup>(value: [G], protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws {
  72. for v in value {
  73. encoder.startField(tagType: protoFieldNumber * 8 + 3) // Start of group
  74. try withAbstractVisitor {(visitor: inout ProtobufVisitor) in
  75. try v.traverse(visitor: &visitor)
  76. }
  77. encoder.startField(tagType: protoFieldNumber * 8 + 4) // End of group
  78. }
  79. }
  80. mutating public func visitMapField<KeyType: ProtobufMapKeyType, ValueType: ProtobufMapValueType>(fieldType: ProtobufMap<KeyType, ValueType>.Type, value: ProtobufMap<KeyType, ValueType>.BaseType, protoFieldNumber: Int, protoFieldName: String, jsonFieldName: String, swiftFieldName: String) throws where KeyType.BaseType: Hashable {
  81. for (k,v) in value {
  82. encoder.startField(tagType: protoFieldNumber * 8 + 2)
  83. var subencoder = ProtobufBinaryEncoder()
  84. subencoder.startField(tagType: 8 + KeyType.protobufWireType())
  85. KeyType.serializeProtobufValue(encoder: &subencoder, value: k)
  86. subencoder.startField(tagType: 16 + ValueType.protobufWireType())
  87. // Note: ValueType could be a message, so messages need
  88. // static func serializeProtobufValue(...)
  89. // TODO: Could we traverse the valuetype instead?
  90. // TODO: Propagate failure out of here...
  91. try ValueType.serializeProtobufValue(encoder: &subencoder, value: v)
  92. encoder.putBytesValue(value: subencoder.buffer)
  93. }
  94. }
  95. }
  96. /*
  97. * Encoder for Binary Protocol Buffer format
  98. *
  99. * TODO: Should this be a class?
  100. */
  101. public struct ProtobufBinaryEncoder {
  102. public fileprivate(set) var buffer: [UInt8] = []
  103. public init() {}
  104. public mutating func appendUnknown(bytes: [UInt8]) {
  105. buffer.append(contentsOf: bytes)
  106. }
  107. mutating func startField(tagType: Int) {
  108. putVarInt(value: UInt64(tagType))
  109. }
  110. mutating func putVarInt(value: UInt64) {
  111. var v = value
  112. while v > 127 {
  113. buffer.append(UInt8(v & 0x7f | 0x80))
  114. v >>= 7
  115. }
  116. buffer.append(UInt8(v))
  117. }
  118. mutating func putVarInt(value: Int64) {
  119. putVarInt(value: UInt64(bitPattern: value))
  120. }
  121. mutating func putVarInt(value: Int) {
  122. putVarInt(value: Int64(value))
  123. }
  124. mutating func putZigZagVarInt(value: Int64) {
  125. let coded = UInt64(bitPattern: (value << 1))
  126. ^ UInt64(bitPattern: (value >> 63))
  127. putVarInt(value: coded)
  128. }
  129. mutating func putBoolValue(value: Bool) {
  130. buffer.append(value ? 1 : 0)
  131. }
  132. mutating func putFixedUInt64(value : UInt64) {
  133. var v = value
  134. let n = MemoryLayout<UInt64>.size
  135. withUnsafePointer(to: &v) { v -> () in
  136. v.withMemoryRebound(to: UInt8.self, capacity: n) { p -> () in
  137. let buff = UnsafeBufferPointer<UInt8>(start: p, count: n)
  138. buffer.append(contentsOf: buff)
  139. }
  140. }
  141. }
  142. mutating func putFixedUInt32(value : UInt32) {
  143. var v = value
  144. let n = MemoryLayout<UInt32>.size
  145. withUnsafePointer(to: &v) { v -> () in
  146. v.withMemoryRebound(to: UInt8.self, capacity: n) { p -> () in
  147. let buff = UnsafeBufferPointer<UInt8>(start: p, count: n)
  148. buffer.append(contentsOf: buff)
  149. }
  150. }
  151. }
  152. mutating func putFloatValue(value: Float) {
  153. var v = value
  154. let n = MemoryLayout<Float>.size
  155. withUnsafePointer(to: &v) { v -> () in
  156. v.withMemoryRebound(to: UInt8.self, capacity: n) { p -> () in
  157. let buff = UnsafeBufferPointer<UInt8>(start: p, count: n)
  158. buffer.append(contentsOf: buff)
  159. }
  160. }
  161. }
  162. mutating func putDoubleValue(value: Double) {
  163. var v = value
  164. let n = MemoryLayout<Double>.size
  165. withUnsafePointer(to: &v) { v -> () in
  166. v.withMemoryRebound(to: UInt8.self, capacity: n) { p -> () in
  167. let buff = UnsafeBufferPointer<UInt8>(start: p, count: n)
  168. buffer.append(contentsOf: buff)
  169. }
  170. }
  171. }
  172. // Write a string field, including the leading index/tag value.
  173. mutating func putStringValue(value: String) {
  174. let stringWithNul = value.utf8CString
  175. let stringLength = stringWithNul.count - 1
  176. putVarInt(value: stringLength)
  177. if stringLength > 0 {
  178. // TODO: There has got to be a better way to do this...
  179. stringWithNul.withUnsafeBufferPointer { bp -> () in
  180. bp.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: stringLength) { p -> () in
  181. let stringWithoutNul = UnsafeBufferPointer<UInt8>(start: p, count: stringLength)
  182. buffer.append(contentsOf: stringWithoutNul)
  183. }
  184. }
  185. }
  186. }
  187. mutating func putBytesValue(value: [UInt8]) {
  188. putVarInt(value: value.count)
  189. buffer.append(contentsOf: value)
  190. }
  191. }