diff --git a/MsgPack/Decoder.swift b/MsgPack/Decoder.swift index 2dba09c..68fa402 100644 --- a/MsgPack/Decoder.swift +++ b/MsgPack/Decoder.swift @@ -148,10 +148,103 @@ struct MsgPckSingleValueDecodingContainer: SingleValueDecodingContainer { } func decode(_ type: String.Type) throws -> String { - fatalError("not implemented") + return try Format.string(from: &decoder.storage) } func decode(_ type: T.Type) throws -> T where T : Decodable { fatalError("not implemented") } } + +struct MsgPckKeyedDecodingContainer: KeyedDecodingContainerProtocol { + var codingPath: [CodingKey] + + var allKeys: [K] + + func contains(_ key: K) -> Bool { + fatalError("not implemented") + } + + func decodeNil(forKey key: K) throws -> Bool { + fatalError("not implemented") + } + + func decode(_ type: Bool.Type, forKey key: K) throws -> Bool { + fatalError("not implemented") + } + + func decode(_ type: Int.Type, forKey key: K) throws -> Int { + fatalError("not implemented") + } + + func decode(_ type: Int8.Type, forKey key: K) throws -> Int8 { + fatalError("not implemented") + } + + func decode(_ type: Int16.Type, forKey key: K) throws -> Int16 { + fatalError("not implemented") + } + + func decode(_ type: Int32.Type, forKey key: K) throws -> Int32 { + fatalError("not implemented") + } + + func decode(_ type: Int64.Type, forKey key: K) throws -> Int64 { + fatalError("not implemented") + } + + func decode(_ type: UInt.Type, forKey key: K) throws -> UInt { + fatalError("not implemented") + } + + func decode(_ type: UInt8.Type, forKey key: K) throws -> UInt8 { + fatalError("not implemented") + } + + func decode(_ type: UInt16.Type, forKey key: K) throws -> UInt16 { + fatalError("not implemented") + } + + func decode(_ type: UInt32.Type, forKey key: K) throws -> UInt32 { + fatalError("not implemented") + } + + func decode(_ type: UInt64.Type, forKey key: K) throws -> UInt64 { + fatalError("not implemented") + } + + func decode(_ type: Float.Type, forKey key: K) throws -> Float { + fatalError("not implemented") + } + + func decode(_ type: Double.Type, forKey key: K) throws -> Double { + fatalError("not implemented") + } + + func decode(_ type: String.Type, forKey key: K) throws -> String { + fatalError("not implemented") + } + + func decode(_ type: T.Type, forKey key: K) throws -> T where T : Decodable { + fatalError("not implemented") + } + + func nestedContainer(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer where NestedKey : CodingKey { + fatalError("not implemented") + } + + func nestedUnkeyedContainer(forKey key: K) throws -> UnkeyedDecodingContainer { + fatalError("not implemented") + } + + func superDecoder() throws -> Swift.Decoder { + fatalError("not implemented") + } + + func superDecoder(forKey key: K) throws -> Swift.Decoder { + fatalError("not implemented") + } + + typealias Key = K + +} diff --git a/MsgPack/Encoder.swift b/MsgPack/Encoder.swift index 8c0355f..4419d26 100644 --- a/MsgPack/Encoder.swift +++ b/MsgPack/Encoder.swift @@ -22,7 +22,7 @@ public class Encoder { } enum MsgPackEncodingError: Swift.Error { - case notImplemented, stringNotConvertibleToUTF8(String), valueDidNotAskForContainer + case stringNotConvertibleToUTF8(String), valueDidNotAskForContainer } class IntermediateEncoder: Swift.Encoder { @@ -159,7 +159,7 @@ class MsgPackSingleValueEncodingContainer: MessagePackEncodingContainer, SingleV } func encode(_ value: T) throws { - throw MsgPackEncodingError.notImplemented + fatalError("Not implemented") } } @@ -262,7 +262,7 @@ class MsgPackKeyedEncodingContainer: MessagePackEncodingContainer, } func superEncoder(forKey key: K) -> Swift.Encoder { - preconditionFailure("not implemented") + fatalError("not implemented") } } diff --git a/MsgPack/Format.swift b/MsgPack/Format.swift index 81fadcd..c5df725 100644 --- a/MsgPack/Format.swift +++ b/MsgPack/Format.swift @@ -63,9 +63,12 @@ public enum FormatID: UInt8 { case float32 case float64 - case positiveInt7 = 0 - case negativeInt5 = 0b11100000 + case firstPositiveInt7 = 0b00000000 + case lastPositiveInt7 = 0b01111111 + case firstNegativeInt5 = 0b11100000 + case lastNegativeInt5 = 0b11111111 + case uInt8 = 0xCC case uInt16 case uInt32 @@ -82,16 +85,19 @@ public enum FormatID: UInt8 { case fixExt8 case fixExt16 - case fixString = 0b10100000 + case fixStringStart = 0b10100000 + case fixStringEnd = 0b10111111 case string8 = 0xD9 case string16 case string32 - case fixArray = 0b10010000 + case fixArrayStart = 0b10010000 + case fixArrayEnd = 0b10011111 case array16 = 0xDC case array32 - case fixMap = 0b10000000 + case fixMapStart = 0b10000000 + case fixMapEnd = 0b10001111 case map16 = 0xDE case map32 } @@ -110,9 +116,9 @@ extension Format { // MARK: Small integers (< 8 bit) case .positiveInt7(let value): - data.append(value | FormatID.positiveInt7.rawValue) + data.append(value | FormatID.firstPositiveInt7.rawValue) case .negativeInt5(let value): - data.append(value | FormatID.negativeInt5.rawValue) + data.append(value | FormatID.firstNegativeInt5.rawValue) // MARK: Unsigned integers case .uInt8(let value): @@ -173,7 +179,7 @@ extension Format { // MARK: Strings case .fixString(let utf8Data): precondition(utf8Data.count < 32, "fix strings cannot contain more than 31 bytes") - data.append( UInt8(utf8Data.count) | FormatID.fixString.rawValue) + data.append( UInt8(utf8Data.count) | FormatID.fixStringStart.rawValue) data.append(utf8Data) case .string8(let utf8Data): data.append(contentsOf: [FormatID.string8.rawValue, UInt8(utf8Data.count)]) @@ -194,7 +200,7 @@ 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) | FormatID.fixArray.rawValue) + data.append( UInt8(array.count) | FormatID.fixArrayStart.rawValue) for element in array { element.appendTo(data: &data) } @@ -218,7 +224,7 @@ 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) | FormatID.fixMap.rawValue) + data.append( UInt8(pairs.count) | FormatID.fixMapStart.rawValue) for (key, value) in pairs { key.appendTo(data: &data) value.appendTo(data: &data) @@ -321,3 +327,44 @@ extension Format { #endif } } + +extension Format { + static func string(from data: inout Data, offset: Int = 0) throws -> String { + switch data[offset] { + case FormatID.fixStringStart.rawValue ... FormatID.fixStringEnd.rawValue: + let length = Int(data[offset] & 0b00011111) + guard let string = data.withUnsafeMutableBytes({ + String(bytesNoCopy: $0.advanced(by: offset + 1), length: length, encoding: .utf8, freeWhenDone: false) + }) else { + throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "not a valid string")) + } + return string + case FormatID.string8.rawValue: + let length = Int(data[offset + 1]) + guard let string = data.withUnsafeMutableBytes({ + String(bytesNoCopy: $0.advanced(by: offset + 2), length: length, encoding: .utf8, freeWhenDone: false) + }) else { + throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "not a valid string")) + } + return string + case FormatID.string16.rawValue: + let length = Int(data.bigEndianInteger(at: offset) as UInt16) + guard let string = data.withUnsafeMutableBytes({ + String(bytesNoCopy: $0.advanced(by: offset + 3), length: length, encoding: .utf8, freeWhenDone: false) + }) else { + throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "not a valid string")) + } + return string + case FormatID.string32.rawValue: + let length = Int(data.bigEndianInteger(at: offset) as UInt16) + guard let string = data.withUnsafeMutableBytes({ + String(bytesNoCopy: $0.advanced(by: offset + 5), length: length, encoding: .utf8, freeWhenDone: false) + }) else { + throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "not a valid string")) + } + return string + default: + throw DecodingError.typeMismatch(String.self, .init(codingPath: [], debugDescription: "Wrong string format: \(data[offset])")) + } + } +} diff --git a/Playground.playground/Contents.swift b/Playground.playground/Contents.swift index bef399e..697d4c0 100644 --- a/Playground.playground/Contents.swift +++ b/Playground.playground/Contents.swift @@ -44,5 +44,4 @@ func roundtrip(value: T) throws -> T { return try decoder.decode(T.self, from: encoder.encode(value)) } -var x: UInt64? = nil -try roundtrip(value: false) +try roundtrip(value: "Hello")