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!
Add the following dependency to your Package.swift:
.package(url: "https://github.com/tesseract-one/ContextCodable.swift.git", from: "0.1.0")
Run swift build
and build your app.
Add the following to your Podfile:
pod 'ContextCodable.swift', '~> 0.1.0'
Then run pod install
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)!)
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)
ContextCodable.swift is available under the Apache 2.0 license. See the LICENSE file for more information.