Decode string

This commit is contained in:
Damiaan Dufaux 2017-08-02 23:27:37 +02:00
parent 101abe3e46
commit aca03f1952
4 changed files with 155 additions and 16 deletions

View file

@ -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<T>(_ type: T.Type) throws -> T where T : Decodable {
fatalError("not implemented")
}
}
struct MsgPckKeyedDecodingContainer<K: CodingKey>: 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<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable {
fatalError("not implemented")
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> 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
}

View file

@ -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<T : Encodable>(_ value: T) throws {
throw MsgPackEncodingError.notImplemented
fatalError("Not implemented")
}
}
@ -262,7 +262,7 @@ class MsgPackKeyedEncodingContainer<K: CodingKey>: MessagePackEncodingContainer,
}
func superEncoder(forKey key: K) -> Swift.Encoder {
preconditionFailure("not implemented")
fatalError("not implemented")
}
}

View file

@ -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])"))
}
}
}

View file

@ -44,5 +44,4 @@ func roundtrip<T: Codable>(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")