From c80b0f83752590ea88f5b4e2946da04c3acb12de Mon Sep 17 00:00:00 2001 From: Yehor Popovych Date: Fri, 7 Jul 2023 17:15:48 +0100 Subject: [PATCH] renamed to ContextCodable, added README --- ...ft.podspec => ContextCodable.swift.podspec | 12 +- Package.swift | 12 +- README.md | 136 +++++++++++++++++- Sources/ConfigurationCodable/Decodable.swift | 96 ------------- Sources/ConfigurationCodable/Encodable.swift | 68 --------- Sources/ContextCodable/Decodable.swift | 94 ++++++++++++ Sources/ContextCodable/Encodable.swift | 68 +++++++++ .../ThreadLocal.swift | 0 .../DecodableTests.swift | 48 +++---- .../EncodableTests.swift | 58 ++++---- 10 files changed, 359 insertions(+), 233 deletions(-) rename ConfigurationCodable.swift.podspec => ContextCodable.swift.podspec (68%) delete mode 100644 Sources/ConfigurationCodable/Decodable.swift delete mode 100644 Sources/ConfigurationCodable/Encodable.swift create mode 100644 Sources/ContextCodable/Decodable.swift create mode 100644 Sources/ContextCodable/Encodable.swift rename Sources/{ConfigurationCodable => ContextCodable}/ThreadLocal.swift (100%) rename Tests/{ConfigurationCodableTests => ContextCodableTests}/DecodableTests.swift (76%) rename Tests/{ConfigurationCodableTests => ContextCodableTests}/EncodableTests.swift (72%) diff --git a/ConfigurationCodable.swift.podspec b/ContextCodable.swift.podspec similarity index 68% rename from ConfigurationCodable.swift.podspec rename to ContextCodable.swift.podspec index 2f6e6e6..dbee92c 100644 --- a/ConfigurationCodable.swift.podspec +++ b/ContextCodable.swift.podspec @@ -1,5 +1,5 @@ Pod::Spec.new do |s| - s.name = 'ConfigurationCodable.swift' + s.name = 'ContextCodable.swift' s.version = '0.1.0' s.summary = 'Backport of CodableWithConfiguration to old OS versions and Linux' @@ -7,11 +7,11 @@ Pod::Spec.new do |s| CodableWithConfiguration ported to older versions of Apple operating systems and Linux DESC - s.homepage = 'https://github.com/tesseract-one/ConfigurationCodable.swift' + s.homepage = 'https://github.com/tesseract-one/ContextCodable.swift' s.license = { :type => 'Apache-2.0', :file => 'LICENSE' } s.author = { 'Tesseract Systems, Inc.' => 'info@tesseract.one' } - s.source = { :git => 'https://github.com/tesseract-one/ConfigurationCodable.swift.git', :tag => s.version.to_s } + s.source = { :git => 'https://github.com/tesseract-one/ContextCodable.swift.git', :tag => s.version.to_s } s.ios.deployment_target = '11.0' s.osx.deployment_target = '10.12' @@ -20,12 +20,12 @@ Pod::Spec.new do |s| s.swift_version = '5.4' - s.module_name = 'ConfigurationCodable' + s.module_name = 'ContextCodable' - s.source_files = 'Sources/ConfigurationCodable/**/*.swift' + s.source_files = 'Sources/ContextCodable/**/*.swift' s.test_spec 'Tests' do |test_spec| test_spec.platforms = {:ios => '11.0', :osx => '10.12', :tvos => '11.0'} - test_spec.source_files = 'Tests/ConfigurationCodableTests/*.swift' + test_spec.source_files = 'Tests/ContextCodableTests/*.swift' end end diff --git a/Package.swift b/Package.swift index 4bc3157..08c5f82 100644 --- a/Package.swift +++ b/Package.swift @@ -4,20 +4,20 @@ import PackageDescription let package = Package( - name: "ConfigurationCodable", + name: "ContextCodable", platforms: [.macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2)], products: [ .library( - name: "ConfigurationCodable", - targets: ["ConfigurationCodable"]) + name: "ContextCodable", + targets: ["ContextCodable"]) ], dependencies: [], targets: [ .target( - name: "ConfigurationCodable", + name: "ContextCodable", dependencies: []), .testTarget( - name: "ConfigurationCodableTests", - dependencies: ["ConfigurationCodable"]) + name: "ContextCodableTests", + dependencies: ["ContextCodable"]) ] ) diff --git a/README.md b/README.md index 89970c5..0d89582 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,134 @@ -# ConfigurationCodable.swift -Backport of CodableWithConfiguration to old OS versions and Linux +# ContextCodable.swift + +![🐧 linux: ready](https://img.shields.io/badge/%F0%9F%90%A7%20linux-ready-red.svg) +[![GitHub license](https://img.shields.io/badge/license-Apache%202.0-lightgrey.svg)](https://raw.githubusercontent.com/tesseract-one/ContextCodable.swift/main/LICENSE) +[![Build Status](https://github.com/tesseract-one/ContextCodable.swift/workflows/Build%20%26%20Tests/badge.svg?branch=main)](https://github.com/tesseract-one/ContextCodable.swift/actions?query=workflow%3ABuild%20%26%20Tests+branch%3Amain) +[![GitHub release](https://img.shields.io/github/release/tesseract-one/ContextCodable.swift.svg)](https://github.com/tesseract-one/ContextCodable.swift/releases) +[![SPM compatible](https://img.shields.io/badge/SwiftPM-Compatible-brightgreen.svg)](https://swift.org/package-manager/) +[![CocoaPods version](https://img.shields.io/cocoapods/v/ContextCodable.swift.svg)](https://cocoapods.org/pods/ContextCodable.swift) +![Platform OS X | iOS | tvOS | watchOS | Linux](https://img.shields.io/badge/platform-Linux%20%7C%20OS%20X%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-orange.svg) + +### Backport of CodableWithConfiguration to old OS versions and Linux + +## Why? + +Apple added type of `Codable` - `CodableWithConfiguration` which allows to provide context for encoding and decoding. + +But this protocols are available only from macOS 12, and `JSONEncoder` and `JSONDecoder` support added only in macOS 15. Linux does not support them at all. + +So we created this library, which enables this API on old Swift and platforms. It has some speed drawbacks, but it works! + +## Getting started + +### Installation + +#### [Package Manager](https://swift.org/package-manager/) + +Add the following dependency to your [Package.swift](https://github.com/apple/swift-package-manager/blob/master/Documentation/Usage.md#define-dependencies): + +```swift +.package(url: "https://github.com/tesseract-one/ContextCodable.swift.git", from: "0.1.0") +``` + +Run `swift build` and build your app. + +#### [CocoaPods](http://cocoapods.org/) + +Add the following to your [Podfile](http://guides.cocoapods.org/using/the-podfile.html): + +```rb +pod 'ContextCodable.swift', '~> 0.1.0' +``` + +Then run `pod install` + +### Examples + +#### Encoding +```swift +import Foundation +import ContextCodable + +struct SomeEncodable: ContextEncodable { + typealias EncodingContext = (top: String, internal: Date) + + let internal: Internal + + struct Internal: ContextEncodable { + typealias EncodingContext = Date + + let value: Bool + + func encode(to encoder: Encoder, context: EncodingContext) throws { + var container = encoder.unkeyedContainer() + try container.encode(value) + try container.encode(context) + } + } + + enum CodingKeys: CodingKey { + case `internal` + case context + } + + func encode(to encoder: Encoder, context: EncodingContext) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(self.internal, forKey: .internal, context: context.internal) + try container.encode(context.top, forKey: .context) + } +} + +let value = SomeEncodable(internal: SomeEncodable.Internal(value: true)) +let encoded = try JSONEncoder().encode(value, context: (top: "Test", internal: Date())) +print(String(data: encoded, encoding: .utf8)!) +``` + +#### Decoding +```swift +import Foundation +import ContextCodable + +struct SomeDecodable: ContextDecodable { + typealias DecodingContext = (top: String, internal: Date) + + let internal: Internal + let top: String + + struct Internal: ContextDecodable { + typealias DecodingContext = Date + + let value: Bool + let date: Date + + init(from decoder: Decoder, context: DecodingContext) throws { + var container = try decoder.unkeyedContainer() + value = try container.decode(Bool.self) + date = context + } + } + + enum CodingKeys: CodingKey { + case `internal` + case context + } + + init(from decoder: Decoder, context: DecodingContext) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.internal = try decoder.decode(Internal.self, forKey: .internal, context: context.internal) + self.top = context.top + } +} + +let json = Data("{\"internal\": [true]}".utf8) +let decoded = try JSONDecoder().decode(SomeDecodable.self, from: json, context: (top: "Test", internal: Date())) +print(decoded) +``` + +## Author + + - [Tesseract Systems, Inc.](mailto:info@tesseract.one) + ([@tesseract_one](https://twitter.com/tesseract_one)) + +## License + +ContextCodable.swift is available under the Apache 2.0 license. See [the LICENSE file](./LICENSE) for more information. diff --git a/Sources/ConfigurationCodable/Decodable.swift b/Sources/ConfigurationCodable/Decodable.swift deleted file mode 100644 index 942ae06..0000000 --- a/Sources/ConfigurationCodable/Decodable.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// Decodable.swift -// -// -// Created by Yehor Popovych on 06/07/2023. -// - -import Foundation -import CoreFoundation - -public typealias CodableWithConfiguration = - DecodableWithConfiguration & EncodableWithConfiguration - -public protocol DecodableWithConfiguration { - associatedtype DecodingConfiguration - - init(from decoder: Decoder, configuration: DecodingConfiguration) throws -} - -public struct DecodableWrapper: Decodable { - public let value: Wrapped - - @inlinable - public init(from decoder: Decoder) throws { - guard let anyconf = Self.configuration() else { - throw DecodingError.valueNotFound( - Wrapped.DecodingConfiguration.self, - DecodingError.Context(codingPath: decoder.codingPath, - debugDescription: "Configuration is empty") - ) - } - guard let conf = anyconf as? Wrapped.DecodingConfiguration else { - let error = "Configuration has different type \(type(of: anyconf))" - throw DecodingError.typeMismatch( - Wrapped.DecodingConfiguration.self, - DecodingError.Context( - codingPath: decoder.codingPath, - debugDescription: error - ) - ) - } - value = try Wrapped(from: decoder, configuration: conf) - } - - public static func set(configuration: Wrapped.DecodingConfiguration) { - DecodableThreadLocalKey.set(value: configuration) - } - - // One time call. Will remove configuration from ThreadLocal - // Any because body is unknown (try cast it) - public static func configuration() -> Any? { - DecodableThreadLocalKey.replace(with: nil) - } - - public static var threadLocalKey: ThreadLocal { DecodableThreadLocalKey } -} - -public extension JSONDecoder { - @inlinable - func decode( - _: T.Type, from data: Data, configuration: T.DecodingConfiguration - ) throws -> T { - DecodableWrapper.set(configuration: configuration) - return try decode(DecodableWrapper.self, from: data).value - } -} - -public extension UnkeyedDecodingContainer { - @inlinable - mutating func decode( - _: T.Type, configuration: T.DecodingConfiguration - ) throws -> T { - DecodableWrapper.set(configuration: configuration) - return try decode(DecodableWrapper.self).value - } -} - -public extension KeyedDecodingContainer { - @inlinable - func decode( - _: T.Type, forKey key: Key, configuration: T.DecodingConfiguration - ) throws -> T { - DecodableWrapper.set(configuration: configuration) - return try decode(DecodableWrapper.self, forKey: key).value - } - - @inlinable - func decodeIfPresent( - _: T.Type, forKey key: Key, configuration: T.DecodingConfiguration - ) throws -> T? { - DecodableWrapper.set(configuration: configuration) - return try decodeIfPresent(DecodableWrapper.self, forKey: key)?.value - } -} - -private let DecodableThreadLocalKey = ThreadLocal() diff --git a/Sources/ConfigurationCodable/Encodable.swift b/Sources/ConfigurationCodable/Encodable.swift deleted file mode 100644 index 2942558..0000000 --- a/Sources/ConfigurationCodable/Encodable.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// Encodable.swift -// -// -// Created by Yehor Popovych on 06/07/2023. -// - -import Foundation - -public protocol EncodableWithConfiguration { - associatedtype EncodingConfiguration - - func encode(to encoder: Encoder, configuration: EncodingConfiguration) throws -} - -public struct EncodableWrapper: Encodable { - public let value: Wrapped - public let configuration: Wrapped.EncodingConfiguration - - @inlinable - public init(_ v: Wrapped, configuration: Wrapped.EncodingConfiguration) { - self.value = v - self.configuration = configuration - } - - @inlinable - public func encode(to encoder: Encoder) throws { - try value.encode(to: encoder, configuration: configuration) - } -} - -public extension JSONEncoder { - @inlinable - func encode( - _ t: T, configuration: T.EncodingConfiguration - ) throws -> Data where T: EncodableWithConfiguration { - try encode(EncodableWrapper(t, configuration: configuration)) - } -} - -public extension UnkeyedEncodingContainer { - @inlinable - mutating func encode( - _ value: T, configuration: T.EncodingConfiguration - ) throws { - try encode(EncodableWrapper(value, configuration: configuration)) - } -} - -public extension KeyedEncodingContainer { - @inlinable - mutating func encode( - _ value: T, forKey key: Key, configuration: T.EncodingConfiguration - ) throws { - try encode(EncodableWrapper(value, configuration: configuration), - forKey: key) - } - - @inlinable - mutating func encodeIfPresent( - _ value: T?, forKey key: Key, configuration: T.EncodingConfiguration - ) throws { - try encodeIfPresent( - value.map { EncodableWrapper($0, configuration: configuration) }, - forKey: key - ) - } -} diff --git a/Sources/ContextCodable/Decodable.swift b/Sources/ContextCodable/Decodable.swift new file mode 100644 index 0000000..0690c90 --- /dev/null +++ b/Sources/ContextCodable/Decodable.swift @@ -0,0 +1,94 @@ +// +// Decodable.swift +// +// +// Created by Yehor Popovych on 06/07/2023. +// + +import Foundation + +public typealias ContextCodable = ContextDecodable & ContextEncodable + +public protocol ContextDecodable { + associatedtype DecodingContext + + init(from decoder: Decoder, context: DecodingContext) throws +} + +public struct DecodableWrapper: Decodable { + public let value: Wrapped + + @inlinable + public init(from decoder: Decoder) throws { + guard let anyctx = Self.context() else { + throw DecodingError.valueNotFound( + Wrapped.DecodingContext.self, + DecodingError.Context(codingPath: decoder.codingPath, + debugDescription: "Context is empty") + ) + } + guard let context = anyctx as? Wrapped.DecodingContext else { + let error = "Context has different type \(type(of: anyctx))" + throw DecodingError.typeMismatch( + Wrapped.DecodingContext.self, + DecodingError.Context( + codingPath: decoder.codingPath, + debugDescription: error + ) + ) + } + value = try Wrapped(from: decoder, context: context) + } + + public static func set(context: Wrapped.DecodingContext) { + DecodableThreadLocalKey.set(value: context) + } + + // One time call. Will remove configuration from ThreadLocal + // Any because body is unknown (try cast it) + public static func context() -> Any? { + DecodableThreadLocalKey.replace(with: nil) + } + + public static var threadLocalKey: ThreadLocal { DecodableThreadLocalKey } +} + +public extension JSONDecoder { + @inlinable + func decode( + _: T.Type, from data: Data, context: T.DecodingContext + ) throws -> T { + DecodableWrapper.set(context: context) + return try decode(DecodableWrapper.self, from: data).value + } +} + +public extension UnkeyedDecodingContainer { + @inlinable + mutating func decode( + _: T.Type, context: T.DecodingContext + ) throws -> T { + DecodableWrapper.set(context: context) + return try decode(DecodableWrapper.self).value + } +} + +public extension KeyedDecodingContainer { + @inlinable + func decode( + _: T.Type, forKey key: Key, context: T.DecodingContext + ) throws -> T { + DecodableWrapper.set(context: context) + return try decode(DecodableWrapper.self, forKey: key).value + } + + @inlinable + func decodeIfPresent( + _: T.Type, forKey key: Key, context: T.DecodingContext + ) throws -> T? { + DecodableWrapper.set(context: context) + return try decodeIfPresent(DecodableWrapper.self, forKey: key)?.value + } +} + +private let DecodableThreadLocalKey = ThreadLocal() diff --git a/Sources/ContextCodable/Encodable.swift b/Sources/ContextCodable/Encodable.swift new file mode 100644 index 0000000..83d592e --- /dev/null +++ b/Sources/ContextCodable/Encodable.swift @@ -0,0 +1,68 @@ +// +// Encodable.swift +// +// +// Created by Yehor Popovych on 06/07/2023. +// + +import Foundation + +public protocol ContextEncodable { + associatedtype EncodingContext + + func encode(to encoder: Encoder, context: EncodingContext) throws +} + +public struct EncodableWrapper: Encodable { + public let value: Wrapped + public let context: Wrapped.EncodingContext + + @inlinable + public init(_ v: Wrapped, context: Wrapped.EncodingContext) { + self.value = v + self.context = context + } + + @inlinable + public func encode(to encoder: Encoder) throws { + try value.encode(to: encoder, context: context) + } +} + +public extension JSONEncoder { + @inlinable + func encode( + _ value: T, context: T.EncodingContext + ) throws -> Data where T: ContextEncodable { + try encode(EncodableWrapper(value, context: context)) + } +} + +public extension UnkeyedEncodingContainer { + @inlinable + mutating func encode( + _ value: T, context: T.EncodingContext + ) throws { + try encode(EncodableWrapper(value, context: context)) + } +} + +public extension KeyedEncodingContainer { + @inlinable + mutating func encode( + _ value: T, forKey key: Key, context: T.EncodingContext + ) throws { + try encode(EncodableWrapper(value, context: context), + forKey: key) + } + + @inlinable + mutating func encodeIfPresent( + _ value: T?, forKey key: Key, context: T.EncodingContext + ) throws { + try encodeIfPresent( + value.map { EncodableWrapper($0, context: context) }, + forKey: key + ) + } +} diff --git a/Sources/ConfigurationCodable/ThreadLocal.swift b/Sources/ContextCodable/ThreadLocal.swift similarity index 100% rename from Sources/ConfigurationCodable/ThreadLocal.swift rename to Sources/ContextCodable/ThreadLocal.swift diff --git a/Tests/ConfigurationCodableTests/DecodableTests.swift b/Tests/ContextCodableTests/DecodableTests.swift similarity index 76% rename from Tests/ConfigurationCodableTests/DecodableTests.swift rename to Tests/ContextCodableTests/DecodableTests.swift index e162a95..494ebe0 100644 --- a/Tests/ConfigurationCodableTests/DecodableTests.swift +++ b/Tests/ContextCodableTests/DecodableTests.swift @@ -7,8 +7,7 @@ import Foundation import XCTest -@testable import ConfigurationCodable - +@testable import ContextCodable final class DecodableTests: XCTestCase { func testSimple() throws { @@ -17,7 +16,7 @@ final class DecodableTests: XCTestCase { let decoder = JSONDecoder() let decoded = try decoder.decode(Obj.self, from: encoded, - configuration: expected.config) + context: expected.context) XCTAssertEqual(decoded, expected) } @@ -42,7 +41,7 @@ final class DecodableTests: XCTestCase { do { let decoded = try decoder.decode(Obj.self, from: data, - configuration: expected.config) + context: expected.context) XCTAssertEqual(decoded, expected) } catch { XCTFail("error: \(error)") @@ -71,10 +70,9 @@ final class DecodableTests: XCTestCase { } private struct Obj: - Equatable, Encodable, ConfigurationCodable.DecodableWithConfiguration + Equatable, Encodable, ContextDecodable { - typealias DecodingConfiguration = - (date: Date, int: Int, string: String, double: Double) + typealias DecodingContext = (date: Date, int: Int, string: String, double: Double) let intAndStr: IntAndStr let arrayAndDate: ArrayAndDate @@ -99,18 +97,18 @@ private struct Obj: self.string = string } - init(from decoder: Decoder, configuration: DecodingConfiguration) throws { + init(from decoder: Decoder, context: DecodingContext) throws { let container = try decoder.container(keyedBy: CodingKeys.self) intAndStr = try container.decode(IntAndStr.self, forKey: .int, - configuration: configuration.string) + context: context.string) arrayAndDate = try container.decode(ArrayAndDate.self, forKey: .array, - configuration: configuration.date) + context: context.date) nullAndDouble = try container.decode(NullAndDouble.self, forKey: .null, - configuration: configuration.double) - int = configuration.int + context: context.double) + int = context.int string = try container.decode(String.self, forKey: .string) } @@ -122,16 +120,16 @@ private struct Obj: try container.encode(string, forKey: .string) } - var config: DecodingConfiguration { + var context: DecodingContext { (date: arrayAndDate.date, int: int, string: intAndStr.string, double: nullAndDouble.double) } } private struct IntAndStr: - Equatable, Encodable, ConfigurationCodable.DecodableWithConfiguration + Equatable, Encodable, ContextDecodable { - typealias DecodingConfiguration = String + typealias DecodingContext = String let int: Int let string: String @@ -141,9 +139,9 @@ private struct IntAndStr: self.string = string } - init(from decoder: Decoder, configuration: String) throws { + init(from decoder: Decoder, context: DecodingContext) throws { int = try Int(from: decoder) - string = configuration + string = context } func encode(to encoder: Encoder) throws { @@ -152,9 +150,9 @@ private struct IntAndStr: } private struct ArrayAndDate: - Equatable, Encodable, ConfigurationCodable.DecodableWithConfiguration + Equatable, Encodable, ContextDecodable { - typealias DecodingConfiguration = Date + typealias DecodingContext = Date let array: Array let date: Date @@ -164,9 +162,9 @@ private struct ArrayAndDate: self.date = date } - init(from decoder: Decoder, configuration: Date) throws { + init(from decoder: Decoder, context: DecodingContext) throws { array = try Array(from: decoder) - date = configuration + date = context } func encode(to encoder: Encoder) throws { @@ -175,9 +173,9 @@ private struct ArrayAndDate: } private struct NullAndDouble: - Equatable, Encodable, ConfigurationCodable.DecodableWithConfiguration + Equatable, Encodable, ContextDecodable { - typealias DecodingConfiguration = Double + typealias DecodingContext = Double let double: Double @@ -185,10 +183,10 @@ private struct NullAndDouble: self.double = double } - init(from decoder: Decoder, configuration: Double) throws { + init(from decoder: Decoder, context: DecodingContext) throws { let nl = try decoder.singleValueContainer().decodeNil() assert(nl) - double = configuration + double = context } func encode(to encoder: Encoder) throws { diff --git a/Tests/ConfigurationCodableTests/EncodableTests.swift b/Tests/ContextCodableTests/EncodableTests.swift similarity index 72% rename from Tests/ConfigurationCodableTests/EncodableTests.swift rename to Tests/ContextCodableTests/EncodableTests.swift index df0f12a..fdf84d6 100644 --- a/Tests/ConfigurationCodableTests/EncodableTests.swift +++ b/Tests/ContextCodableTests/EncodableTests.swift @@ -7,15 +7,14 @@ import Foundation import XCTest -@testable import ConfigurationCodable - +@testable import ContextCodable final class EncodableTests: XCTestCase { func testSimple() throws { let expected = randomObject() let encodable = expected.enc let encoded = try JSONEncoder().encode(encodable, - configuration: expected.config) + context: expected.context) let decoded = try JSONDecoder().decode(DecObj.self, from: encoded) XCTAssertEqual(decoded, expected) } @@ -35,7 +34,7 @@ final class EncodableTests: XCTestCase { defer { expect.fulfill() } do { let encoded = try encoder.encode(expected.enc, - configuration: expected.config) + context: expected.context) let decoded = try decoder.decode(DecObj.self, from: encoded) XCTAssertEqual(decoded, expected) } catch { @@ -64,9 +63,8 @@ final class EncodableTests: XCTestCase { } } -private struct EncObj: ConfigurationCodable.EncodableWithConfiguration { - typealias EncodingConfiguration = - (date: Date, int: Int, string: String, double: Double) +private struct EncObj: ContextEncodable { + typealias EncodingContext = (date: Date, int: Int, string: String, double: Double) let int: EncIntAndStr let array: EncArrayAndDate @@ -89,21 +87,21 @@ private struct EncObj: ConfigurationCodable.EncodableWithConfiguration { self.string = string } - func encode(to encoder: Encoder, configuration: EncodingConfiguration) throws { + func encode(to encoder: Encoder, context: EncodingContext) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(int, forKey: .int, - configuration: configuration.string) + context: context.string) try container.encode(array, forKey: .array, - configuration: configuration.date) + context: context.date) try container.encode(null, forKey: .null, - configuration: configuration.double) - try container.encode(configuration.int, forKey: .simpleInt) + context: context.double) + try container.encode(context.int, forKey: .simpleInt) try container.encode(string, forKey: .string) } } -private struct EncIntAndStr: ConfigurationCodable.EncodableWithConfiguration { - typealias EncodingConfiguration = String +private struct EncIntAndStr: ContextEncodable { + typealias EncodingContext = String let int: Int @@ -116,15 +114,15 @@ private struct EncIntAndStr: ConfigurationCodable.EncodableWithConfiguration { self.int = int } - func encode(to encoder: Encoder, configuration: String) throws { + func encode(to encoder: Encoder, context: EncodingContext) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(int, forKey: .int) - try container.encode(configuration, forKey: .string) + try container.encode(context, forKey: .string) } } -private struct EncArrayAndDate: ConfigurationCodable.EncodableWithConfiguration { - typealias EncodingConfiguration = Date +private struct EncArrayAndDate: ContextEncodable { + typealias EncodingContext = Date let array: Array @@ -137,20 +135,20 @@ private struct EncArrayAndDate: ConfigurationCodable.EncodableWithConfiguration case date } - func encode(to encoder: Encoder, configuration: Date) throws { + func encode(to encoder: Encoder, context: EncodingContext) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(array, forKey: .array) - try container.encode(configuration, forKey: .date) + try container.encode(context, forKey: .date) } } -private struct EncNullAndDouble: ConfigurationCodable.EncodableWithConfiguration { - typealias EncodingConfiguration = Double +private struct EncNullAndDouble: ContextEncodable { + typealias EncodingContext = Double - func encode(to encoder: Encoder, configuration: Double) throws { + func encode(to encoder: Encoder, context: EncodingContext) throws { var container = encoder.unkeyedContainer() try container.encodeNil() - try container.encode(configuration) + try container.encode(context) } } @@ -174,9 +172,9 @@ private struct DecObj: Equatable, Decodable { var enc: EncObj { EncObj(int: int.enc, array: array.enc, null: null.enc, string: string) } - var config: EncObj.EncodingConfiguration { - (date: array.config, int: simpleInt, - string: int.config, double: null.config) + var context: EncObj.EncodingContext { + (date: array.context, int: simpleInt, + string: int.context, double: null.context) } } @@ -190,7 +188,7 @@ private struct DecIntAndStr: Equatable, Decodable { } var enc: EncIntAndStr { EncIntAndStr(int: int) } - var config: EncIntAndStr.EncodingConfiguration { string } + var context: EncIntAndStr.EncodingContext { string } } private struct DecArrayAndDate: Equatable, Decodable { @@ -203,7 +201,7 @@ private struct DecArrayAndDate: Equatable, Decodable { } var enc: EncArrayAndDate { EncArrayAndDate(array: array) } - var config: EncArrayAndDate.EncodingConfiguration { date } + var context: EncArrayAndDate.EncodingContext { date } } private struct DecNullAndDouble: Equatable, Decodable { @@ -221,5 +219,5 @@ private struct DecNullAndDouble: Equatable, Decodable { } var enc: EncNullAndDouble { EncNullAndDouble() } - var config: EncNullAndDouble.EncodingConfiguration { double } + var context: EncNullAndDouble.EncodingContext { double } }