/src/swift-protobuf/Sources/SwiftProtobuf/BinaryEncoder.swift
Line | Count | Source |
1 | | // Sources/SwiftProtobuf/BinaryEncoder.swift - Binary 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 | | /// Core support for protobuf binary encoding. Note that this is built |
12 | | /// on the general traversal machinery. |
13 | | /// |
14 | | // ----------------------------------------------------------------------------- |
15 | | |
16 | | import Foundation |
17 | | |
18 | | /// Encoder for Binary Protocol Buffer format |
19 | | internal struct BinaryEncoder { |
20 | | private var pointer: UnsafeMutableRawPointer |
21 | | private var buffer: UnsafeMutableRawBufferPointer |
22 | | |
23 | 5.40M | init(forWritingInto buffer: UnsafeMutableRawBufferPointer) { |
24 | 5.40M | self.buffer = buffer |
25 | 5.40M | self.pointer = buffer.baseAddress! |
26 | 5.40M | } |
27 | | |
28 | 2.18G | private mutating func append(_ byte: UInt8) { |
29 | 2.18G | pointer.storeBytes(of: byte, as: UInt8.self) |
30 | 2.18G | pointer = pointer.advanced(by: 1) |
31 | 2.18G | } |
32 | | |
33 | 2.39M | private mutating func append<Bytes: SwiftProtobufContiguousBytes>(contentsOf bytes: Bytes) { |
34 | 2.39M | bytes.withUnsafeBytes { dataPointer in |
35 | 2.39M | if let baseAddress = dataPointer.baseAddress, dataPointer.count > 0 { |
36 | 2.04M | pointer.copyMemory(from: baseAddress, byteCount: dataPointer.count) |
37 | 2.04M | advance(dataPointer.count) |
38 | 2.04M | } |
39 | 2.39M | } |
40 | 2.39M | } |
41 | | |
42 | 48.6k | internal var used: Int { |
43 | 48.6k | buffer.baseAddress!.distance(to: pointer) |
44 | 48.6k | } |
45 | | |
46 | 6.08k | internal var remainder: UnsafeMutableRawBufferPointer { |
47 | 6.08k | UnsafeMutableRawBufferPointer( |
48 | 6.08k | start: pointer, |
49 | 6.08k | count: buffer.count - used |
50 | 6.08k | ) |
51 | 6.08k | } |
52 | | |
53 | 4.25M | internal mutating func advance(_ bytes: Int) { |
54 | 4.25M | pointer = pointer.advanced(by: bytes) |
55 | 4.25M | } |
56 | | |
57 | | @discardableResult |
58 | 527k | private mutating func append(contentsOf bufferPointer: UnsafeRawBufferPointer) -> Int { |
59 | 527k | let count = bufferPointer.count |
60 | 527k | if let baseAddress = bufferPointer.baseAddress, count > 0 { |
61 | 152k | pointer.copyMemory(from: baseAddress, byteCount: count) |
62 | 152k | } |
63 | 527k | pointer = pointer.advanced(by: count) |
64 | 527k | return count |
65 | 527k | } |
66 | | |
67 | 337k | mutating func appendUnknown(data: Data) { |
68 | 337k | append(contentsOf: data) |
69 | 337k | } |
70 | | |
71 | 171M | mutating func startField(fieldNumber: Int, wireFormat: WireFormat) { |
72 | 171M | startField(tag: FieldTag(fieldNumber: fieldNumber, wireFormat: wireFormat)) |
73 | 171M | } |
74 | | |
75 | 306M | mutating func startField(tag: FieldTag) { |
76 | 306M | putVarInt(value: UInt64(tag.rawValue)) |
77 | 306M | } |
78 | | |
79 | 1.58G | mutating func putVarInt(value: UInt64) { |
80 | 1.58G | var v = value |
81 | 2.17G | while v > 127 { |
82 | 589M | append(UInt8(v & 0x7f | 0x80)) |
83 | 589M | v >>= 7 |
84 | 1.58G | } |
85 | 1.58G | append(UInt8(v)) |
86 | 1.58G | } |
87 | | |
88 | 636M | mutating func putVarInt(value: Int64) { |
89 | 636M | putVarInt(value: UInt64(bitPattern: value)) |
90 | 636M | } |
91 | | |
92 | 146M | mutating func putVarInt(value: Int) { |
93 | 146M | putVarInt(value: Int64(value)) |
94 | 146M | } |
95 | | |
96 | 1.58M | mutating func putZigZagVarInt(value: Int64) { |
97 | 1.58M | let coded = ZigZag.encoded(value) |
98 | 1.58M | putVarInt(value: coded) |
99 | 1.58M | } |
100 | | |
101 | 0 | mutating func putBoolValue(value: Bool) { |
102 | 0 | append(value ? 1 : 0) |
103 | 0 | } |
104 | | |
105 | 9.52M | mutating func putFixedUInt64(value: UInt64) { |
106 | 9.52M | var v = value.littleEndian |
107 | 9.52M | let n = MemoryLayout<UInt64>.size |
108 | 9.52M | pointer.copyMemory(from: &v, byteCount: n) |
109 | 9.52M | pointer = pointer.advanced(by: n) |
110 | 9.52M | } |
111 | | |
112 | 9.72M | mutating func putFixedUInt32(value: UInt32) { |
113 | 9.72M | var v = value.littleEndian |
114 | 9.72M | let n = MemoryLayout<UInt32>.size |
115 | 9.72M | pointer.copyMemory(from: &v, byteCount: n) |
116 | 9.72M | pointer = pointer.advanced(by: n) |
117 | 9.72M | } |
118 | | |
119 | 3.61M | mutating func putFloatValue(value: Float) { |
120 | 3.61M | let n = MemoryLayout<Float>.size |
121 | 3.61M | var v = value.bitPattern.littleEndian |
122 | 3.61M | pointer.copyMemory(from: &v, byteCount: n) |
123 | 3.61M | pointer = pointer.advanced(by: n) |
124 | 3.61M | } |
125 | | |
126 | 3.20M | mutating func putDoubleValue(value: Double) { |
127 | 3.20M | let n = MemoryLayout<Double>.size |
128 | 3.20M | var v = value.bitPattern.littleEndian |
129 | 3.20M | pointer.copyMemory(from: &v, byteCount: n) |
130 | 3.20M | pointer = pointer.advanced(by: n) |
131 | 3.20M | } |
132 | | |
133 | | // Write a string field, including the leading index/tag value. |
134 | 469k | mutating func putStringValue(value: String) { |
135 | 469k | let utf8 = value.utf8 |
136 | 469k | // If the String does not support an internal representation in a form |
137 | 469k | // of contiguous storage, body is not called and nil is returned. |
138 | 527k | let isAvailable = utf8.withContiguousStorageIfAvailable { (body: UnsafeBufferPointer<UInt8>) -> Int in |
139 | 527k | putVarInt(value: body.count) |
140 | 527k | return append(contentsOf: UnsafeRawBufferPointer(body)) |
141 | 527k | } |
142 | 469k | if isAvailable == nil { |
143 | 0 | let count = utf8.count |
144 | 0 | putVarInt(value: count) |
145 | 0 | for b in utf8 { |
146 | 0 | pointer.storeBytes(of: b, as: UInt8.self) |
147 | 0 | pointer = pointer.advanced(by: 1) |
148 | 0 | } |
149 | 0 | } |
150 | 469k | } |
151 | | |
152 | 3.39M | mutating func putBytesValue<Bytes: SwiftProtobufContiguousBytes>(value: Bytes) { |
153 | 3.39M | putVarInt(value: value.count) |
154 | 3.39M | append(contentsOf: value) |
155 | 3.39M | } |
156 | | } |