mirror of
https://github.com/Dev1an/MsgPack.git
synced 2026-04-06 10:45:51 +00:00
Decode integers
This commit is contained in:
parent
9c06dd51a8
commit
1255f3c3a7
5 changed files with 256 additions and 60 deletions
|
|
@ -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
156
MsgPack/Decoder.swift
Normal 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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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#>
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue