mirror of
https://github.com/Dev1an/MsgPack.git
synced 2026-03-25 08:45:55 +00:00
Decode nested structs
This commit is contained in:
parent
b640c44128
commit
d4a3b31dd1
7 changed files with 249 additions and 86 deletions
|
|
@ -9,6 +9,7 @@
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
7495EA251F30B393000EBDF6 /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FA3B621F2C9096005CE521 /* Encoder.swift */; };
|
7495EA251F30B393000EBDF6 /* Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FA3B621F2C9096005CE521 /* Encoder.swift */; };
|
||||||
74A1AE171F2E3E8300B139A3 /* Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74A1AE161F2E3E8300B139A3 /* Format.swift */; };
|
74A1AE171F2E3E8300B139A3 /* Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74A1AE161F2E3E8300B139A3 /* Format.swift */; };
|
||||||
|
74E08F571F3360B2008C0F36 /* Reference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08F561F3360B2008C0F36 /* Reference.swift */; };
|
||||||
74FA3B501F2C9060005CE521 /* MsgPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 74FA3B461F2C9060005CE521 /* MsgPack.framework */; };
|
74FA3B501F2C9060005CE521 /* MsgPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 74FA3B461F2C9060005CE521 /* MsgPack.framework */; };
|
||||||
74FA3B551F2C9060005CE521 /* MsgPackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FA3B541F2C9060005CE521 /* MsgPackTests.swift */; };
|
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, ); }; };
|
74FA3B571F2C9060005CE521 /* MsgPack.h in Headers */ = {isa = PBXBuildFile; fileRef = 74FA3B491F2C9060005CE521 /* MsgPack.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
|
@ -28,6 +29,7 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
74A1AE161F2E3E8300B139A3 /* Format.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Format.swift; sourceTree = "<group>"; };
|
74A1AE161F2E3E8300B139A3 /* Format.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Format.swift; sourceTree = "<group>"; };
|
||||||
74A426DB1F30774F001BE9C4 /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
|
74A426DB1F30774F001BE9C4 /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
|
||||||
|
74E08F561F3360B2008C0F36 /* Reference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reference.swift; sourceTree = "<group>"; };
|
||||||
74FA3B461F2C9060005CE521 /* MsgPack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MsgPack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
74FA3B461F2C9060005CE521 /* MsgPack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MsgPack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
74FA3B491F2C9060005CE521 /* MsgPack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MsgPack.h; sourceTree = "<group>"; };
|
74FA3B491F2C9060005CE521 /* MsgPack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MsgPack.h; sourceTree = "<group>"; };
|
||||||
74FA3B4A1F2C9060005CE521 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
74FA3B4A1F2C9060005CE521 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
|
@ -82,6 +84,7 @@
|
||||||
74FA3B601F2C908D005CE521 /* Decoder.swift */,
|
74FA3B601F2C908D005CE521 /* Decoder.swift */,
|
||||||
74FA3B621F2C9096005CE521 /* Encoder.swift */,
|
74FA3B621F2C9096005CE521 /* Encoder.swift */,
|
||||||
74A1AE161F2E3E8300B139A3 /* Format.swift */,
|
74A1AE161F2E3E8300B139A3 /* Format.swift */,
|
||||||
|
74E08F561F3360B2008C0F36 /* Reference.swift */,
|
||||||
74FA3B4A1F2C9060005CE521 /* Info.plist */,
|
74FA3B4A1F2C9060005CE521 /* Info.plist */,
|
||||||
74A426DB1F30774F001BE9C4 /* JSON.swift */,
|
74A426DB1F30774F001BE9C4 /* JSON.swift */,
|
||||||
);
|
);
|
||||||
|
|
@ -207,6 +210,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
7495EA251F30B393000EBDF6 /* Encoder.swift in Sources */,
|
7495EA251F30B393000EBDF6 /* Encoder.swift in Sources */,
|
||||||
|
74E08F571F3360B2008C0F36 /* Reference.swift in Sources */,
|
||||||
74A1AE171F2E3E8300B139A3 /* Format.swift in Sources */,
|
74A1AE171F2E3E8300B139A3 /* Format.swift in Sources */,
|
||||||
74FA3B611F2C908D005CE521 /* Decoder.swift in Sources */,
|
74FA3B611F2C908D005CE521 /* Decoder.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,20 @@ public class Decoder {
|
||||||
public init() {}
|
public init() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias PartiallyDecodedDictionary = [String:PartiallyDecodedValue]
|
class PartiallyDecodedDictionary: Reference<[String:PartiallyDecodedValue]> {
|
||||||
|
let pointer: Int
|
||||||
|
var byteCount = 0
|
||||||
|
init(pointer: Int) {
|
||||||
|
self.pointer = pointer
|
||||||
|
super.init(to: [:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum PartiallyDecodedValue {
|
enum PartiallyDecodedValue {
|
||||||
case constant(FormatID)
|
case constant(FormatID)
|
||||||
case fixedWidth(FormatID, pointer: Int)
|
case fixedWidth(FormatID, pointer: Int)
|
||||||
case variableWidth(FormatID, pointer: Int, length: Int)
|
case variableWidth(FormatID, pointer: Int, length: Int)
|
||||||
case array([PartiallyDecodedValue])
|
case array([PartiallyDecodedValue], pointer: Int, byteCount: Int)
|
||||||
case dictionary(PartiallyDecodedDictionary)
|
case dictionary(PartiallyDecodedDictionary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,16 +40,27 @@ class IntermediateDecoder: Swift.Decoder {
|
||||||
var userInfo = [CodingUserInfoKey : Any]()
|
var userInfo = [CodingUserInfoKey : Any]()
|
||||||
|
|
||||||
var storage: Data
|
var storage: Data
|
||||||
var offset = 0
|
|
||||||
|
|
||||||
var dictionary = PartiallyDecodedDictionary()
|
let dictionary: PartiallyDecodedDictionary
|
||||||
|
|
||||||
init(with data: Data) {
|
init(with data: Data) {
|
||||||
storage = data
|
storage = data
|
||||||
|
dictionary = PartiallyDecodedDictionary(pointer: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(withUnsafeDataFrom otherDecoder: IntermediateDecoder, start: Int, length: Int) {
|
||||||
|
storage = otherDecoder.storage.withUnsafeMutableBytes {
|
||||||
|
Data(bytesNoCopy: $0.advanced(by: start), count: length, deallocator: .none)
|
||||||
|
}
|
||||||
|
dictionary = otherDecoder.dictionary
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(withUnsafeDataFrom otherDecoder: IntermediateDecoder, start: Int) {
|
||||||
|
self.init(withUnsafeDataFrom: otherDecoder, start: start, length: otherDecoder.storage.count - start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
|
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
|
||||||
return KeyedDecodingContainer(try MsgPckKeyedDecodingContainer<Key>(referringTo: self, at: offset, with: []))
|
return KeyedDecodingContainer(try MsgPckKeyedDecodingContainer<Key>(referringTo: self, with: codingPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
|
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
|
||||||
|
|
@ -55,7 +74,7 @@ class IntermediateDecoder: Swift.Decoder {
|
||||||
|
|
||||||
struct MsgPckSingleValueDecodingContainer: SingleValueDecodingContainer {
|
struct MsgPckSingleValueDecodingContainer: SingleValueDecodingContainer {
|
||||||
let decoder: IntermediateDecoder
|
let decoder: IntermediateDecoder
|
||||||
var base: Int
|
let base: Int
|
||||||
|
|
||||||
var codingPath: [CodingKey]
|
var codingPath: [CodingKey]
|
||||||
|
|
||||||
|
|
@ -165,42 +184,63 @@ struct MsgPckSingleValueDecodingContainer: SingleValueDecodingContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TemporaryCodingKey: CodingKey {
|
||||||
|
let stringValue: String
|
||||||
|
let intValue: Int? = nil
|
||||||
|
|
||||||
|
init?(stringValue: String) {
|
||||||
|
self.stringValue = stringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
init?(intValue: Int) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtocol {
|
struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtocol {
|
||||||
var codingPath: [CodingKey]
|
var codingPath: [CodingKey]
|
||||||
|
|
||||||
|
let relativeDictionary: PartiallyDecodedDictionary
|
||||||
|
|
||||||
let decoder: IntermediateDecoder
|
let decoder: IntermediateDecoder
|
||||||
var base = 0
|
|
||||||
|
|
||||||
var allKeys = [K]()
|
var allKeys = [K]()
|
||||||
|
|
||||||
init(referringTo decoder: IntermediateDecoder, at base: Int, with codingPath: [CodingKey]) throws {
|
init(referringTo decoder: IntermediateDecoder, with codingPath: [CodingKey]) throws {
|
||||||
self.codingPath = codingPath
|
self.codingPath = codingPath
|
||||||
self.decoder = decoder
|
self.decoder = decoder
|
||||||
self.base = base
|
|
||||||
|
|
||||||
if decoder.dictionary.count == 0 {
|
var link = decoder.dictionary
|
||||||
let elementCount: Int
|
for x in codingPath {
|
||||||
switch decoder.storage[base] {
|
guard case let .dictionary(newLink) = link.storage[x.stringValue]! else {fatalError()}
|
||||||
case FormatID.fixMapRange:
|
link = newLink
|
||||||
elementCount = Int(decoder.storage[base] - FormatID.fixMap.rawValue)
|
|
||||||
self.base += 1
|
|
||||||
case FormatID.map16.rawValue:
|
|
||||||
elementCount = Int(decoder.storage.bigEndianInteger(at: base+1) as UInt16)
|
|
||||||
self.base += 3
|
|
||||||
case FormatID.map32.rawValue:
|
|
||||||
elementCount = Int(decoder.storage.bigEndianInteger(at: base+1) as UInt32)
|
|
||||||
self.base += 5
|
|
||||||
default:
|
|
||||||
throw DecodingError.typeMismatch(Dictionary<String,Any>.self, .init(codingPath: codingPath, debugDescription: "Expected a MsgPack map format, but found 0x\(String(decoder.storage[base], radix: 16))"))
|
|
||||||
}
|
}
|
||||||
for cursor in 0 ..< elementCount {
|
relativeDictionary = link
|
||||||
let key = try Format.string(from: &decoder.storage, base: &self.base)
|
var cursor = relativeDictionary.pointer
|
||||||
|
|
||||||
|
if relativeDictionary.storage.count == 0 {
|
||||||
|
let elementCount: Int
|
||||||
|
switch decoder.storage[cursor] {
|
||||||
|
case FormatID.fixMapRange:
|
||||||
|
elementCount = Int(decoder.storage[cursor] - FormatID.fixMap.rawValue)
|
||||||
|
cursor += 1
|
||||||
|
case FormatID.map16.rawValue:
|
||||||
|
elementCount = Int(decoder.storage.bigEndianInteger(at: cursor+1) as UInt16)
|
||||||
|
cursor += 3
|
||||||
|
case FormatID.map32.rawValue:
|
||||||
|
elementCount = Int(decoder.storage.bigEndianInteger(at: cursor+1) as UInt32)
|
||||||
|
cursor += 5
|
||||||
|
default:
|
||||||
|
throw DecodingError.typeMismatch(Dictionary<String,Any>.self, .init(codingPath: codingPath, debugDescription: "Expected a MsgPack map format, but found 0x\(String(decoder.storage[cursor], radix: 16))"))
|
||||||
|
}
|
||||||
|
for _ in 0 ..< elementCount {
|
||||||
|
let key = try Format.string(from: &decoder.storage, base: &cursor)
|
||||||
|
|
||||||
let valueFormat: FormatID
|
let valueFormat: FormatID
|
||||||
if let valueFormatLookup = FormatID(rawValue: decoder.storage[self.base]) {
|
if let valueFormatLookup = FormatID(rawValue: decoder.storage[cursor]) {
|
||||||
valueFormat = valueFormatLookup
|
valueFormat = valueFormatLookup
|
||||||
} else {
|
} else {
|
||||||
switch decoder.storage[self.base] {
|
switch decoder.storage[cursor] {
|
||||||
case FormatID.fixMapRange:
|
case FormatID.fixMapRange:
|
||||||
valueFormat = .fixMap
|
valueFormat = .fixMap
|
||||||
case FormatID.fixStringRange:
|
case FormatID.fixStringRange:
|
||||||
|
|
@ -210,55 +250,65 @@ struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtoco
|
||||||
case FormatID.negativeInt5Range:
|
case FormatID.negativeInt5Range:
|
||||||
valueFormat = .negativeInt5
|
valueFormat = .negativeInt5
|
||||||
default:
|
default:
|
||||||
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "Unknown format: 0x\(String(decoder.storage[self.base], radix: 16))"))
|
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "Unknown format: 0x\(String(decoder.storage[cursor], radix: 16))"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch valueFormat {
|
switch valueFormat {
|
||||||
case .nil, .false, .true:
|
case .nil, .false, .true:
|
||||||
decoder.dictionary[key] = .constant(valueFormat)
|
relativeDictionary.storage[key] = .constant(valueFormat)
|
||||||
self.base += 1
|
cursor += 1
|
||||||
case .positiveInt7, .negativeInt5:
|
case .positiveInt7, .negativeInt5:
|
||||||
decoder.dictionary[key] = .fixedWidth(valueFormat, pointer: self.base)
|
relativeDictionary.storage[key] = .fixedWidth(valueFormat, pointer: cursor)
|
||||||
self.base += 1
|
cursor += 1
|
||||||
case .uInt8, .int8, .string8:
|
case .uInt8, .int8, .string8:
|
||||||
decoder.dictionary[key] = .fixedWidth(valueFormat, pointer: self.base + 1)
|
relativeDictionary.storage[key] = .fixedWidth(valueFormat, pointer: cursor + 1)
|
||||||
self.base += 2
|
cursor += 2
|
||||||
case .uInt16, .int16:
|
case .uInt16, .int16:
|
||||||
decoder.dictionary[key] = .fixedWidth(valueFormat, pointer: self.base + 1)
|
relativeDictionary.storage[key] = .fixedWidth(valueFormat, pointer: cursor + 1)
|
||||||
self.base += 3
|
cursor += 3
|
||||||
case .uInt32, .int32, .float32:
|
case .uInt32, .int32, .float32:
|
||||||
decoder.dictionary[key] = .fixedWidth(valueFormat, pointer: self.base + 1)
|
relativeDictionary.storage[key] = .fixedWidth(valueFormat, pointer: cursor + 1)
|
||||||
self.base += 5
|
cursor += 5
|
||||||
case .uInt64, .int64, .float64:
|
case .uInt64, .int64, .float64:
|
||||||
decoder.dictionary[key] = .fixedWidth(valueFormat, pointer: self.base + 1)
|
relativeDictionary.storage[key] = .fixedWidth(valueFormat, pointer: cursor + 1)
|
||||||
self.base += 9
|
cursor += 9
|
||||||
case .fixArray, .fixMap, .fixString:
|
case .fixString:
|
||||||
let length = Int(decoder.storage[self.base] - valueFormat.rawValue)
|
let length = Int(decoder.storage[cursor] - valueFormat.rawValue)
|
||||||
self.base += 1
|
cursor += 1
|
||||||
decoder.dictionary[key] = .variableWidth(valueFormat, pointer: self.base, length: length)
|
relativeDictionary.storage[key] = .variableWidth(valueFormat, pointer: cursor, length: length)
|
||||||
self.base += length
|
cursor += length
|
||||||
case .array16, .map16, .string16:
|
case .string16:
|
||||||
let length = Int(decoder.storage.bigEndianInteger(at: self.base + 1) as UInt16)
|
let length = Int(decoder.storage.bigEndianInteger(at: cursor + 1) as UInt16)
|
||||||
self.base += 3
|
cursor += 3
|
||||||
decoder.dictionary[key] = .variableWidth(valueFormat, pointer: self.base, length: length)
|
relativeDictionary.storage[key] = .variableWidth(valueFormat, pointer: cursor, length: length)
|
||||||
self.base += length
|
cursor += length
|
||||||
case .string32, .array32, .map32:
|
case .string32:
|
||||||
let length = Int(decoder.storage.bigEndianInteger(at: self.base + 1) as UInt16)
|
let length = Int(decoder.storage.bigEndianInteger(at: cursor + 1) as UInt16)
|
||||||
self.base += 5
|
cursor += 5
|
||||||
decoder.dictionary[key] = .variableWidth(valueFormat, pointer: self.base, length: length)
|
relativeDictionary.storage[key] = .variableWidth(valueFormat, pointer: cursor, length: length)
|
||||||
self.base += length
|
cursor += length
|
||||||
|
case .fixArray, .array16, .array32:
|
||||||
|
let length = Int(decoder.storage[cursor] - valueFormat.rawValue)
|
||||||
|
cursor += 1
|
||||||
|
fatalError("not implemented")
|
||||||
|
case .fixMap, .map16, .map32:
|
||||||
|
let partial = PartiallyDecodedDictionary(pointer: cursor)
|
||||||
|
relativeDictionary.storage[key] = .dictionary(partial)
|
||||||
|
try MsgPckKeyedDecodingContainer(referringTo: decoder, with: codingPath + [TemporaryCodingKey(stringValue: key)!])
|
||||||
|
cursor += partial.byteCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
relativeDictionary.byteCount = cursor - relativeDictionary.pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(_ key: K) -> Bool {
|
func contains(_ key: K) -> Bool {
|
||||||
return decoder.dictionary[key.stringValue] != nil
|
return relativeDictionary.storage[key.stringValue] != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeNil(forKey key: K) throws -> Bool {
|
func decodeNil(forKey key: K) throws -> Bool {
|
||||||
switch decoder.dictionary[key.stringValue]! {
|
switch relativeDictionary.storage[key.stringValue]! {
|
||||||
case .constant(let format):
|
case .constant(let format):
|
||||||
return format == .nil
|
return format == .nil
|
||||||
default:
|
default:
|
||||||
|
|
@ -267,8 +317,8 @@ struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtoco
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode(_ type: Bool.Type, forKey key: K) throws -> Bool {
|
func decode(_ type: Bool.Type, forKey key: K) throws -> Bool {
|
||||||
guard let value = decoder.dictionary[key.stringValue] else {
|
guard let value = relativeDictionary.storage[key.stringValue] else {
|
||||||
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found"))
|
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found: \(key.stringValue)"))
|
||||||
}
|
}
|
||||||
guard case let .constant(format) = value else {
|
guard case let .constant(format) = value else {
|
||||||
throw DecodingError.typeMismatch(type, .init(codingPath: codingPath, debugDescription: "Expected bool but found \(value)"))
|
throw DecodingError.typeMismatch(type, .init(codingPath: codingPath, debugDescription: "Expected bool but found \(value)"))
|
||||||
|
|
@ -282,8 +332,8 @@ struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtoco
|
||||||
}
|
}
|
||||||
|
|
||||||
func formattedPointer<T>(for key: K, format expectedFormat: FormatID, type: T.Type) throws -> Int {
|
func formattedPointer<T>(for key: K, format expectedFormat: FormatID, type: T.Type) throws -> Int {
|
||||||
guard let value = decoder.dictionary[key.stringValue] else {
|
guard let value = relativeDictionary.storage[key.stringValue] else {
|
||||||
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found"))
|
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found: \(key.stringValue)"))
|
||||||
}
|
}
|
||||||
guard case let .fixedWidth(format, pointer) = value else {
|
guard case let .fixedWidth(format, pointer) = value else {
|
||||||
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Expected fixed width value but found \(value)")
|
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Expected fixed width value but found \(value)")
|
||||||
|
|
@ -345,11 +395,11 @@ struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtoco
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode(_ type: String.Type, forKey key: K) throws -> String {
|
func decode(_ type: String.Type, forKey key: K) throws -> String {
|
||||||
guard let value = decoder.dictionary[key.stringValue] else {
|
guard let value = relativeDictionary.storage[key.stringValue] else {
|
||||||
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found"))
|
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found: \(key.stringValue)"))
|
||||||
}
|
}
|
||||||
guard case let .variableWidth(format, base, length) = value else {
|
guard case let .variableWidth(format, base, length) = value else {
|
||||||
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Expected fixed width value but found \(value)")
|
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Expected variable width value but found \(value)")
|
||||||
}
|
}
|
||||||
guard [.string8, .string16, .string32, .fixString].contains(format) else {
|
guard [.string8, .string16, .string32, .fixString].contains(format) else {
|
||||||
throw DecodingError.typeMismatch(type, .init(codingPath: codingPath, debugDescription: "Expected a string but found \(format)"))
|
throw DecodingError.typeMismatch(type, .init(codingPath: codingPath, debugDescription: "Expected a string but found \(format)"))
|
||||||
|
|
@ -363,7 +413,25 @@ struct MsgPckKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtoco
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable {
|
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable {
|
||||||
|
guard let value = relativeDictionary.storage[key.stringValue] else {
|
||||||
|
throw DecodingError.keyNotFound(key, .init(codingPath: codingPath, debugDescription: "Key not found: \(key.stringValue)"))
|
||||||
|
}
|
||||||
|
let sliceDecoder: IntermediateDecoder
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
case .constant(let format):
|
||||||
|
sliceDecoder = IntermediateDecoder(with: Data([format.rawValue]))
|
||||||
|
case let .fixedWidth(format, pointer):
|
||||||
|
sliceDecoder = IntermediateDecoder(withUnsafeDataFrom: decoder, start: pointer - format.length)
|
||||||
|
case let .variableWidth(format, pointer, length):
|
||||||
|
sliceDecoder = IntermediateDecoder(withUnsafeDataFrom: decoder, start: pointer - format.length, length: length + format.length)
|
||||||
|
case .array(_):
|
||||||
fatalError("not implemented")
|
fatalError("not implemented")
|
||||||
|
case let .dictionary(reference):
|
||||||
|
sliceDecoder = IntermediateDecoder(withUnsafeDataFrom: decoder, start: reference.pointer, length: reference.byteCount)
|
||||||
|
}
|
||||||
|
sliceDecoder.codingPath = codingPath + [key]
|
||||||
|
return try T(from: sliceDecoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
||||||
|
|
|
||||||
|
|
@ -266,10 +266,9 @@ class MsgPackKeyedEncodingContainer<K: CodingKey>: MessagePackEncodingContainer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KeyedStorageContainer {
|
class KeyedStorageContainer: Reference<[String: MessagePackEncodingContainer]> {
|
||||||
var storage: [String: MessagePackEncodingContainer]
|
init() {
|
||||||
init(storage: [String:MessagePackEncodingContainer] = [:]) {
|
super.init(to: [:])
|
||||||
self.storage = storage
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,62 @@ public enum FormatID: UInt8 {
|
||||||
static let fixMapRange = FormatID.fixMap.rawValue ..< FormatID.fixArray.rawValue
|
static let fixMapRange = FormatID.fixMap.rawValue ..< FormatID.fixArray.rawValue
|
||||||
static let fixArrayRange = FormatID.fixArray.rawValue ..< FormatID.fixString.rawValue
|
static let fixArrayRange = FormatID.fixArray.rawValue ..< FormatID.fixString.rawValue
|
||||||
static let fixStringRange = FormatID.fixString.rawValue ..< FormatID.nil.rawValue
|
static let fixStringRange = FormatID.fixString.rawValue ..< FormatID.nil.rawValue
|
||||||
|
|
||||||
|
var length: Int {
|
||||||
|
switch self {
|
||||||
|
|
||||||
|
case .nil:
|
||||||
|
return 0
|
||||||
|
case .false:
|
||||||
|
return 0
|
||||||
|
case .true:
|
||||||
|
return 0
|
||||||
|
case .float32:
|
||||||
|
return 1
|
||||||
|
case .float64:
|
||||||
|
return 1
|
||||||
|
case .positiveInt7:
|
||||||
|
return 0
|
||||||
|
case .negativeInt5:
|
||||||
|
return 0
|
||||||
|
case .uInt8:
|
||||||
|
return 1
|
||||||
|
case .uInt16:
|
||||||
|
return 1
|
||||||
|
case .uInt32:
|
||||||
|
return 1
|
||||||
|
case .uInt64:
|
||||||
|
return 1
|
||||||
|
case .int8:
|
||||||
|
return 1
|
||||||
|
case .int16:
|
||||||
|
return 1
|
||||||
|
case .int32:
|
||||||
|
return 1
|
||||||
|
case .int64:
|
||||||
|
return 1
|
||||||
|
case .fixString:
|
||||||
|
return 1
|
||||||
|
case .string8:
|
||||||
|
return 2
|
||||||
|
case .string16:
|
||||||
|
return 3
|
||||||
|
case .string32:
|
||||||
|
return 5
|
||||||
|
case .fixArray:
|
||||||
|
return 1
|
||||||
|
case .array16:
|
||||||
|
return 3
|
||||||
|
case .array32:
|
||||||
|
return 5
|
||||||
|
case .fixMap:
|
||||||
|
return 1
|
||||||
|
case .map16:
|
||||||
|
return 3
|
||||||
|
case .map32:
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Format {
|
extension Format {
|
||||||
|
|
|
||||||
16
MsgPack/Reference.swift
Normal file
16
MsgPack/Reference.swift
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
//
|
||||||
|
// Reference.swift
|
||||||
|
// MsgPack
|
||||||
|
//
|
||||||
|
// Created by Damiaan on 3/08/17.
|
||||||
|
// Copyright © 2017 dPro. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class Reference<T> {
|
||||||
|
var storage: T
|
||||||
|
init(to value: T) {
|
||||||
|
storage = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -110,22 +110,36 @@ class MsgPackTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Simple: Codable {
|
struct Graph: Codable {
|
||||||
let a: Bool
|
let title: String
|
||||||
let b: Bool
|
let circles: Circle
|
||||||
let c: Bool?
|
|
||||||
let d: Bool?
|
|
||||||
let e: Bool?
|
|
||||||
let f: Int8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Circle: Codable {
|
||||||
|
let radius: UInt64
|
||||||
|
let center: Position
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Position: Codable {
|
||||||
|
let x: Int8
|
||||||
|
let y: Int8
|
||||||
|
}
|
||||||
|
|
||||||
|
let graph = Graph(
|
||||||
|
title: "My graph",
|
||||||
|
circles: Circle(
|
||||||
|
radius: 0x0102030405060708,
|
||||||
|
center: Position(x: -123, y: 2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
func roundtrip<T: Codable>(value: T) throws -> T {
|
func roundtrip<T: Codable>(value: T) throws -> T {
|
||||||
return try decoder.decode(T.self, from: encoder.encode(value))
|
return try decoder.decode(T.self, from: encoder.encode(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testExample() {
|
func testExample() {
|
||||||
do {
|
do {
|
||||||
print("roundtrip:", try roundtrip(value: Simple(a: true, b: false, c: true, d: false, e: nil, f: -8)))
|
print("roundtrip:", try roundtrip(value: graph))
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,33 +4,34 @@ import MsgPack
|
||||||
|
|
||||||
let encoder = Encoder()
|
let encoder = Encoder()
|
||||||
|
|
||||||
struct Graph: Encodable {
|
struct Graph: Codable {
|
||||||
let title: String
|
let title: String
|
||||||
let circles: [Circle]
|
let circles: Circle
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Circle: Encodable {
|
struct Circle: Codable {
|
||||||
let radius: UInt
|
let radius: UInt64
|
||||||
let center: Position
|
let center: Position
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Position: Encodable {
|
struct Position: Codable {
|
||||||
let x: Int8
|
let x: Int8
|
||||||
let y: Int8
|
let y: Int8
|
||||||
}
|
}
|
||||||
|
|
||||||
let graph = Graph(
|
let graph = Graph(
|
||||||
title: "My graph",
|
title: "My graph",
|
||||||
circles: [
|
circles:
|
||||||
Circle(
|
Circle(
|
||||||
radius: 0x0102030405060708,
|
radius: 0x0102030405060708,
|
||||||
center: Position(x: -123, y: 2)
|
center: Position(x: -123, y: 2)
|
||||||
),
|
|
||||||
Circle(
|
|
||||||
radius: 1000,
|
|
||||||
center: Position(x: 116, y: 81)
|
|
||||||
)
|
)
|
||||||
]
|
// ,
|
||||||
|
// Circle(
|
||||||
|
// radius: 1000,
|
||||||
|
// center: Position(x: 116, y: 81)
|
||||||
|
// )
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try encoder.encode(graph)
|
try encoder.encode(graph)
|
||||||
|
|
@ -52,4 +53,9 @@ struct Simple: Codable {
|
||||||
|
|
||||||
try roundtrip(value: -56.4)
|
try roundtrip(value: -56.4)
|
||||||
try roundtrip(value: "Hello world 😎")
|
try roundtrip(value: "Hello world 😎")
|
||||||
try roundtrip(value: Simple(a: true, b: false, c: true, d: false, e: nil, f: "😜"))
|
do {
|
||||||
|
try roundtrip(value: graph)
|
||||||
|
} catch {
|
||||||
|
error
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue