Decode integers

This commit is contained in:
Damiaan Dufaux 2017-08-02 21:09:16 +02:00
parent 9c06dd51a8
commit 1255f3c3a7
5 changed files with 256 additions and 60 deletions

View file

@ -12,7 +12,7 @@
74FA3B501F2C9060005CE521 /* MsgPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 74FA3B461F2C9060005CE521 /* MsgPack.framework */; };
74FA3B551F2C9060005CE521 /* MsgPackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FA3B541F2C9060005CE521 /* MsgPackTests.swift */; };
74FA3B571F2C9060005CE521 /* MsgPack.h in Headers */ = {isa = PBXBuildFile; fileRef = 74FA3B491F2C9060005CE521 /* MsgPack.h */; settings = {ATTRIBUTES = (Public, ); }; };
74FA3B611F2C908D005CE521 /* DecoderHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FA3B601F2C908D005CE521 /* DecoderHelper.swift */; };
74FA3B611F2C908D005CE521 /* Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FA3B601F2C908D005CE521 /* Decoder.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -34,7 +34,7 @@
74FA3B4F1F2C9060005CE521 /* MsgPackTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MsgPackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
74FA3B541F2C9060005CE521 /* MsgPackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgPackTests.swift; sourceTree = "<group>"; };
74FA3B561F2C9060005CE521 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
74FA3B601F2C908D005CE521 /* DecoderHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecoderHelper.swift; sourceTree = "<group>"; };
74FA3B601F2C908D005CE521 /* Decoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decoder.swift; sourceTree = "<group>"; };
74FA3B621F2C9096005CE521 /* Encoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encoder.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -79,7 +79,7 @@
isa = PBXGroup;
children = (
74FA3B491F2C9060005CE521 /* MsgPack.h */,
74FA3B601F2C908D005CE521 /* DecoderHelper.swift */,
74FA3B601F2C908D005CE521 /* Decoder.swift */,
74FA3B621F2C9096005CE521 /* Encoder.swift */,
74A1AE161F2E3E8300B139A3 /* Format.swift */,
74FA3B4A1F2C9060005CE521 /* Info.plist */,
@ -208,7 +208,7 @@
files = (
7495EA251F30B393000EBDF6 /* Encoder.swift in Sources */,
74A1AE171F2E3E8300B139A3 /* Format.swift in Sources */,
74FA3B611F2C908D005CE521 /* DecoderHelper.swift in Sources */,
74FA3B611F2C908D005CE521 /* Decoder.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

156
MsgPack/Decoder.swift Normal file
View file

@ -0,0 +1,156 @@
//
// Decoder.swift
// MsgPack
//
// Created by Damiaan on 29/07/17.
// Copyright © 2017 dPro. All rights reserved.
//
import Foundation
public class Decoder {
public func decode<T : Decodable>(_ type: T.Type, from data: Data) throws -> T {
let decoder = IntermediateDecoder(with: data)
return try T(from: decoder)
}
public init() {}
}
class IntermediateDecoder: Swift.Decoder {
var codingPath = [CodingKey]()
var userInfo = [CodingUserInfoKey : Any]()
var storage: Data
var offset = 0
init(with data: Data) {
storage = data
}
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
fatalError()
}
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
fatalError()
}
func singleValueContainer() throws -> SingleValueDecodingContainer {
return MsgPckSingleValueDecodingContainer(refferingTo: self)
}
}
struct MsgPckSingleValueDecodingContainer: SingleValueDecodingContainer {
var codingPath = [CodingKey]()
var decoder: IntermediateDecoder
var base = 0
enum Error: Swift.Error {
case invalidFormat(UInt8)
}
init(refferingTo decoder: IntermediateDecoder) {
self.decoder = decoder
}
func decodeNil() -> Bool {
return decoder.storage[base] == FormatID.nil.rawValue
}
func decode(_ type: Bool.Type) throws -> Bool {
let byte = decoder.storage[base]
guard byte & 0b11111110 == FormatID.false.rawValue else {
throw Error.invalidFormat(byte)
}
return byte == FormatID.true.rawValue
}
func decode(_ type: Int.Type) throws -> Int {
fatalError("not implemented")
}
func decode(_ type: Int8.Type) throws -> Int8 {
guard decoder.storage[base] == FormatID.int8.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.read(at: base+1)
}
func decode(_ type: Int16.Type) throws -> Int16 {
guard decoder.storage[base] == FormatID.int16.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.bigEndianInteger(at: base+1)
}
func decode(_ type: Int32.Type) throws -> Int32 {
guard decoder.storage[base] == FormatID.int32.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.bigEndianInteger(at: base+1)
}
func decode(_ type: Int64.Type) throws -> Int64 {
guard decoder.storage[base] == FormatID.int64.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.bigEndianInteger(at: base+1)
}
func decode(_ type: UInt.Type) throws -> UInt {
fatalError("not implemented")
}
func decode(_ type: UInt8.Type) throws -> UInt8 {
guard decoder.storage[base] == FormatID.uInt8.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.read(at: base+1)
}
func decode(_ type: UInt16.Type) throws -> UInt16 {
guard decoder.storage[base] == FormatID.uInt16.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.bigEndianInteger(at: base+1)
}
func decode(_ type: UInt32.Type) throws -> UInt32 {
guard decoder.storage[base] == FormatID.uInt32.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.bigEndianInteger(at: base+1)
}
func decode(_ type: UInt64.Type) throws -> UInt64 {
guard decoder.storage[base] == FormatID.uInt64.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.bigEndianInteger(at: base+1)
}
func decode(_ type: Float.Type) throws -> Float {
guard decoder.storage[base] == FormatID.float32.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
return decoder.storage.read(at: base + 1)
}
func decode(_ type: Double.Type) throws -> Double {
guard decoder.storage[base] == FormatID.float64.rawValue else {
throw Error.invalidFormat(decoder.storage[base])
}
let bitPattern: UInt64 = decoder.storage.read(at: base + 1)
return .init(bitPattern)
}
func decode(_ type: String.Type) throws -> String {
fatalError("not implemented")
}
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
fatalError("not implemented")
}
}

View file

@ -1,30 +0,0 @@
//
// Decoder.swift
// MsgPack
//
// Created by Damiaan on 29/07/17.
// Copyright © 2017 dPro. All rights reserved.
//
import Foundation
//class MessagePackDecoder: Decoder {
// var codingPath = [CodingKey?]()
//
// var userInfo = [CodingUserInfoKey : Any]()
//
// func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
// <#code#>
// }
//
// func unkeyedContainer() throws -> UnkeyedDecodingContainer {
// <#code#>
// }
//
// func singleValueContainer() throws -> SingleValueDecodingContainer {
// <#code#>
// }
//
//
//}

View file

@ -14,7 +14,7 @@ enum Format {
case `nil`
case boolean(Bool)
case positiveInt7(UInt8)
case negativeInt5(UInt8)
@ -45,6 +45,56 @@ enum Format {
case map32 ([(key: Format, value: Format)])
}
public enum FormatID: UInt8 {
// Do not reorder the cases because their raw values are infered based on the ordering
case `nil` = 0xC0
case `false` = 0xC2
case `true`
case bin8
case bin16
case bin32
case ext8
case ext16
case ext32
case float32
case float64
case positiveInt7 = 0
case negativeInt5 = 0b11100000
case uInt8 = 0xCC
case uInt16
case uInt32
case uInt64
case int8
case int16
case int32
case int64
case fixExt1
case fixExt2
case fixExt4
case fixExt8
case fixExt16
case fixString = 0b10100000
case string8 = 0xD9
case string16
case string32
case fixArray = 0b10010000
case array16 = 0xDC
case array32
case fixMap = 0b10000000
case map16 = 0xDE
case map32
}
extension Format {
func appendTo(data: inout Data) {
@ -52,89 +102,91 @@ extension Format {
// MARK: Optional
case .nil:
data.append(0xC0)
data.append(FormatID.nil.rawValue)
// MARK: Boolean
case .boolean(let boolean):
data.append(boolean ? 0xC3 : 0xC2)
data.append(boolean ? FormatID.true.rawValue : FormatID.false.rawValue)
// MARK: Small integers (< 8 bit)
case .positiveInt7(let value):
data.append(value | 0b10000000)
data.append(value | FormatID.positiveInt7.rawValue)
case .negativeInt5(let value):
data.append(value | 0b11100000)
data.append(value | FormatID.negativeInt5.rawValue)
// MARK: Unsigned integers
case .uInt8(let value):
data.append(0xCC)
data.append(value)
data.append(contentsOf: [
FormatID.uInt8.rawValue,
value
])
case .uInt16(let value):
var newData = Data(count: 3)
newData[0] = 0xCD
newData[0] = FormatID.uInt16.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
case .uInt32(let value):
var newData = Data(count: 5)
newData[0] = 0xCE
newData[0] = FormatID.uInt32.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
case .uInt64(let value):
var newData = Data(count: 9)
newData[0] = 0xCF
newData[0] = FormatID.uInt64.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
// MARK: Signed integers
case .int8(let value):
var newData = Data(count: 2)
newData[0] = 0xD0
newData[0] = FormatID.int8.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
case .int16(let value):
var newData = Data(count: 3)
newData[0] = 0xD1
newData[0] = FormatID.int16.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
case .int32(let value):
var newData = Data(count: 5)
newData[0] = 0xD2
newData[0] = FormatID.int32.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
case .int64(let value):
var newData = Data(count: 9)
newData[0] = 0xD3
newData[0] = FormatID.int64.rawValue
newData.write(value: value.bigEndian, offset: 1)
data.append(newData)
// MARK: Floats
case .float32(let value):
var newData = Data(count: 5)
newData[0] = 0xCA
newData[0] = FormatID.float32.rawValue
newData.write(value: value.bitPattern.bigEndian, offset: 1)
data.append(newData)
case .float64(let value):
var newData = Data(count: 9)
newData[0] = 0xCB
newData[0] = FormatID.float64.rawValue
newData.write(value: value.bitPattern.bigEndian, offset: 1)
data.append(newData)
// MARK: Strings
case .fixString(let utf8Data):
precondition(utf8Data.count < 32, "fix strings cannot contain more than 31 bytes")
data.append( UInt8(utf8Data.count) | 0b10100000)
data.append( UInt8(utf8Data.count) | FormatID.fixString.rawValue)
data.append(utf8Data)
case .string8(let utf8Data):
data.append(contentsOf: [0xD9, UInt8(utf8Data.count)])
data.append(contentsOf: [FormatID.string8.rawValue, UInt8(utf8Data.count)])
data.append(utf8Data)
case .string16(let utf8Data):
var prefix = Data(count: 3)
prefix[0] = 0xDA
prefix[0] = FormatID.string16.rawValue
prefix.write(value: UInt16(utf8Data.count).bigEndian, offset: 1)
data.append(prefix)
data.append(utf8Data)
case .string32(let utf8Data):
var prefix = Data(count: 5)
prefix[0] = 0xDB
prefix[0] = FormatID.string32.rawValue
prefix.write(value: UInt32(utf8Data.count).bigEndian, offset: 1)
data.append(prefix)
data.append(utf8Data)
@ -142,13 +194,13 @@ extension Format {
// MARK: Arrays
case .fixArray(let array):
precondition(array.count < 16, "fix arrays cannot contain more than 15 elements")
data.append( UInt8(array.count) | 0b10010000)
data.append( UInt8(array.count) | FormatID.fixArray.rawValue)
for element in array {
element.appendTo(data: &data)
}
case .array16(let array):
var prefix = Data(count: 3)
prefix[0] = 0xDC
prefix[0] = FormatID.array16.rawValue
prefix.write(value: UInt16(array.count).bigEndian, offset: 1)
data.append(prefix)
for element in array {
@ -156,7 +208,7 @@ extension Format {
}
case .array32(let array):
var prefix = Data(count: 5)
prefix[0] = 0xDD
prefix[0] = FormatID.array32.rawValue
prefix.write(value: UInt32(array.count).bigEndian, offset: 1)
data.append(prefix)
for element in array {
@ -166,14 +218,14 @@ extension Format {
// MARK: Maps
case .fixMap(let pairs):
precondition(pairs.count < 16, "fix maps cannot contain more than 15 key-value pairs")
data.append( UInt8(pairs.count) | 0b10000000)
data.append( UInt8(pairs.count) | FormatID.fixMap.rawValue)
for (key, value) in pairs {
key.appendTo(data: &data)
value.appendTo(data: &data)
}
case .map16(let pairs):
var prefix = Data(count: 3)
prefix[0] = 0xDE
prefix[0] = FormatID.map16.rawValue
prefix.write(value: UInt16(pairs.count).bigEndian, offset: 1)
data.append(prefix)
for (key, value) in pairs {
@ -182,7 +234,7 @@ extension Format {
}
case .map32(let pairs):
var prefix = Data(count: 5)
prefix[0] = 0xDE
prefix[0] = FormatID.map32.rawValue
prefix.write(value: UInt32(pairs.count).bigEndian, offset: 1)
data.append(prefix)
for (key, value) in pairs {
@ -201,8 +253,21 @@ extension Data {
}
}
}
func read<T>(at offset: Int) -> T {
return withUnsafeBytes {(byteContainer: UnsafePointer<UInt8>) -> T in
byteContainer.advanced(by: offset).withMemoryRebound(to: T.self, capacity: 1) {$0.pointee}
}
}
func bigEndianInteger<T: FixedWidthInteger>(at offset: Int) -> T {
return withUnsafeBytes {(byteContainer: UnsafePointer<UInt8>) -> T in
byteContainer.advanced(by: offset).withMemoryRebound(to: T.self, capacity: 1) {T.init(bigEndian: $0.pointee)}
}
}
}
// MARK: encoding helpers
extension Format {
static func from(string: String) throws -> Format {
guard let data = string.data(using: .utf8) else {throw MsgPackEncodingError.stringNotConvertibleToUTF8(string)}

View file

@ -37,3 +37,8 @@ let encodedGraph = try encoder.encode(graph)
for byte in encodedGraph {
print(String(byte, radix:16))
}
let decoder = Decoder()
let int8 = try encoder.encode(Int8(-57))
try decoder.decode(Int8.self, from: int8)