diff --git a/MsgPack/Encoder.swift b/MsgPack/Encoder.swift index 70323a1..03ba128 100644 --- a/MsgPack/Encoder.swift +++ b/MsgPack/Encoder.swift @@ -35,7 +35,9 @@ class IntermediateEncoder: Swift.Encoder { } func unkeyedContainer() -> UnkeyedEncodingContainer { - preconditionFailure() + let unkeyedContainer = MsgPackUnkeyedEncodingContainer() + container = unkeyedContainer + return unkeyedContainer } func singleValueContainer() -> SingleValueEncodingContainer { @@ -71,6 +73,17 @@ extension Format { } } + static func from(array: [Format]) -> Format { + switch array.count { + case 1..<16: + return .fixArray(array) + case 16..<65536: + return .array16(array) + default: + return .array32(array) + } + } + static func from(int: Int) -> Format { #if arch(arm) || arch(i386) return .int32(Int32(int)) @@ -88,12 +101,34 @@ extension Format { } } -class MessagePackEncodingContainer { +class MessagePackEncodingContainer: Swift.Encoder { + var userInfo = [CodingUserInfoKey : Any]() var codingPath: [CodingKey] = [] + var temporaryContainer: MessagePackEncodingContainer? + func getFormat() throws -> Format { - preconditionFailure() + fatalError("subclasses should implement this method") } + + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { + let keyedContainer = MsgPackKeyedEncodingContainer() + temporaryContainer = keyedContainer + return KeyedEncodingContainer(keyedContainer) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + let unkeyedContainer = MsgPackUnkeyedEncodingContainer() + temporaryContainer = unkeyedContainer + return unkeyedContainer + } + + func singleValueContainer() -> SingleValueEncodingContainer { + let singleValueContainer = MsgPackSingleValueEncodingContainer() + temporaryContainer = singleValueContainer + return singleValueContainer + } + } enum MsgPackEncodingError: Swift.Error { @@ -183,75 +218,77 @@ class MsgPackSingleValueEncodingContainer: MessagePackEncodingContainer, SingleV } class MsgPackKeyedEncodingContainer: MessagePackEncodingContainer, KeyedEncodingContainerProtocol { - var userInfo = [CodingUserInfoKey : Any]() - - var storage = [String: MessagePackEncodingContainer]() - var temporaryContainer: MessagePackEncodingContainer? + + let storageReference: KeyedStorageContainer + + init(storage: KeyedStorageContainer = KeyedStorageContainer()) { + storageReference = storage + } override func getFormat() throws -> Format { - return try Format.from(keyValuePairs: storage.map { + return try Format.from(keyValuePairs: storageReference.storage.map { (try Format.from(string: $0.key), try $0.value.getFormat()) }) } func encodeNil(forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .nil) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .nil) } func encode(_ value: Bool, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .boolean(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .boolean(value) ) } func encode(_ value: Int, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .from(int: value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .from(int: value) ) } func encode(_ value: Int8, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int8(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int8(value) ) } func encode(_ value: Int16, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int16(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int16(value) ) } func encode(_ value: Int32, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int32(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int32(value) ) } func encode(_ value: Int64, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int64(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .int64(value) ) } func encode(_ value: UInt, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .from(uInt: value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .from(uInt: value) ) } func encode(_ value: UInt8, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt8(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt8(value) ) } func encode(_ value: UInt16, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt16(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt16(value) ) } func encode(_ value: UInt32, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt32(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt32(value) ) } func encode(_ value: UInt64, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt64(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .uInt64(value) ) } func encode(_ value: Float, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .float32(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .float32(value) ) } func encode(_ value: Double, forKey key: K) throws { - storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .float64(value) ) + storageReference.storage[key.stringValue] = MsgPackSingleValueEncodingContainer(with: .float64(value) ) } func encode(_ value: String, forKey key: K) throws { - storage[key.stringValue] = try MsgPackSingleValueEncodingContainer(with: .from(string: value) ) + storageReference.storage[key.stringValue] = try MsgPackSingleValueEncodingContainer(with: .from(string: value) ) } func encode(_ value: T, forKey key: K) throws where T : Encodable { @@ -259,21 +296,23 @@ class MsgPackKeyedEncodingContainer: MessagePackEncodingContainer, guard let container = temporaryContainer else { throw MsgPackEncodingError.valueDidNotAskForContainer } - storage[key.stringValue] = container + storageReference.storage[key.stringValue] = container } func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: K) -> KeyedEncodingContainer where NestedKey : CodingKey { let keyedContainer = MsgPackKeyedEncodingContainer() - storage[key.stringValue] = keyedContainer + storageReference.storage[key.stringValue] = keyedContainer return KeyedEncodingContainer(keyedContainer) } func nestedUnkeyedContainer(forKey key: K) -> UnkeyedEncodingContainer { - preconditionFailure("not implemented") + let unkeyedContainer = MsgPackUnkeyedEncodingContainer() + storageReference.storage[key.stringValue] = unkeyedContainer + return unkeyedContainer } func superEncoder() -> Swift.Encoder { - preconditionFailure("not implemented") + return KeyedEncoder(referencing: storageReference) } func superEncoder(forKey key: K) -> Swift.Encoder { @@ -281,20 +320,155 @@ class MsgPackKeyedEncodingContainer: MessagePackEncodingContainer, } } -extension MsgPackKeyedEncodingContainer: Swift.Encoder { +class KeyedStorageContainer { + var storage: [String: MessagePackEncodingContainer] + init(storage: [String:MessagePackEncodingContainer] = [:]) { + self.storage = storage + } +} + +class KeyedEncoder: Swift.Encoder { + var codingPath = [CodingKey]() + + var userInfo = [CodingUserInfoKey : Any]() + + let storageReference: KeyedStorageContainer + + init(referencing storage: KeyedStorageContainer) { + storageReference = storage + } + + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { + return KeyedEncodingContainer(MsgPackKeyedEncodingContainer()) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + preconditionFailure("impossible to give an unkeyed container") + } + + func singleValueContainer() -> SingleValueEncodingContainer { + preconditionFailure("impossible to give a single value container") + } +} + +class MsgPackUnkeyedEncodingContainer: MessagePackEncodingContainer, UnkeyedEncodingContainer { + var count: Int { return storage.count } + + var storage = [MessagePackEncodingContainer]() + + override func getFormat() throws -> Format { + return try .from(array: storage.map {try $0.getFormat()} ) + } + + func encodeNil() throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .nil)) + } + + func encode(_ value: Bool) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .boolean(value))) + } + + func encode(_ value: Int) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .from(int: value))) + } + + func encode(_ value: Int8) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .int8(value))) + } + + func encode(_ value: Int16) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .int16(value))) + } + + func encode(_ value: Int32) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .int32(value))) + } + + func encode(_ value: Int64) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .int64(value))) + } + + func encode(_ value: UInt) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .from(uInt: value))) + } + + func encode(_ value: UInt8) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .uInt8(value))) + } + + func encode(_ value: UInt16) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .uInt16(value))) + } + + func encode(_ value: UInt32) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .uInt32(value))) + } + + func encode(_ value: UInt64) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .uInt64(value))) + } + + func encode(_ value: Float) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .float32(value))) + } + + func encode(_ value: Double) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: .float64(value))) + } + + func encode(_ value: String) throws { + storage.append(MsgPackSingleValueEncodingContainer(with: try .from(string: value))) + } + + func encode(_ value: T) throws { + try value.encode(to: self) + guard let container = temporaryContainer else { throw MsgPackEncodingError.valueDidNotAskForContainer } + storage.append(container) + } + + func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey : CodingKey { + let container = MsgPackKeyedEncodingContainer() + storage.append(container) + return KeyedEncodingContainer(container) + } + + func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + let container = MsgPackUnkeyedEncodingContainer() + storage.append(container) + return container + } + + func superEncoder() -> Swift.Encoder { + return UnkeyedEncoder(referencing: self) + } +} + +class UnkeyedEncoder: Swift.Encoder { + var codingPath = [CodingKey]() + + var userInfo = [CodingUserInfoKey : Any]() + + let container: MsgPackUnkeyedEncodingContainer + + init(referencing container: MsgPackUnkeyedEncodingContainer) { + self.container = container + } + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { let keyedContainer = MsgPackKeyedEncodingContainer() - temporaryContainer = keyedContainer + container.storage.append(keyedContainer) return KeyedEncodingContainer(keyedContainer) } func unkeyedContainer() -> UnkeyedEncodingContainer { - preconditionFailure() + let unkeyedContainer = MsgPackUnkeyedEncodingContainer() + container.storage.append(unkeyedContainer) + return unkeyedContainer } func singleValueContainer() -> SingleValueEncodingContainer { let singleValueContainer = MsgPackSingleValueEncodingContainer() - temporaryContainer = singleValueContainer + container.storage.append(singleValueContainer) return singleValueContainer } } diff --git a/MsgPackTests/MsgPackTests.swift b/MsgPackTests/MsgPackTests.swift index c68a612..af1de1b 100644 --- a/MsgPackTests/MsgPackTests.swift +++ b/MsgPackTests/MsgPackTests.swift @@ -108,26 +108,12 @@ class MsgPackTests: XCTestCase { } } -// var encoder = MsgPack.JSONEncoder2() -// -// struct Obj: Encodable { -// let i: Int -// let p: Person -// } -// -// struct Person: Encodable { -// let name: String -// let friend: Friend -// } -// -// struct Friend: Encodable { -// let count: Double -// } -// -// func testDinges() { -// try! encoder.encode( -// Obj(i: 3, p: Person(name: "Dinges", friend: Friend(count: 8))) -// ) -// } + func testExample() { + do { + print(try encoder.encode([[Int8(-3)], [5], [8]])) + } catch { + print(error) + } + } } diff --git a/Playground.playground/Contents.swift b/Playground.playground/Contents.swift index 29663bf..22cffcc 100644 --- a/Playground.playground/Contents.swift +++ b/Playground.playground/Contents.swift @@ -5,23 +5,36 @@ import Foundation let encoder = Encoder() -try encoder.encode(0x0102030405060708) +struct Graph: Encodable { + let title: String + let circles: [Circle] +} -try encoder.encode("Hello") - -try encoder.encode("😇") - -var n: Int? -try encoder.encode(n) +struct Circle: Encodable { + let radius: UInt + let center: Position +} struct Position: Encodable { let x: Int8 let y: Int8 } -struct Circle: Encodable { - let center: Position - let radius: UInt -} +let graph = Graph( + title: "My graph", + circles: [ + Circle( + radius: 0x0102030405060708, + center: Position(x: -123, y: 2) + ), + Circle( + radius: 1000, + center: Position(x: 116, y: 81) + ) + ] +) -try encoder.encode(Circle(center: Position(x: -1, y: 2), radius: 67)) +let encodedGraph = try encoder.encode(graph) +for byte in encodedGraph { + print(String(byte, radix:16)) +}