├── .gitignore ├── .github └── FUNDING.yml ├── Tests ├── LinuxMain.swift ├── Shared Sources │ └── Airport.swift └── MessagePackTests │ ├── ___RoundTripTests.swift │ ├── ___EncodingTests.swift │ └── ___DecodingTests.swift ├── LICENSE.md ├── Sources ├── Encoder │ ├── UnkeyedEncodingContainer.swift │ ├── KeyedEncodingContainer.swift │ ├── ___Encoder.swift │ └── SingleValueEncodingContainer.swift └── Decoder │ ├── UnkeyedDecodingContainer.swift │ ├── KeyedDecodingContainer.swift │ ├── ___Decoder.swift │ └── SingleValueDecodingContainer.swift ├── Package.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [mattt] 2 | custom: https://flight.school/books/codable 3 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import <#Format#>Tests 3 | 4 | XCTMain([ 5 | testCase(<#Format#>Tests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Tests/Shared Sources/Airport.swift: -------------------------------------------------------------------------------- 1 | struct Airport: Codable, Equatable { 2 | let name: String 3 | let iata: String 4 | let icao: String 5 | let coordinates: [Double] 6 | 7 | struct Runway: Codable, Equatable { 8 | enum Surface: String, Codable, Equatable { 9 | case rigid, flexible, gravel, sealed, unpaved, other 10 | } 11 | 12 | let direction: String 13 | let distance: Int 14 | let surface: Surface 15 | } 16 | 17 | let runways: [Runway] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2018 Read Evaluate Press, LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Sources/Encoder/UnkeyedEncodingContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension _<#Format#>Encoder { 4 | final class UnkeyedContainer { 5 | var codingPath: [CodingKey] 6 | var userInfo: [CodingUserInfoKey: Any] 7 | 8 | init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { 9 | self.codingPath = codingPath 10 | self.userInfo = userInfo 11 | } 12 | } 13 | } 14 | 15 | extension _<#Format#>Encoder.UnkeyedContainer: UnkeyedEncodingContainer { 16 | func encodeNil() throws { 17 | <#Implementation#> 18 | } 19 | 20 | func encode(_ value: T) throws where T : Encodable { 21 | <#Implementation#> 22 | } 23 | 24 | func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey : CodingKey { 25 | <#Implementation#> 26 | } 27 | 28 | func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { 29 | <#Implementation#> 30 | } 31 | 32 | func superEncoder() -> Encoder { 33 | <#Implementation#> 34 | } 35 | } 36 | 37 | extension _<#Format#>Encoder.UnkeyedContainer: <#Format#>EncodingContainer {} 38 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "<#Format#>", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "<#Format#>", 12 | targets: ["<#Format#>"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 21 | .target( 22 | name: "<#Format#>", 23 | dependencies: [], 24 | path: "Sources" 25 | ), 26 | .testTarget( 27 | name: "<#Format#>Tests", 28 | dependencies: ["<#Format#>"], 29 | path: "Tests" 30 | ), 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /Sources/Decoder/UnkeyedDecodingContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension _<#Format#>Decoder { 4 | final class UnkeyedContainer { 5 | var codingPath: [CodingKey] 6 | var userInfo: [CodingUserInfoKey: Any] 7 | 8 | init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { 9 | self.codingPath = codingPath 10 | self.userInfo = userInfo 11 | } 12 | } 13 | } 14 | 15 | extension _<#Format#>Decoder.UnkeyedContainer: UnkeyedDecodingContainer { 16 | func decodeNil() throws -> Bool { 17 | <#Implementation#> 18 | } 19 | 20 | func decode(_ type: T.Type) throws -> T where T : Decodable { 21 | <#Implementation#> 22 | } 23 | 24 | func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { 25 | <#Implementation#> 26 | } 27 | 28 | func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer where NestedKey : CodingKey { 29 | <#Implementation#> 30 | } 31 | 32 | func superDecoder() throws -> Decoder { 33 | <#Implementation#> 34 | } 35 | } 36 | 37 | extension _<#Format#>Decoder.UnkeyedContainer: <#Format#>DecodingContainer {} 38 | -------------------------------------------------------------------------------- /Sources/Encoder/KeyedEncodingContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension _<#Format#>Encoder { 4 | final class KeyedContainer where Key: CodingKey { 5 | var codingPath: [CodingKey] 6 | var userInfo: [CodingUserInfoKey: Any] 7 | 8 | init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { 9 | self.codingPath = codingPath 10 | self.userInfo = userInfo 11 | } 12 | } 13 | } 14 | 15 | extension _<#Format#>Encoder.KeyedContainer: KeyedEncodingContainerProtocol { 16 | func encodeNil(forKey key: Key) throws { 17 | <#Implementation#> 18 | } 19 | 20 | func encode(_ value: T, forKey key: Key) throws where T : Encodable { 21 | <#Implementation#> 22 | } 23 | 24 | func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { 25 | <#Implementation#> 26 | } 27 | 28 | func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer where NestedKey : CodingKey { 29 | <#Implementation#> 30 | } 31 | 32 | func superEncoder() -> Encoder { 33 | <#Implementation#> 34 | } 35 | 36 | func superEncoder(forKey key: Key) -> Encoder { 37 | <#Implementation#> 38 | } 39 | } 40 | 41 | extension _<#Format#>Encoder.KeyedContainer: <#Format#>EncodingContainer {} 42 | -------------------------------------------------------------------------------- /Sources/Decoder/KeyedDecodingContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension _<#Format#>Decoder { 4 | final class KeyedContainer where Key: CodingKey { 5 | var codingPath: [CodingKey] 6 | var userInfo: [CodingUserInfoKey: Any] 7 | 8 | init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { 9 | self.codingPath = codingPath 10 | self.userInfo = userInfo 11 | } 12 | } 13 | } 14 | 15 | extension _<#Format#>Decoder.KeyedContainer: KeyedDecodingContainerProtocol { 16 | var allKeys: [Key] { 17 | <#Implementation#> 18 | } 19 | 20 | func contains(_ key: Key) -> Bool { 21 | <#Implementation#> 22 | } 23 | 24 | func decodeNil(forKey key: Key) throws -> Bool { 25 | <#Implementation#> 26 | } 27 | 28 | func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { 29 | <#Implementation#> 30 | } 31 | 32 | 33 | func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { 34 | <#Implementation#> 35 | } 36 | 37 | func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { 38 | <#Implementation#> 39 | } 40 | 41 | func superDecoder() throws -> Decoder { 42 | <#Implementation#> 43 | } 44 | 45 | func superDecoder(forKey key: Key) throws -> Decoder { 46 | <#Implementation#> 47 | } 48 | } 49 | 50 | extension _<#Format#>Decoder.KeyedContainer: <#Format#>DecodingContainer {} 51 | -------------------------------------------------------------------------------- /Tests/MessagePackTests/___RoundTripTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import <#Format#> 3 | 4 | class <#Format#>RoundTripTests: XCTestCase { 5 | var encoder: <#Format#>Encoder! 6 | var decoder: <#Format#>Decoder! 7 | 8 | override func setUp() { 9 | self.encoder = <#Format#>Encoder() 10 | self.decoder = <#Format#>Decoder() 11 | } 12 | 13 | func testRoundTrip() { 14 | let value = Airport(name: "Portland International Airport", 15 | iata: "PDX", 16 | icao: "KPDX", 17 | coordinates: [-122.5975, 45.5886111111111], 18 | runways: [ 19 | Airport.Runway(direction: "3/21", 20 | distance: 1829, 21 | surface: .flexible) 22 | ]) 23 | let encoded = try! encoder.encode(value) 24 | let decoded = try! decoder.decode(Airport.self, from: encoded) 25 | 26 | XCTAssertEqual(value.name, decoded.name) 27 | XCTAssertEqual(value.iata, decoded.iata) 28 | XCTAssertEqual(value.icao, decoded.icao) 29 | XCTAssertEqual(value.coordinates[0], decoded.coordinates[0], accuracy: 0.01) 30 | XCTAssertEqual(value.coordinates[1], decoded.coordinates[1], accuracy: 0.01) 31 | XCTAssertEqual(value.runways[0].direction, decoded.runways[0].direction) 32 | XCTAssertEqual(value.runways[0].distance, decoded.runways[0].distance) 33 | XCTAssertEqual(value.runways[0].surface, decoded.runways[0].surface) 34 | } 35 | 36 | static var allTests = [ 37 | ("testRoundTrip", testRoundTrip) 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Encoder/___Encoder.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | 5 | */ 6 | public class <#Format#>Encoder { 7 | func encode(_ value: Encodable) throws -> Data { 8 | let encoder = _<#Format#>Encoder() 9 | try value.encode(to: encoder) 10 | return encoder.data 11 | } 12 | } 13 | 14 | final class _<#Format#>Encoder { 15 | var codingPath: [CodingKey] = [] 16 | 17 | var userInfo: [CodingUserInfoKey : Any] = [:] 18 | 19 | fileprivate var container: <#Format#>EncodingContainer? 20 | } 21 | 22 | extension _<#Format#>Encoder: Encoder { 23 | fileprivate func assertCanCreateContainer() { 24 | precondition(self.container == nil) 25 | } 26 | 27 | func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { 28 | assertCanCreateContainer() 29 | 30 | let container = KeyedContainer(codingPath: self.codingPath, userInfo: self.userInfo) 31 | self.container = container 32 | 33 | return KeyedEncodingContainer(container) 34 | } 35 | 36 | func unkeyedContainer() -> UnkeyedEncodingContainer { 37 | assertCanCreateContainer() 38 | 39 | let container = UnkeyedContainer(codingPath: self.codingPath, userInfo: self.userInfo) 40 | self.container = container 41 | 42 | return container 43 | } 44 | 45 | func singleValueContainer() -> SingleValueEncodingContainer { 46 | assertCanCreateContainer() 47 | 48 | let container = SingleValueContainer(codingPath: self.codingPath, userInfo: self.userInfo) 49 | self.container = container 50 | 51 | return container 52 | } 53 | } 54 | 55 | protocol <#Format#>EncodingContainer: class { 56 | <#Requirements#> 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Decoder/___Decoder.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | 5 | */ 6 | final public class <#Format#>Decoder { 7 | func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { 8 | let decoder = _<#Format#>Decoder(data: data) 9 | return try T(from: decoder) 10 | } 11 | } 12 | 13 | final class _<#Format#>Decoder { 14 | var codingPath: [CodingKey] = [] 15 | 16 | var userInfo: [CodingUserInfoKey : Any] = [:] 17 | 18 | var container: <#Format#>DecodingContainer? 19 | fileprivate var data: Data 20 | 21 | init(data: Data) { 22 | self.data = data 23 | } 24 | } 25 | 26 | extension _<#Format#>Decoder: Decoder { 27 | fileprivate func assertCanCreateContainer() { 28 | precondition(self.container == nil) 29 | } 30 | 31 | func container(keyedBy type: Key.Type) -> KeyedDecodingContainer where Key : CodingKey { 32 | assertCanCreateContainer() 33 | 34 | let container = KeyedContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo) 35 | self.container = container 36 | 37 | return KeyedDecodingContainer(container) 38 | } 39 | 40 | func unkeyedContainer() -> UnkeyedDecodingContainer { 41 | assertCanCreateContainer() 42 | 43 | let container = UnkeyedContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo) 44 | self.container = container 45 | 46 | return container 47 | } 48 | 49 | func singleValueContainer() -> SingleValueDecodingContainer { 50 | assertCanCreateContainer() 51 | 52 | let container = SingleValueContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo) 53 | self.container = container 54 | 55 | return container 56 | } 57 | } 58 | 59 | protocol <#Format#>DecodingContainer: class { 60 | <#Requirements#> 61 | } 62 | -------------------------------------------------------------------------------- /Tests/MessagePackTests/___EncodingTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import <#Format#> 3 | 4 | class <#Format#>EncodingTests: XCTestCase { 5 | var encoder: <#Format#>Encoder! 6 | 7 | override func setUp() { 8 | self.encoder = <#Format#>Encoder() 9 | } 10 | 11 | func testEncodeFalse() { 12 | let value = try! encoder.encode(false) 13 | XCTAssertEqual(value, <#Expected#>) 14 | } 15 | 16 | func testEncodeTrue() { 17 | let value = try! encoder.encode(true) 18 | XCTAssertEqual(value, <#Expected#>) 19 | } 20 | 21 | func testEncodeInt() { 22 | let value = try! encoder.encode(Int.max) 23 | XCTAssertEqual(value, <#Expected#>) 24 | } 25 | 26 | func testEncodeUInt() { 27 | let value = try! encoder.encode(UInt.max) 28 | XCTAssertEqual(value, <#Expected#>) 29 | } 30 | 31 | func testEncodeFloat() { 32 | let value = try! encoder.encode(Float.pi) 33 | XCTAssertEqual(value, <#Expected#>) 34 | } 35 | 36 | func testEncodeDouble() { 37 | let value = try! encoder.encode(Double.pi) 38 | XCTAssertEqual(value, <#Expected#>) 39 | } 40 | 41 | func testEncodeArray() { 42 | let value = try! encoder.encode([1, 2, 3]) 43 | XCTAssertEqual(value, <#Expected#>) 44 | } 45 | 46 | func testEncodeDictionary() { 47 | let value = try! encoder.encode(["a": 1, "b": 2, "c": 3]) 48 | XCTAssertEqual(value, <#Expected#>) 49 | } 50 | 51 | static var allTests = [ 52 | ("testEncodeFalse", testEncodeFalse), 53 | ("testEncodeTrue", testEncodeTrue), 54 | ("testEncodeInt", testEncodeInt), 55 | ("testEncodeInt", testEncodeUInt), 56 | ("testEncodeFloat", testEncodeFloat), 57 | ("testEncodeDouble", testEncodeDouble), 58 | ("testEncodeArray", testEncodeArray), 59 | ("testEncodeDictionary", testEncodeDictionary) 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /Sources/Encoder/SingleValueEncodingContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension _<#Format#>Encoder { 4 | final class SingleValueContainer { 5 | var codingPath: [CodingKey] 6 | var userInfo: [CodingUserInfoKey: Any] 7 | 8 | init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { 9 | self.codingPath = codingPath 10 | self.userInfo = userInfo 11 | } 12 | } 13 | } 14 | 15 | extension _<#Format#>Encoder.SingleValueContainer: SingleValueEncodingContainer { 16 | func encodeNil() throws { 17 | <#Implementation#> 18 | } 19 | 20 | func encode(_ value: Bool) throws { 21 | <#Implementation#> 22 | } 23 | 24 | func encode(_ value: String) throws { 25 | <#Implementation#> 26 | } 27 | 28 | func encode(_ value: Double) throws { 29 | <#Implementation#> 30 | } 31 | 32 | func encode(_ value: Float) throws { 33 | <#Implementation#> 34 | } 35 | 36 | func encode(_ value: Int) throws { 37 | <#Implementation#> 38 | } 39 | 40 | func encode(_ value: Int8) throws { 41 | <#Implementation#> 42 | } 43 | 44 | func encode(_ value: Int16) throws { 45 | <#Implementation#> 46 | } 47 | 48 | func encode(_ value: Int32) throws { 49 | <#Implementation#> 50 | } 51 | 52 | func encode(_ value: Int64) throws { 53 | <#Implementation#> 54 | } 55 | 56 | func encode(_ value: UInt) throws { 57 | <#Implementation#> 58 | } 59 | 60 | func encode(_ value: UInt8) throws { 61 | <#Implementation#> 62 | } 63 | 64 | func encode(_ value: UInt16) throws { 65 | <#Implementation#> 66 | } 67 | 68 | func encode(_ value: UInt32) throws { 69 | <#Implementation#> 70 | } 71 | 72 | func encode(_ value: UInt64) throws { 73 | <#Implementation#> 74 | } 75 | 76 | func encode(_ value: T) throws where T : Encodable { 77 | <#Implementation#> 78 | } 79 | } 80 | 81 | extension _<#Format#>Encoder.SingleValueContainer: <#Format#>EncodingContainer {} 82 | -------------------------------------------------------------------------------- /Tests/MessagePackTests/___DecodingTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import <#Format#> 3 | 4 | class <#Format#>DecodingTests: XCTestCase { 5 | var decoder: <#Format#>Decoder! 6 | 7 | override func setUp() { 8 | self.decoder = <#Format#>Decoder() 9 | } 10 | 11 | func testDecodeFalse() { 12 | let data = <#Data#> 13 | let value = try! decoder.decode(Bool.self, from: data) 14 | XCTAssertEqual(value, false) 15 | } 16 | 17 | func testDecodeTrue() { 18 | let data = <#Data#> 19 | let value = try! decoder.decode(Bool.self, from: data) 20 | XCTAssertEqual(value, true) 21 | } 22 | 23 | func testDecodeInt() { 24 | let data = <#Data#> 25 | let value = try! decoder.decode(Int.self, from: data) 26 | XCTAssertEqual(value, Int.max) 27 | } 28 | 29 | func testDecodeUInt() { 30 | let data = <#Data#> 31 | let value = try! decoder.decode(Int.self, from: data) 32 | XCTAssertEqual(value, UInt.max) 33 | } 34 | 35 | func testDecodeFloat() { 36 | let data = <#Data#> 37 | let value = try! decoder.decode(Double.self, from: data) 38 | XCTAssertEqual(value, Float.pi) 39 | } 40 | 41 | func testDecodeDouble() { 42 | let data = <#Data#> 43 | let value = try! decoder.decode(Double.self, from: data) 44 | XCTAssertEqual(value, Double.pi) 45 | } 46 | 47 | func testDecodeArray() { 48 | let data = <#Data#> 49 | let value = try! decoder.decode([Int].self, from: data) 50 | XCTAssertEqual(value, [1, 2, 3]) 51 | } 52 | 53 | func testDecodeDictionary() { 54 | let data = <#Data#> 55 | let value = try! decoder.decode([String: Int].self, from: data) 56 | XCTAssertEqual(value, ["a": 1, "b": 2, "c": 3]) 57 | } 58 | 59 | static var allTests = [ 60 | ("testDecodeFalse", testDecodeFalse), 61 | ("testDecodeTrue", testDecodeTrue), 62 | ("testDecodeInt", testDecodeInt), 63 | ("testDecodeUInt", testDecodeUInt), 64 | ("testDecodeFloat", testDecodeFloat), 65 | ("testDecodeDouble", testDecodeDouble), 66 | ("testDecodeArray", testDecodeArray) 67 | ("testDecodeDictionary", testDecodeDictionary) 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /Sources/Decoder/SingleValueDecodingContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension _<#Format#>Decoder { 4 | final class SingleValueContainer { 5 | var codingPath: [CodingKey] 6 | var userInfo: [CodingUserInfoKey: Any] 7 | 8 | 9 | init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { 10 | self.codingPath = codingPath 11 | self.userInfo = userInfo 12 | } 13 | } 14 | } 15 | 16 | extension _<#Format#>Decoder.SingleValueContainer: SingleValueDecodingContainer { 17 | func decodeNil() -> Bool { 18 | <#Implementation#> 19 | } 20 | 21 | func decode(_ type: Bool.Type) throws -> Bool { 22 | <#Implementation#> 23 | } 24 | 25 | func decode(_ type: String.Type) throws -> String { 26 | <#Implementation#> 27 | } 28 | 29 | func decode(_ type: Double.Type) throws -> Double { 30 | <#Implementation#> 31 | } 32 | 33 | func decode(_ type: Float.Type) throws -> Float { 34 | <#Implementation#> 35 | } 36 | 37 | func decode(_ type: Int.Type) throws -> Int { 38 | <#Implementation#> 39 | } 40 | 41 | func decode(_ type: Int8.Type) throws -> Int8 { 42 | <#Implementation#> 43 | } 44 | 45 | func decode(_ type: Int16.Type) throws -> Int16 { 46 | <#Implementation#> 47 | } 48 | 49 | func decode(_ type: Int32.Type) throws -> Int32 { 50 | <#Implementation#> 51 | } 52 | 53 | func decode(_ type: Int64.Type) throws -> Int64 { 54 | <#Implementation#> 55 | } 56 | 57 | func decode(_ type: UInt.Type) throws -> UInt { 58 | <#Implementation#> 59 | } 60 | 61 | func decode(_ type: UInt8.Type) throws -> UInt8 { 62 | <#Implementation#> 63 | } 64 | 65 | func decode(_ type: UInt16.Type) throws -> UInt16 { 66 | <#Implementation#> 67 | } 68 | 69 | func decode(_ type: UInt32.Type) throws -> UInt32 { 70 | <#Implementation#> 71 | } 72 | 73 | func decode(_ type: UInt64.Type) throws -> UInt64 { 74 | <#Implementation#> 75 | } 76 | 77 | func decode(_ type: T.Type) throws -> T where T : Decodable { 78 | <#Implementation#> 79 | } 80 | } 81 | 82 | extension _<#Format#>Decoder.SingleValueContainer: <#Format#>DecodingContainer {} 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DIY Codable Encoder / Decoder Kit 2 | 3 | In Swift 4, 4 | a type that conforms to the `Codable` protocol 5 | can be encoded to or decoded from representations 6 | for any format that implements a corresponding `Encoder` or `Decoder` type. 7 | 8 | At the time of its release, 9 | the only reference implementations for these types 10 | were the Foundation framework's `JSONEncoder` / `JSONDecoder` 11 | and `PropertyListEncoder` and `PropertyListDecoder`. 12 | The [implementation details](https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/JSONEncoder.swift) 13 | of these types, however, 14 | are obfuscated by translation logic from 15 | `JSONSerialization` and `PropertyListSerialization`. 16 | 17 | This repository provides a template 18 | that makes it easier for developers 19 | to create encoders and decoders for custom formats. 20 | The template includes stubbed placeholders for the required types and methods 21 | as well as simple tests for encoding and decoding `Codable` types. 22 | 23 | This general structure was used to implement a `Codable`-compatible 24 | [encoder and decoder for the MessagePack format](https://github.com/flight-school/messagepack). 25 | 26 | For more information about the design and implementation 27 | of custom encoder and decoder types, 28 | see Chapter 7 of 29 | [Flight School Guide to Swift Codable](https://flight.school/books/codable). 30 | 31 | ## Usage 32 | 33 | * Clone this repository 34 | * Find all instances of the "<#Format#>" placeholder 35 | and replace with the name of your own format 36 | * Replace the leading underscores in the 37 | `___Decoder.swift` and `___Encoder.swift` files, 38 | as well as the source files in the Tests directory 39 | * Run the command `swift package generate-xcodeproj` 40 | in the root project directory 41 | * Fill in the missing implementation accordingly 42 | 43 | ### Encoder Structure 44 | 45 | ```swift 46 | public class <#Format#>Encoder { 47 | public func encode(_ value: T) throws -> Data 48 | where T : Encodable 49 | } 50 | 51 | final class _<#Format#>Encoder: Encoder { 52 | final class SingleValueContainer: SingleValueEncodingContainer 53 | final class UnkeyedContainer: UnkeyedEncodingContainer 54 | final class KeyedContainer: KeyedEncodingContainerProtocol 55 | where Key: CodingKey 56 | } 57 | 58 | protocol <#Format#>EncodingContainer: class {} 59 | ``` 60 | 61 | ### Decoder Structure 62 | 63 | ```swift 64 | public class <#Format#>Decoder { 65 | public func decode(_ type: T.Type, 66 | from data: Data) throws -> T 67 | where T : Decodable 68 | } 69 | 70 | final class _<#Format#>Decoder: Decoder { 71 | final class SingleValueContainer: SingleValueDecodingContainer 72 | final class UnkeyedContainer: UnkeyedDecodingContainer 73 | final class KeyedContainer: KeyedContainer 74 | where Key: CodingKey 75 | } 76 | 77 | protocol <#Format#>DecodingContainer: class {} 78 | ``` 79 | 80 | ## License 81 | 82 | MIT 83 | 84 | ## Contact 85 | 86 | Mattt ([@mattt](https://twitter.com/mattt)) 87 | --------------------------------------------------------------------------------