| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // Sources/SwiftProtobuf/BinaryEncoder.swift - Binary encoding support
- //
- // Copyright (c) 2014 - 2016 Apple Inc. and the project authors
- // Licensed under Apache License v2.0 with Runtime Library Exception
- //
- // See LICENSE.txt for license information:
- // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
- //
- // -----------------------------------------------------------------------------
- ///
- /// Core support for protobuf binary encoding. Note that this is built
- /// on the general traversal machinery.
- ///
- // -----------------------------------------------------------------------------
- import Foundation
- /// Encoder for Binary Protocol Buffer format
- internal struct BinaryEncoder {
- private var pointer: UnsafeMutableRawPointer
- private var buffer: UnsafeMutableRawBufferPointer
- init(forWritingInto buffer: UnsafeMutableRawBufferPointer) {
- self.buffer = buffer
- self.pointer = buffer.baseAddress!
- }
- private mutating func append(_ byte: UInt8) {
- pointer.storeBytes(of: byte, as: UInt8.self)
- pointer = pointer.advanced(by: 1)
- }
- private mutating func append<Bytes: SwiftProtobufContiguousBytes>(contentsOf bytes: Bytes) {
- bytes.withUnsafeBytes { dataPointer in
- if let baseAddress = dataPointer.baseAddress, dataPointer.count > 0 {
- pointer.copyMemory(from: baseAddress, byteCount: dataPointer.count)
- advance(dataPointer.count)
- }
- }
- }
- internal var used: Int {
- buffer.baseAddress!.distance(to: pointer)
- }
- internal var remainder: UnsafeMutableRawBufferPointer {
- UnsafeMutableRawBufferPointer(
- start: pointer,
- count: buffer.count - used
- )
- }
- internal mutating func advance(_ bytes: Int) {
- pointer = pointer.advanced(by: bytes)
- }
- @discardableResult
- private mutating func append(contentsOf bufferPointer: UnsafeRawBufferPointer) -> Int {
- let count = bufferPointer.count
- if let baseAddress = bufferPointer.baseAddress, count > 0 {
- pointer.copyMemory(from: baseAddress, byteCount: count)
- }
- pointer = pointer.advanced(by: count)
- return count
- }
- mutating func appendUnknown(data: Data) {
- append(contentsOf: data)
- }
- mutating func startField(fieldNumber: Int, wireFormat: WireFormat) {
- startField(tag: FieldTag(fieldNumber: fieldNumber, wireFormat: wireFormat))
- }
- mutating func startField(tag: FieldTag) {
- putVarInt(value: UInt64(tag.rawValue))
- }
- mutating func putVarInt(value: UInt64) {
- var v = value
- while v > 127 {
- append(UInt8(v & 0x7f | 0x80))
- v >>= 7
- }
- append(UInt8(v))
- }
- mutating func putVarInt(value: Int64) {
- putVarInt(value: UInt64(bitPattern: value))
- }
- mutating func putVarInt(value: Int) {
- putVarInt(value: Int64(value))
- }
- mutating func putZigZagVarInt(value: Int64) {
- let coded = ZigZag.encoded(value)
- putVarInt(value: coded)
- }
- mutating func putBoolValue(value: Bool) {
- append(value ? 1 : 0)
- }
- mutating func putFixedUInt64(value: UInt64) {
- var v = value.littleEndian
- let n = MemoryLayout<UInt64>.size
- pointer.copyMemory(from: &v, byteCount: n)
- pointer = pointer.advanced(by: n)
- }
- mutating func putFixedUInt32(value: UInt32) {
- var v = value.littleEndian
- let n = MemoryLayout<UInt32>.size
- pointer.copyMemory(from: &v, byteCount: n)
- pointer = pointer.advanced(by: n)
- }
- mutating func putFloatValue(value: Float) {
- let n = MemoryLayout<Float>.size
- var v = value.bitPattern.littleEndian
- pointer.copyMemory(from: &v, byteCount: n)
- pointer = pointer.advanced(by: n)
- }
- mutating func putDoubleValue(value: Double) {
- let n = MemoryLayout<Double>.size
- var v = value.bitPattern.littleEndian
- pointer.copyMemory(from: &v, byteCount: n)
- pointer = pointer.advanced(by: n)
- }
- // Write a string field, including the leading index/tag value.
- mutating func putStringValue(value: String) {
- let utf8 = value.utf8
- // If the String does not support an internal representation in a form
- // of contiguous storage, body is not called and nil is returned.
- let isAvailable = utf8.withContiguousStorageIfAvailable { (body: UnsafeBufferPointer<UInt8>) -> Int in
- putVarInt(value: body.count)
- return append(contentsOf: UnsafeRawBufferPointer(body))
- }
- if isAvailable == nil {
- let count = utf8.count
- putVarInt(value: count)
- for b in utf8 {
- pointer.storeBytes(of: b, as: UInt8.self)
- pointer = pointer.advanced(by: 1)
- }
- }
- }
- mutating func putBytesValue<Bytes: SwiftProtobufContiguousBytes>(value: Bytes) {
- putVarInt(value: value.count)
- append(contentsOf: value)
- }
- }
|