summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift571
1 files changed, 571 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift b/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift
new file mode 100644
index 000000000..5b302d38f
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/swift/Sources/TCompactProtocol.swift
@@ -0,0 +1,571 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import Foundation
+import CoreFoundation
+
+public enum TCType: UInt8 {
+ case stop = 0x00
+ case boolean_TRUE = 0x01
+ case boolean_FALSE = 0x02
+ case i8 = 0x03
+ case i16 = 0x04
+ case i32 = 0x05
+ case i64 = 0x06
+ case double = 0x07
+ case binary = 0x08
+ case list = 0x09
+ case set = 0x0A
+ case map = 0x0B
+ case `struct` = 0x0C
+
+ public static let typeMask: UInt8 = 0xE0 // 1110 0000
+ public static let typeBits: UInt8 = 0x07 // 0000 0111
+ public static let typeShiftAmount = 5
+
+}
+
+
+public class TCompactProtocol: TProtocol {
+ public static let protocolID: UInt8 = 0x82
+ public static let version: UInt8 = 1
+ public static let versionMask: UInt8 = 0x1F // 0001 1111
+
+ public var transport: TTransport
+
+ var lastField: [UInt8] = []
+ var lastFieldId: UInt8 = 0
+
+ var boolFieldName: String?
+ var boolFieldType: TType?
+ var boolFieldId: Int32?
+ var booleanValue: Bool?
+
+ var currentMessageName: String?
+
+ public required init(on transport: TTransport) {
+ self.transport = transport
+ }
+
+
+ /// Mark: - TCompactProtocol helpers
+
+ func writebyteDirect(_ byte: UInt8) throws {
+ let byte = Data([byte])
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+ try self.transport.write(data: byte)
+ }
+ }
+
+ func writeVarint32(_ val: UInt32) throws {
+ var val = val
+ var i32buf = [UInt8](repeating: 0, count: 5)
+ var idx = 0
+ while true {
+ if (val & ~0x7F) == 0 {
+ i32buf[idx] = UInt8(val)
+ idx += 1
+ break
+ } else {
+ i32buf[idx] = UInt8((val & 0x7F) | 0x80)
+ idx += 1
+ val >>= 7
+ }
+ }
+
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+ try self.transport.write(data: Data(i32buf[0..<idx]))
+ }
+ }
+
+ func writeVarint64(_ val: UInt64) throws {
+ var val = val
+ var varint64out = [UInt8](repeating: 0, count: 10)
+ var idx = 0
+ while true {
+ if (val & ~0x7F) == 0{
+ varint64out[idx] = UInt8(val)
+ idx += 1
+ break
+ } else {
+ varint64out[idx] = UInt8(val & 0x7F) | 0x80
+ idx += 1
+ val >>= 7
+ }
+ }
+
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+ try self.transport.write(data: Data(varint64out[0..<idx]))
+ }
+ }
+
+ func writeCollectionBegin(_ elementType: TType, size: Int32) throws {
+ let ctype = compactType(elementType).rawValue
+ if size <= 14 {
+ try writebyteDirect(UInt8(size << 4) | ctype)
+ } else {
+ try writebyteDirect(0xF0 | ctype)
+ try writeVarint32(UInt32(size))
+ }
+ }
+
+ func readBinary(_ size: Int) throws -> Data {
+ var result = Data()
+ if size != 0 {
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+ result = try self.transport.readAll(size: size)
+ }
+ }
+ return result
+ }
+
+ func readVarint32() throws -> UInt32 {
+ var result: UInt32 = 0
+ var shift: UInt32 = 0
+ while true {
+ let byte: UInt8 = try read()
+
+ result |= UInt32(byte & 0x7F) << shift
+ if (byte & 0x80) == 0 {
+ break
+ }
+
+ shift += 7
+ }
+
+ return result
+ }
+
+ func readVarint64() throws -> UInt64 {
+ var result: UInt64 = 0
+ var shift: UInt64 = 0
+
+ while true {
+ let byte: UInt8 = try read()
+
+ result |= UInt64(byte & 0x7F) << shift
+ if (byte & 0x80) == 0 {
+ break
+ }
+
+ shift += 7
+ }
+ return result
+ }
+
+
+ func ttype(_ compactTypeVal: UInt8) throws -> TType {
+ guard let compactType = TCType(rawValue: compactTypeVal) else {
+ throw TProtocolError(message: "Unknown TCType value: \(compactTypeVal)")
+ }
+
+ switch compactType {
+ case .stop: return .stop;
+ case .boolean_FALSE, .boolean_TRUE: return .bool;
+ case .i8: return .i8;
+ case .i16: return .i16;
+ case .i32: return .i32;
+ case .i64: return .i64;
+ case .double: return .double;
+ case .binary: return .string;
+ case .list: return .list;
+ case .set: return .set;
+ case .map: return .map;
+ case .struct: return .struct;
+ }
+ }
+
+ func compactType(_ ttype: TType) -> TCType {
+ switch ttype {
+ case .stop: return .stop
+ case .void: return .i8
+ case .bool: return .boolean_FALSE
+ case .i8: return .i8
+ case .double: return .double
+ case .i16: return .i16
+ case .i32: return .i32
+ case .i64: return .i64
+ case .string: return .binary
+ case .struct: return .struct
+ case .map: return .map
+ case .set: return .set
+ case .list: return .list
+ case .utf8: return .binary
+ case .utf16: return .binary
+ }
+ }
+
+ /// ZigZag encoding maps signed integers to unsigned integers so that
+ /// numbers with a small absolute value (for instance, -1) have
+ /// a small varint encoded value too. It does this in a way that
+ /// "zig-zags" back and forth through the positive and negative integers,
+ /// so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so
+ ///
+ /// - parameter n: number to zigzag
+ ///
+ /// - returns: zigzaged UInt32
+ func i32ToZigZag(_ n : Int32) -> UInt32 {
+ return UInt32(bitPattern: Int32(n << 1) ^ Int32(n >> 31))
+ }
+
+ func i64ToZigZag(_ n : Int64) -> UInt64 {
+ return UInt64(bitPattern: Int64(n << 1) ^ Int64(n >> 63))
+ }
+
+ func zigZagToi32(_ n: UInt32) -> Int32 {
+ return Int32(n >> 1) ^ (-Int32(n & 1))
+ }
+
+ func zigZagToi64(_ n: UInt64) -> Int64 {
+ return Int64(n >> 1) ^ (-Int64(n & 1))
+ }
+
+
+
+ /// Mark: - TProtocol
+
+ public func readMessageBegin() throws -> (String, TMessageType, Int32) {
+ let protocolId: UInt8 = try read()
+
+ if protocolId != TCompactProtocol.protocolID {
+ let expected = String(format:"%2X", TCompactProtocol.protocolID)
+ let got = String(format:"%2X", protocolId)
+ throw TProtocolError(message: "Wrong Protocol ID \(got)",
+ extendedError: .mismatchedProtocol(expected: expected, got: got))
+ }
+
+ let versionAndType: UInt8 = try read()
+ let version: UInt8 = versionAndType & TCompactProtocol.versionMask
+ if version != TCompactProtocol.version {
+ throw TProtocolError(error: .badVersion(expected: "\(TCompactProtocol.version)",
+ got:"\(version)"))
+ }
+
+ let type = (versionAndType >> UInt8(TCType.typeShiftAmount)) & TCType.typeBits
+ guard let mtype = TMessageType(rawValue: Int32(type)) else {
+ throw TProtocolError(message: "Unknown TMessageType value: \(type)")
+ }
+ let sequenceId = try readVarint32()
+ let name: String = try read()
+
+ return (name, mtype, Int32(sequenceId))
+ }
+
+ public func readMessageEnd() throws { }
+
+ public func readStructBegin() throws -> String {
+ lastField.append(lastFieldId)
+ lastFieldId = 0
+ return ""
+ }
+
+ public func readStructEnd() throws {
+ lastFieldId = lastField.last ?? 0
+ lastField.removeLast()
+ }
+
+ public func readFieldBegin() throws -> (String, TType, Int32) {
+ let byte: UInt8 = try read()
+ guard let type = TCType(rawValue: byte & 0x0F) else {
+ throw TProtocolError(message: "Unknown TCType \(byte & 0x0F)")
+ }
+
+ // if it's a stop, then we can return immediately, as the struct is over
+ if type == .stop {
+ return ("", .stop, 0)
+ }
+
+ var fieldId: Int16 = 0
+
+ // mask off the 4MSB of the type header. it could contain a field id delta
+ let modifier = (byte & 0xF0) >> 4
+ if modifier == 0 {
+ // not a delta. look ahead for the zigzag varint field id
+ fieldId = try read()
+ } else {
+ // has a delta. add the delta to the last Read field id.
+ fieldId = Int16(lastFieldId + modifier)
+ }
+
+ let fieldType = try ttype(type.rawValue)
+
+ // if this happens to be a boolean field, the value is encoded in the type
+ if type == .boolean_TRUE || type == .boolean_FALSE {
+ // save the boolean value in a special instance variable
+ booleanValue = type == .boolean_TRUE
+ }
+
+ // push the new field onto the field stack so we can keep the deltas going
+ lastFieldId = UInt8(fieldId)
+ return ("", fieldType, Int32(fieldId))
+ }
+
+ public func readFieldEnd() throws { }
+
+ public func read() throws -> String {
+ let length = try readVarint32()
+
+ var result: String
+
+ if length != 0 {
+ let data = try readBinary(Int(length))
+ result = String(data: data, encoding: String.Encoding.utf8) ?? ""
+ } else {
+ result = ""
+ }
+
+ return result
+ }
+
+ public func read() throws -> Bool {
+ if let val = booleanValue {
+ self.booleanValue = nil
+ return val
+ } else {
+ let result = try read() as UInt8
+ return TCType(rawValue: result) == .boolean_TRUE
+ }
+ }
+
+ public func read() throws -> UInt8 {
+ var buff: UInt8 = 0
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+ buff = try self.transport.readAll(size: 1)[0]
+ }
+ return buff
+ }
+
+ public func read() throws -> Int16 {
+ let v = try readVarint32()
+ return Int16(zigZagToi32(v))
+ }
+
+ public func read() throws -> Int32 {
+ let v = try readVarint32()
+ return zigZagToi32(v)
+ }
+
+ public func read() throws -> Int64 {
+ let v = try readVarint64()
+ return zigZagToi64(v)
+ }
+
+ public func read() throws -> Double {
+ var buff = Data()
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+ buff = try self.transport.readAll(size: 8)
+ }
+
+ let i64: UInt64 = buff.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> UInt64 in
+ return UnsafePointer<UInt64>(OpaquePointer(ptr)).pointee
+ }
+ let bits = CFSwapInt64LittleToHost(i64)
+ return Double(bitPattern: bits)
+ }
+
+ public func read() throws -> Data {
+ let length = try readVarint32()
+ return try readBinary(Int(length))
+ }
+
+ public func readMapBegin() throws -> (TType, TType, Int32) {
+ var keyAndValueType: UInt8 = 8
+ let size = try readVarint32()
+ if size != 0 {
+ keyAndValueType = try read()
+ }
+
+ let keyType = try ttype(keyAndValueType >> 4)
+ let valueType = try ttype(keyAndValueType & 0xF)
+
+ return (keyType, valueType, Int32(size))
+ }
+
+ public func readMapEnd() throws { }
+
+ public func readSetBegin() throws -> (TType, Int32) {
+ return try readListBegin()
+ }
+
+ public func readSetEnd() throws { }
+
+ public func readListBegin() throws -> (TType, Int32) {
+ let sizeAndType: UInt8 = try read()
+ var size: UInt32 = UInt32(sizeAndType >> 4) & 0x0f
+ if size == 15 {
+ size = try readVarint32()
+ }
+ let elementType = try ttype(sizeAndType & 0x0F)
+
+ return (elementType, Int32(size))
+ }
+
+ public func readListEnd() throws { }
+
+ public func writeMessageBegin(name: String,
+ type messageType: TMessageType,
+ sequenceID: Int32) throws {
+ try writebyteDirect(TCompactProtocol.protocolID)
+ let nextByte: UInt8 = (TCompactProtocol.version & TCompactProtocol.versionMask) |
+ (UInt8((UInt32(messageType.rawValue) << UInt32(TCType.typeShiftAmount))) &
+ TCType.typeMask)
+ try writebyteDirect(nextByte)
+ try writeVarint32(UInt32(sequenceID))
+ try write(name)
+
+ currentMessageName = name
+ }
+
+ public func writeMessageEnd() throws {
+ currentMessageName = nil
+ }
+
+ public func writeStructBegin(name: String) throws {
+ lastField.append(lastFieldId)
+ lastFieldId = 0
+ }
+
+ public func writeStructEnd() throws {
+ lastFieldId = lastField.last ?? 0
+ lastField.removeLast()
+ }
+
+ public func writeFieldBegin(name: String,
+ type fieldType: TType,
+ fieldID: Int32) throws {
+ if fieldType == .bool {
+ boolFieldName = name
+ boolFieldType = fieldType
+ boolFieldId = fieldID
+ return
+ } else {
+ try writeFieldBeginInternal(name: name,
+ type: fieldType,
+ fieldID: fieldID,
+ typeOverride: 0xFF)
+ }
+ }
+
+ func writeFieldBeginInternal(name: String,
+ type fieldType: TType,
+ fieldID: Int32,
+ typeOverride: UInt8) throws {
+
+ let typeToWrite = typeOverride == 0xFF ? compactType(fieldType).rawValue : typeOverride
+
+ // check if we can use delta encoding for the field id
+ let diff = UInt8(fieldID) - lastFieldId
+ if (UInt8(fieldID) > lastFieldId) && (diff <= 15) {
+ // Write them together
+ try writebyteDirect((UInt8(fieldID) - lastFieldId) << 4 | typeToWrite)
+
+ } else {
+ // Write them separate
+ try writebyteDirect(typeToWrite)
+ try write(Int16(fieldID))
+ }
+
+ lastFieldId = UInt8(fieldID)
+ }
+
+ public func writeFieldStop() throws {
+ try writebyteDirect(TCType.stop.rawValue)
+ }
+
+ public func writeFieldEnd() throws { }
+
+ public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws {
+ if size == 0 {
+ try writebyteDirect(0)
+ } else {
+ try writeVarint32(UInt32(size))
+
+ let compactedTypes = compactType(keyType).rawValue << 4 | compactType(valueType).rawValue
+ try writebyteDirect(compactedTypes)
+ }
+ }
+
+ public func writeMapEnd() throws { }
+
+ public func writeSetBegin(elementType: TType, size: Int32) throws {
+ try writeCollectionBegin(elementType, size: size)
+ }
+
+ public func writeSetEnd() throws { }
+
+ public func writeListBegin(elementType: TType, size: Int32) throws {
+ try writeCollectionBegin(elementType, size: size)
+ }
+
+ public func writeListEnd() throws { }
+
+ public func write(_ value: String) throws {
+ try write(value.data(using: String.Encoding.utf8)!)
+ }
+
+ public func write(_ value: Bool) throws {
+ if let boolFieldId = boolFieldId, let boolFieldType = boolFieldType,
+ let boolFieldName = boolFieldName {
+
+ // we haven't written the field header yet
+ let compactType: TCType = value ? .boolean_TRUE : .boolean_FALSE
+ try writeFieldBeginInternal(name: boolFieldName, type: boolFieldType, fieldID: boolFieldId,
+ typeOverride: compactType.rawValue)
+ self.boolFieldId = nil
+ self.boolFieldType = nil
+ self.boolFieldName = nil
+ } else {
+ // we're not part of a field, so just write the value.
+ try writebyteDirect(value ? TCType.boolean_TRUE.rawValue : TCType.boolean_FALSE.rawValue)
+ }
+ }
+
+ public func write(_ value: UInt8) throws {
+ try writebyteDirect(value)
+ }
+
+ public func write(_ value: Int16) throws {
+ try writeVarint32(i32ToZigZag(Int32(value)))
+ }
+
+ public func write(_ value: Int32) throws {
+ try writeVarint32(i32ToZigZag(value))
+ }
+
+ public func write(_ value: Int64) throws {
+ try writeVarint64(i64ToZigZag(value))
+ }
+
+ public func write(_ value: Double) throws {
+ var bits = CFSwapInt64HostToLittle(value.bitPattern)
+ let data = withUnsafePointer(to: &bits) {
+ return Data(bytes: UnsafePointer<UInt8>(OpaquePointer($0)), count: MemoryLayout<UInt64>.size)
+ }
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+ try self.transport.write(data: data)
+ }
+ }
+
+ public func write(_ data: Data) throws {
+ try writeVarint32(UInt32(data.count))
+ try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+ try self.transport.write(data: data)
+ }
+ }
+}