Skip to content

Instantly share code, notes, and snippets.

@avaidyam
Last active May 29, 2021 13:46
Show Gist options
  • Save avaidyam/a51845eeb9b69303e3a9abb73448d847 to your computer and use it in GitHub Desktop.
Save avaidyam/a51845eeb9b69303e3a9abb73448d847 to your computer and use it in GitHub Desktop.
Key-Value Encoding in Swift 4
import Foundation
import XCTest
class TestKeyValueEncoder : XCTestCase {
func testEncodingTopLevelEmptyStruct() {
let empty = EmptyStruct()
_testRoundTrip(of: empty)
}
func testEncodingTopLevelEmptyClass() {
let empty = EmptyClass()
_testRoundTrip(of: empty)
}
func testEncodingTopLevelSingleValueEnum() {
let s1 = Switch.off
/*_testEncodeFailure*/_testRoundTrip(of: s1)
_testRoundTrip(of: TopLevelWrapper(s1))
let s2 = Switch.on
/*_testEncodeFailure*/_testRoundTrip(of: s2)
_testRoundTrip(of: TopLevelWrapper(s2))
}
func testEncodingTopLevelSingleValueStruct() {
let t = Timestamp(3141592653)
/*_testEncodeFailure*/_testRoundTrip(of: t)
_testRoundTrip(of: TopLevelWrapper(t))
}
func testEncodingTopLevelSingleValueClass() {
let c = Counter()
/*_testEncodeFailure*/_testRoundTrip(of: c)
_testRoundTrip(of: TopLevelWrapper(c))
}
func testEncodingTopLevelStructuredStruct() {
// Address is a struct type with multiple fields.
let address = Address.testValue
_testRoundTrip(of: address)
}
func testEncodingTopLevelStructuredClass() {
// Person is a class with multiple fields.
let person = Person.testValue
_testRoundTrip(of: person)
}
func testEncodingTopLevelStructuredSingleStruct() {
// Numbers is a struct which encodes as an array through a single value container.
let numbers = Numbers.testValue
_testRoundTrip(of: numbers)
}
func testEncodingTopLevelStructuredSingleClass() {
// Mapping is a class which encodes as a dictionary through a single value container.
let mapping = Mapping.testValue
_testRoundTrip(of: mapping)
}
func testEncodingTopLevelDeepStructuredType() {
// Company is a type with fields which are Codable themselves.
let company = Company.testValue
_testRoundTrip(of: company)
}
func testEncodingClassWhichSharesEncoderWithSuper() {
// Employee is a type which shares its encoder & decoder with its superclass, Person.
//let employee = Employee.testValue
//_testRoundTrip(of: employee)
}
func testEncodingTopLevelNullableType() {
// EnhancedBool is a type which encodes either as a Bool or as nil.
/*_testEncodeFailure*/_testRoundTrip(of: EnhancedBool.true)
/*_testEncodeFailure*/_testRoundTrip(of: EnhancedBool.false)
/*_testEncodeFailure*/_testRoundTrip(of: EnhancedBool.fileNotFound)
_testRoundTrip(of: TopLevelWrapper(EnhancedBool.true))
_testRoundTrip(of: TopLevelWrapper(EnhancedBool.false))
_testRoundTrip(of: TopLevelWrapper(EnhancedBool.fileNotFound))
}
func testNestedContainerCodingPaths() {
let encoder = KeyValueEncoder(options: [.primitiveRootValues, .multipleRootContainers, .overwriteDuplicates])
do {
let _ = try encoder.encode(NestedContainersTestType())
} catch let error as NSError {
XCTAssert(false, "Caught error during encoding nested container types: \(error)")
}
}
func testSuperEncoderCodingPaths() {
let encoder = KeyValueEncoder(options: [.primitiveRootValues, .multipleRootContainers, .overwriteDuplicates])
do {
let _ = try encoder.encode(NestedContainersTestType(testSuperEncoder: true))
} catch let error as NSError {
XCTAssert(false, "Caught error during encoding nested container types: \(error)")
}
}
//
//
//
// TODO: Check if this === actual value
private func _testRoundTrip<T : Codable & Equatable>(of value: T) {
do {
let encoder = KeyValueEncoder(options: [.primitiveRootValues, .overwriteDuplicates])
let intermediate = try encoder.encode(value) as Any
let decoder = KeyValueDecoder(options: [.primitiveRootValues])
let output: T = try decoder.decode(intermediate) as T
XCTAssertEqual(value, output, "Encode <--> Decode pass expected identical results.")
} catch(let error) {
XCTAssert(false, "Encode of top-level \(T.self) was not expected to fail. \(error)")
}
}
private func _testEncodeFailure<T : Encodable>(of value: T) {
do {
let encoder = KeyValueEncoder(options: [.primitiveRootValues, .multipleRootContainers, .overwriteDuplicates])
let _ = try encoder.encode(value)
XCTAssert(false, "Encode of top-level \(T.self) was expected to fail.")
} catch {}
}
}
// MARK: - Helper Global Functions
func expectEqualPaths(_ lhs: [CodingKey?], _ rhs: [CodingKey?], _ prefix: String) {
if lhs.count != rhs.count {
XCTAssert(false, "\(prefix) [CodingKey?].count mismatch: \(lhs.count) != \(rhs.count)")
return
}
for (key1, key2) in zip(lhs, rhs) {
switch (key1?.intValue, key2?.intValue) {
case (.none, .none): break
case (.some(let i1), .none):
XCTAssert(false, "\(prefix) CodingKey.intValue mismatch: \(type(of: key1))(\(i1)) != nil")
return
case (.none, .some(let i2)):
XCTAssert(false, "\(prefix) CodingKey.intValue mismatch: nil != \(type(of: key2))(\(i2))")
return
case (.some(let i1), .some(let i2)):
guard i1 == i2 else {
XCTAssert(false, "\(prefix) CodingKey.intValue mismatch: \(type(of: key1))(\(i1)) != \(type(of: key2))(\(i2))")
return
}
break
}
XCTAssertEqual(key1?.stringValue, key2?.stringValue, "\(prefix) CodingKey.stringValue mismatch: \(type(of: key1))('\(String(describing: key1?.stringValue))') != \(type(of: key2))('\(String(describing: key2?.stringValue))')")
}
}
// MARK: - Test Types
/* FIXME: Import from %S/Inputs/Coding/SharedTypes.swift somehow. */
// MARK: - Empty Types
fileprivate struct EmptyStruct : Codable, Equatable {
static func ==(_ lhs: EmptyStruct, _ rhs: EmptyStruct) -> Bool {
return true
}
}
fileprivate class EmptyClass : Codable, Equatable {
static func ==(_ lhs: EmptyClass, _ rhs: EmptyClass) -> Bool {
return true
}
}
// MARK: - Single-Value Types
/// A simple on-off switch type that encodes as a single Bool value.
fileprivate enum Switch : Codable {
case off
case on
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
switch try container.decode(Bool.self) {
case false: self = .off
case true: self = .on
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .off: try container.encode(false)
case .on: try container.encode(true)
}
}
}
/// A simple timestamp type that encodes as a single Double value.
fileprivate struct Timestamp : Codable, Equatable {
let value: Double
init(_ value: Double) {
self.value = value
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
value = try container.decode(Double.self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.value)
}
static func ==(_ lhs: Timestamp, _ rhs: Timestamp) -> Bool {
return lhs.value == rhs.value
}
}
/// A simple referential counter type that encodes as a single Int value.
fileprivate final class Counter : Codable, Equatable {
var count: Int = 0
init() {}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
count = try container.decode(Int.self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.count)
}
static func ==(_ lhs: Counter, _ rhs: Counter) -> Bool {
return lhs === rhs || lhs.count == rhs.count
}
}
// MARK: - Structured Types
/// A simple address type that encodes as a dictionary of values.
fileprivate struct Address : Codable, Equatable {
let street: String
let city: String
let state: String
let zipCode: Int
let country: String
init(street: String, city: String, state: String, zipCode: Int, country: String) {
self.street = street
self.city = city
self.state = state
self.zipCode = zipCode
self.country = country
}
static func ==(_ lhs: Address, _ rhs: Address) -> Bool {
return lhs.street == rhs.street &&
lhs.city == rhs.city &&
lhs.state == rhs.state &&
lhs.zipCode == rhs.zipCode &&
lhs.country == rhs.country
}
static var testValue: Address {
return Address(street: "1 Infinite Loop",
city: "Cupertino",
state: "CA",
zipCode: 95014,
country: "United States")
}
}
/// A simple person class that encodes as a dictionary of values.
fileprivate class Person : Codable, Equatable {
let name: String
let email: String
let website: URL?
init(name: String, email: String, website: URL? = nil) {
self.name = name
self.email = email
self.website = website
}
private enum CodingKeys : String, CodingKey {
case name
case email
case website
}
// FIXME: Remove when subclasses (Employee) are able to override synthesized conformance.
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
email = try container.decode(String.self, forKey: .email)
website = try container.decodeIfPresent(URL.self, forKey: .website)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(email, forKey: .email)
try container.encodeIfPresent(website, forKey: .website)
}
func isEqual(_ other: Person) -> Bool {
return self.name == other.name &&
self.email == other.email &&
self.website == other.website
}
static func ==(_ lhs: Person, _ rhs: Person) -> Bool {
return lhs.isEqual(rhs)
}
class var testValue: Person {
return Person(name: "Johnny Appleseed", email: "[email protected]")
}
}
/// A class which shares its encoder and decoder with its superclass.
fileprivate class Employee : Person {
let id: Int
init(name: String, email: String, website: URL? = nil, id: Int) {
self.id = id
super.init(name: name, email: email, website: website)
}
enum CodingKeys : String, CodingKey {
case id
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try super.encode(to: encoder)
}
override func isEqual(_ other: Person) -> Bool {
if let employee = other as? Employee {
guard self.id == employee.id else { return false }
}
return super.isEqual(other)
}
override class var testValue: Employee {
return Employee(name: "Johnny Appleseed", email: "[email protected]", id: 42)
}
}
/// A simple company struct which encodes as a dictionary of nested values.
fileprivate struct Company : Codable, Equatable {
let address: Address
var employees: [Employee]
init(address: Address, employees: [Employee]) {
self.address = address
self.employees = employees
}
static func ==(_ lhs: Company, _ rhs: Company) -> Bool {
return lhs.address == rhs.address && lhs.employees == rhs.employees
}
static var testValue: Company {
return Company(address: Address.testValue, employees: [Employee.testValue])
}
}
/// An enum type which decodes from Bool?.
fileprivate enum EnhancedBool : Codable {
case `true`
case `false`
case fileNotFound
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self = .fileNotFound
} else {
let value = try container.decode(Bool.self)
self = value ? .true : .false
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .true: try container.encode(true)
case .false: try container.encode(false)
case .fileNotFound: try container.encodeNil()
}
}
}
/// A type which encodes as an array directly through a single value container.
struct Numbers : Codable, Equatable {
let values = [4, 8, 15, 16, 23, 42]
init() {}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let decodedValues = try container.decode([Int].self)
guard decodedValues == values else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "The Numbers are wrong!"))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(values)
}
static func ==(_ lhs: Numbers, _ rhs: Numbers) -> Bool {
return lhs.values == rhs.values
}
static var testValue: Numbers {
return Numbers()
}
}
/// A type which encodes as a dictionary directly through a single value container.
fileprivate final class Mapping : Codable, Equatable {
let values: [String : URL]
init(values: [String : URL]) {
self.values = values
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
values = try container.decode([String : URL].self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(values)
}
static func ==(_ lhs: Mapping, _ rhs: Mapping) -> Bool {
return lhs === rhs || lhs.values == rhs.values
}
static var testValue: Mapping {
return Mapping(values: ["Apple": URL(string: "http://apple.com")!,
"localhost": URL(string: "http://127.0.0.1")!])
}
}
struct NestedContainersTestType : Encodable {
let testSuperEncoder: Bool
init(testSuperEncoder: Bool = false) {
self.testSuperEncoder = testSuperEncoder
}
enum TopLevelCodingKeys : Int, CodingKey {
case a
case b
case c
}
enum IntermediateCodingKeys : Int, CodingKey {
case one
case two
}
func encode(to encoder: Encoder) throws {
if self.testSuperEncoder {
var topLevelContainer = encoder.container(keyedBy: TopLevelCodingKeys.self)
expectEqualPaths(encoder.codingPath, [], "Top-level Encoder's codingPath changed.")
expectEqualPaths(topLevelContainer.codingPath, [], "New first-level keyed container has non-empty codingPath.")
let superEncoder = topLevelContainer.superEncoder(forKey: .a)
expectEqualPaths(encoder.codingPath, [], "Top-level Encoder's codingPath changed.")
expectEqualPaths(topLevelContainer.codingPath, [], "First-level keyed container's codingPath changed.")
expectEqualPaths(superEncoder.codingPath, [TopLevelCodingKeys.a], "New superEncoder had unexpected codingPath.")
_testNestedContainers(in: superEncoder, baseCodingPath: [TopLevelCodingKeys.a])
} else {
_testNestedContainers(in: encoder, baseCodingPath: [])
}
}
func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey?]) {
expectEqualPaths(encoder.codingPath, baseCodingPath, "New encoder has non-empty codingPath.")
// codingPath should not change upon fetching a non-nested container.
var firstLevelContainer = encoder.container(keyedBy: TopLevelCodingKeys.self)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "New first-level keyed container has non-empty codingPath.")
// Nested Keyed Container
do {
// Nested container for key should have a new key pushed on.
var secondLevelContainer = firstLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self, forKey: .a)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "New second-level keyed container had unexpected codingPath.")
// Inserting a keyed container should not change existing coding paths.
let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self, forKey: .one)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "Second-level keyed container's codingPath changed.")
expectEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, IntermediateCodingKeys.one], "New third-level keyed container had unexpected codingPath.")
// Inserting an unkeyed container should not change existing coding paths.
let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer(forKey: .two)
expectEqualPaths(encoder.codingPath, baseCodingPath + [], "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath + [], "First-level keyed container's codingPath changed.")
expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "Second-level keyed container's codingPath changed.")
expectEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, IntermediateCodingKeys.two], "New third-level unkeyed container had unexpected codingPath.")
}
// Nested Unkeyed Container
do {
// Nested container for key should have a new key pushed on.
var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .b)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "New second-level keyed container had unexpected codingPath.")
// Appending a keyed container should not change existing coding paths.
let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "Second-level unkeyed container's codingPath changed.")
expectEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, nil], "New third-level keyed container had unexpected codingPath.")
// Appending an unkeyed container should not change existing coding paths.
let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer()
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "Second-level unkeyed container's codingPath changed.")
expectEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, nil], "New third-level unkeyed container had unexpected codingPath.")
}
}
}
// MARK: - Helper Types
/// Wraps a type T so that it can be encoded at the top level of a payload.
fileprivate struct TopLevelWrapper<T: Codable & Equatable>: Codable, Equatable {
let value: T
init(_ value: T) {
self.value = value
}
static func ==(_ lhs: TopLevelWrapper<T>, _ rhs: TopLevelWrapper<T>) -> Bool {
return lhs.value == rhs.value
}
}
/* TODO: Support sharing the Coder with super. */
//
// MARK: KeyValueDecoder
//
///
public class KeyValueDecoder {
///
public struct Options: OptionSet {
public typealias RawValue = Int
public var rawValue: Int
public init(rawValue: RawValue) {
self.rawValue = rawValue
}
///
public static let multipleRootContainers = Options(rawValue: 1 << 0)
///
public static let primitiveRootValues = Options(rawValue: 1 << 1)
}
public let options: Options
public init(options: Options = []) {
self.options = options
}
private var root: DecoderContainer? = nil
public func decode<T: Decodable>(_ value: Any) throws -> T {
self.root = DecoderContainer(owner: self, codingPath: [], content: value)
return try T(from: self.root!)
}
//
// MARK: KeyValueDecoder -> KeyedContainer
//
///
private class KeyedContainer<Key: CodingKey>: KeyedDecodingChildContainer {
internal class Box {
var content: [DecodingChildContainer] = []
}
var codingPath: [CodingKey?]
var children = Box()
private let content: [String: Any]
let owner: KeyValueDecoder
init(owner: KeyValueDecoder, codingPath: [CodingKey?], content: [String: Any]) {
self.owner = owner
self.codingPath = codingPath
self.content = content
}
//
// MARK: KeyValueDecoder -> KeyedContainer -> Decoding
//
func decodeValue<T: Decodable>(forKey key: Key) throws -> T? {
guard let outerValue = self.content[key.value()] else {
return nil
}
guard let value = outerValue as? T else {
let desc = "Expected type \(T.self) but container stored value \(outerValue)."
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
return value
}
//
// MARK: KeyValueDecoder -> KeyedContainer -> ChildContainer
//
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
guard let outerValue = self.content[key.value()] else {
let desc = "No element matching key \(key) in the container."
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
guard let inside = outerValue as? [String: Any] else {
let desc = "Expected type \(Dictionary<String, Any>.self) but container stored value \(outerValue)."
throw DecodingError.typeMismatch(Dictionary<String, Any>.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = KeyedContainer<NestedKey>(owner: self.owner, codingPath: self.codingPath + [key], content: inside)
self.children.content.append(container)
return KeyedDecodingContainer(container)
}
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
guard let outerValue = self.content[key.value()] else {
let desc = "No element matching key \(key) in the container."
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
guard let inside = outerValue as? [Any] else {
let desc = "Expected type \(Array<Any>.self) but container stored value \(outerValue)."
throw DecodingError.typeMismatch(Array<Any>.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = UnkeyedContainer(owner: self.owner, codingPath: self.codingPath + [key], content: inside)
self.children.content.append(container)
return container
}
func superDecoder() throws -> Decoder {
let key = Key(stringValue: "super")! // or Key(intValue: 0)
return try self.superDecoder(forKey: key)
}
func superDecoder(forKey key: Key) throws -> Decoder {
guard let inside = self.content[key.value()] else {
let desc = "No superDecoder element found in the container."
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = DecoderContainer(owner: self.owner, codingPath: self.codingPath + [key], content: inside)
self.children.content.append(container)
return container
}
//
// MARK: KeyValueDecoder -> KeyedContainer -> Misc
//
var allKeys: [Key] {
return Array(self.content.keys).flatMap { Key(stringValue: $0) }
}
func contains(_ key: Key) -> Bool {
return self.content.keys.contains(key.value())
}
}
//
// MARK: KeyValueDecoder -> UnkeyedContainer
//
///
private class UnkeyedContainer: UnkeyedDecodingChildContainer {
private let content: [Any]
var codingPath: [CodingKey?]
var count: Int? = nil
var children: [DecodingChildContainer] = []
let owner: KeyValueDecoder
init(owner: KeyValueDecoder, codingPath: [CodingKey?], content: [Any]) {
self.owner = owner
self.codingPath = codingPath
self.content = content
self.count = content.count
}
//
// MARK: KeyValueDecoder -> UnkeyedContainer -> Decoding
//
func decodeValue<T: Decodable>() throws -> T? {
guard let count = self.count, count > 0 else {
return nil
}
let outerValue = self.content[self.content.count - count]
guard let value = outerValue as? T else {
let desc = "Expected type \(T.self) but container stored value \(outerValue)."
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
self.count = count - 1 // decrement
return value
}
//
// MARK: KeyValueDecoder -> UnkeyedContainer -> ChildContainer
//
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
guard let count = self.count, count > 0 else {
let desc = "No more elements remaining in the container."
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let outerValue = self.content[self.content.count - count]
guard let inside = outerValue as? [String: Any] else {
let desc = "Expected type \(Dictionary<String, Any>.self) but container stored value \(outerValue)."
throw DecodingError.typeMismatch(Dictionary<String, Any>.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = KeyedContainer<NestedKey>(owner: self.owner, codingPath: self.codingPath + [nil], content: inside)
self.children.append(container)
self.count = count - 1 // decrement
return KeyedDecodingContainer(container)
}
func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
guard let count = self.count, count > 0 else {
let desc = "No more elements remaining in the container."
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let outerValue = self.content[self.content.count - count]
guard let inside = outerValue as? [Any] else {
let desc = "Expected type \(Array<Any>.self) but container stored value \(outerValue)."
throw DecodingError.typeMismatch(Array<Any>.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = UnkeyedContainer(owner: self.owner, codingPath: self.codingPath + [nil], content: inside)
self.children.append(container)
self.count = count - 1 // decrement
return container
}
func superDecoder() throws -> Decoder {
guard let count = self.count, count > 0 else {
let desc = "No more elements remaining in the container."
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let outerValue = self.content[self.content.count - count]
let container = DecoderContainer(owner: self.owner, codingPath: self.codingPath + [nil], content: outerValue)
self.children.append(container)
self.count = count - 1 // decrement
return container
}
//
// MARK: KeyValueDecoder -> UnkeyedContainer -> Misc
//
var isAtEnd: Bool {
return self.count == nil || self.count == 0
}
}
//
// MARK: KeyValueDecoder -> SingleValueContainer
//
///
private class SingleValueContainer: SingleValueDecodingChildContainer {
private let content: Any
fileprivate var children: [DecodingChildContainer] {
get { return [] } set { }
}
let owner: KeyValueDecoder
init(owner: KeyValueDecoder, content: Any) {
self.owner = owner
self.content = content
}
//
// MARK: KeyValueDecoder -> SingleValueContainer -> Decoding
//
func decodeNil() -> Bool {
if case Optional<Any>.none = self.content {
return true
} else if case Optional<Any>.some(_) = self.content {
return false
}
return false // uh...?
}
func decodeValue<T: Decodable>() throws -> T {
guard case Optional<Any>.some(_) = self.content else {
let desc = "Expected type \(T.self) but container stored nil."
throw DecodingError.valueNotFound(T.self, DecodingError.Context(codingPath: [], debugDescription: desc))
}
guard let value = self.content as? T else {
let desc = "Expected type \(T.self) but container stored value \(self.content)."
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: [], debugDescription: desc))
}
return value
}
}
//
// MARK: KeyValueDecoder -> DecoderContainer
//
private class DecoderContainer: DecoderDecodingChildContainer {
internal class Box {
var content: [DecodingChildContainer] = []
}
public var codingPath: [CodingKey?]
public var userInfo: [CodingUserInfoKey : Any] = [:]
fileprivate let owner: KeyValueDecoder
internal var children = Box()
fileprivate var content: Any = Optional<Any>.none as Any
fileprivate init(owner: KeyValueDecoder, codingPath: [CodingKey?], content: Any) {
self.owner = owner
self.codingPath = codingPath
self.content = content
}
//
// MARK: KeyValueDecoder -> DecoderContainer -> ChildContainer
//
public func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
try! throwIfExists()
guard let inside = self.content as? [String: Any] else {
let desc = "This decoder's content could not support a keyed container."
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = KeyedContainer<Key>(owner: self.owner, codingPath: self.codingPath, content: inside)
self.children.content.append(container)
return KeyedDecodingContainer(container)
}
public func unkeyedContainer() throws -> UnkeyedDecodingContainer {
try! throwIfExists()
guard let inside = self.content as? [Any] else {
let desc = "This decoder's content could not support an unkeyed container."
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
let container = UnkeyedContainer(owner: self.owner, codingPath: self.codingPath, content: inside)
self.children.content.append(container)
return container
}
public func singleValueContainer() throws -> SingleValueDecodingContainer {
try! throwIfExists()
if !self.owner.options.contains(.primitiveRootValues) {
fatalError("This decoder does not support primitive root values.")
}
let container = SingleValueContainer(owner: self.owner, content: self.content)
self.children.content.append(container)
return container
}
//
// MARK: KeyValueDecoder -> DecoderContainer -> Misc
//
private func throwIfExists() throws {
if self.children.content.count > 0 && !self.owner.options.contains(.multipleRootContainers) {
let desc = "This decoder is not configured to support multiple root containers."
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
}
}
}
//
// MARK: Helpers
//
///
fileprivate extension CodingKey {
func value() -> String {
return self.stringValue
}
func value() -> Int {
if let i = self.intValue { return i }
fatalError("requires an integer coding key")
}
}
///
fileprivate protocol DecodingChildContainer {}
fileprivate protocol DecoderDecodingChildContainer: Decoder, DecodingChildContainer {}
fileprivate protocol KeyedDecodingChildContainer: KeyedDecodingContainerProtocol, DecodingChildContainer {
func decodeValue<T: Decodable>(forKey: Key) throws -> T?
}
fileprivate protocol UnkeyedDecodingChildContainer: UnkeyedDecodingContainer, DecodingChildContainer {
mutating func decodeValue<T: Decodable>() throws -> T?
}
fileprivate protocol SingleValueDecodingChildContainer: SingleValueDecodingContainer, DecodingChildContainer {
func decodeNil() -> Bool
func decodeValue<T: Decodable>() throws -> T
}
fileprivate extension KeyedDecodingChildContainer {
func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Int.Type, forKey key: Key) throws -> Int? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Int8.Type, forKey key: Key) throws -> Int8? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Int16.Type, forKey key: Key) throws -> Int16? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Int32.Type, forKey key: Key) throws -> Int32? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Int64.Type, forKey key: Key) throws -> Int64? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: UInt.Type, forKey key: Key) throws -> UInt? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: UInt8.Type, forKey key: Key) throws -> UInt8? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: UInt16.Type, forKey key: Key) throws -> UInt16? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: UInt32.Type, forKey key: Key) throws -> UInt32? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: UInt64.Type, forKey key: Key) throws -> UInt64? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Float.Type, forKey key: Key) throws -> Float? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: Double.Type, forKey key: Key) throws -> Double? {
return try decodeValue(forKey: key)
}
func decodeIfPresent(_ type: String.Type, forKey key: Key) throws -> String? {
return try decodeValue(forKey: key)
}
func decodeIfPresent<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T? {
return try decodeValue(forKey: key)
}
}
fileprivate extension UnkeyedDecodingChildContainer {
mutating func decodeIfPresent(_ type: Bool.Type) throws -> Bool? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Int.Type) throws -> Int? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Int8.Type) throws -> Int8? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Int16.Type) throws -> Int16? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Int32.Type) throws -> Int32? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Int64.Type) throws -> Int64? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: UInt.Type) throws -> UInt? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: UInt8.Type) throws -> UInt8? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: UInt16.Type) throws -> UInt16? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: UInt32.Type) throws -> UInt32? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: UInt64.Type) throws -> UInt64? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Float.Type) throws -> Float? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: Double.Type) throws -> Double? {
return try decodeValue()
}
mutating func decodeIfPresent(_ type: String.Type) throws -> String? {
return try decodeValue()
}
mutating func decodeIfPresent<T: Decodable>(_ type: T.Type) throws -> T? {
return try decodeValue()
}
}
fileprivate extension SingleValueDecodingChildContainer {
func decode(_ type: Bool.Type) throws -> Bool {
return try decodeValue()
}
func decode(_ type: Int.Type) throws -> Int {
return try decodeValue()
}
func decode(_ type: Int8.Type) throws -> Int8 {
return try decodeValue()
}
func decode(_ type: Int16.Type) throws -> Int16 {
return try decodeValue()
}
func decode(_ type: Int32.Type) throws -> Int32 {
return try decodeValue()
}
func decode(_ type: Int64.Type) throws -> Int64 {
return try decodeValue()
}
func decode(_ type: UInt.Type) throws -> UInt {
return try decodeValue()
}
func decode(_ type: UInt8.Type) throws -> UInt8 {
return try decodeValue()
}
func decode(_ type: UInt16.Type) throws -> UInt16 {
return try decodeValue()
}
func decode(_ type: UInt32.Type) throws -> UInt32 {
return try decodeValue()
}
func decode(_ type: UInt64.Type) throws -> UInt64 {
return try decodeValue()
}
func decode(_ type: Float.Type) throws -> Float {
return try decodeValue()
}
func decode(_ type: Double.Type) throws -> Double {
return try decodeValue()
}
func decode(_ type: String.Type) throws -> String {
return try decodeValue()
}
func decode<T: Decodable>(_ type: T.Type) throws -> T {
return try decodeValue()
}
}
/* TODO: Support sharing the Coder with super. */
//
// MARK: KeyValueEncoder
//
///
public class KeyValueEncoder {
///
public struct Options: OptionSet {
public typealias RawValue = Int
public var rawValue: Int
public init(rawValue: RawValue) {
self.rawValue = rawValue
}
///
public static let multipleRootContainers = Options(rawValue: 1 << 0)
///
public static let primitiveRootValues = Options(rawValue: 1 << 1)
///
public static let overwriteDuplicates = Options(rawValue: 1 << 2)
}
public let options: Options
public init(options: Options = []) {
self.options = options
}
private var root: EncoderContainer? = nil
public func encode<T: Encodable>(_ value: T) throws -> Any {
self.root = EncoderContainer(owner: self, codingPath: [])
try value.encode(to: self.root!)
return self.root!.values()
}
//
// MARK: KeyValueEncoder -> KeyedContainer
//
///
private class KeyedContainer<Key: CodingKey>: KeyedEncodingChildContainer {
let owner: KeyValueEncoder
var codingPath: [CodingKey?]
var children: [String: EncodingChildContainer] = [:]
var content: [String: Encodable] = [:]
init(owner: KeyValueEncoder, codingPath: [CodingKey?]) {
self.owner = owner
self.codingPath = codingPath
}
//
// MARK: KeyValueEncoder -> KeyedContainer -> Encoding
//
func encode<T: Encodable>(value: T, forKey key: Key) throws {
if let _ = self.content.index(forKey: key.value()), !self.owner.options.contains(.overwriteDuplicates) {
let desc = "Key \(key) already exists in the container."
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
self.content[key.value()] = value
}
func values() -> Any {
var values = self.content as [String: Any]
let childValues = self.children.mapValues { $0.values() }
childValues.forEach { values[$0.key] = $0.value }
return values
}
//
// MARK: KeyValueEncoder -> KeyedContainer -> ChildContainer
//
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
let container = KeyedContainer<NestedKey>(owner: self.owner, codingPath: self.codingPath + [key])
self.children[key.value()] = container
return KeyedEncodingContainer(container)
}
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
let container = UnkeyedContainer(owner: self.owner, codingPath: self.codingPath + [key])
self.children[key.value()] = container
return container
}
func superEncoder() -> Encoder {
let key = Key(stringValue: "super")! // or Key(intValue: 0)
return self.superEncoder(forKey: key)
}
func superEncoder(forKey key: Key) -> Encoder {
let container = EncoderContainer(owner: self.owner, codingPath: self.codingPath + [key])
self.children[key.value()] = container
return container
}
}
//
// MARK: KeyValueEncoder -> UnkeyedContainer
//
///
private class UnkeyedContainer: UnkeyedEncodingChildContainer {
let owner: KeyValueEncoder
var codingPath: [CodingKey?]
var children: [EncodingChildContainer] = []
var content: [Encodable] = []
init(owner: KeyValueEncoder, codingPath: [CodingKey?]) {
self.owner = owner
self.codingPath = codingPath
}
//
// MARK: KeyValueEncoder -> UnkeyedContainer -> Encoding
//
func encode<T: Encodable>(value: T) throws {
self.content.append(value)
}
func values() -> Any {
return (self.content as [Any]) + self.children.map { $0.values() }
}
//
// MARK: KeyValueEncoder -> UnkeyedContainer -> ChildContainer
//
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
let container = KeyedContainer<NestedKey>(owner: self.owner, codingPath: self.codingPath + [nil])
self.children.append(container)
return KeyedEncodingContainer(container)
}
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
let container = UnkeyedContainer(owner: self.owner, codingPath: self.codingPath + [nil])
self.children.append(container)
return container
}
func superEncoder() -> Encoder {
let container = EncoderContainer(owner: self.owner, codingPath: self.codingPath + [nil])
self.children.append(container)
return container
}
//
// MARK: KeyValueEncoder -> UnkeyedContainer -> Misc
//
/*
func throwIfExists<T: Encodable>(_ value: T, forKey key: Key) throws {
if let _ = self.content.index(forKey: key.value()) {
let desc = "Key \(key) already exists in the container."
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
}
*/
}
//
// MARK: KeyValueEncoder -> SingleValueContainer
//
///
private class SingleValueContainer: SingleValueEncodingChildContainer {
fileprivate var children: [EncodingChildContainer] {
get { return [] } set { }
}
var content: [Encodable] = [] // strange way to not deal with Optional.
let owner: KeyValueEncoder
init(owner: KeyValueEncoder) {
self.owner = owner
}
//
// MARK: KeyValueEncoder -> SingleValueContainer -> Encoding
//
func encodeNil() throws {
if self.content.count > 0 && !self.owner.options.contains(.overwriteDuplicates) {
let desc = "Value already exists in the container."
throw EncodingError.invalidValue(self.content[0] as Any, EncodingError.Context(codingPath: [], debugDescription: desc))
}
self.content = []
}
func encode<T: Encodable>(value: T) throws {
if self.content.count > 0 && !self.owner.options.contains(.overwriteDuplicates) {
let desc = "Value already exists in the container."
throw EncodingError.invalidValue(value as Any, EncodingError.Context(codingPath: [], debugDescription: desc))
}
self.content = [value]
}
func values() -> Any {
return self.content.first as Any
}
}
//
// MARK: KeyValueCoder -> EncoderContainer
//
private class EncoderContainer: EncoderEncodingChildContainer {
internal class Box {
var content: [EncodingChildContainer] = []
}
fileprivate let owner: KeyValueEncoder
public var codingPath: [CodingKey?]
public var userInfo: [CodingUserInfoKey : Any] = [:]
internal var children = Box()
init(owner: KeyValueEncoder, codingPath: [CodingKey?]) {
self.owner = owner
self.codingPath = codingPath
}
//
// MARK: KeyValueCoder -> EncoderContainer -> Encoding
//
// message, dictionary
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> {
try! throwIfExists()
let container = KeyedContainer<Key>(owner: self.owner, codingPath: self.codingPath)
self.children.content.append(container)
return KeyedEncodingContainer(container)
}
// array, set
func unkeyedContainer() -> UnkeyedEncodingContainer {
try! throwIfExists()
let container = UnkeyedContainer(owner: self.owner, codingPath: self.codingPath)
self.children.content.append(container)
return container
}
// values
func singleValueContainer() -> SingleValueEncodingContainer {
try! throwIfExists()
if !self.owner.options.contains(.primitiveRootValues) {
fatalError("This encoder does not support primitive root values.")
}
let container = SingleValueContainer(owner: self.owner)
self.children.content.append(container)
return container
}
//
// MARK: KeyValueCoder -> EncoderContainer -> Misc
//
private func throwIfExists() throws {
if self.children.content.count > 0 && !self.owner.options.contains(.multipleRootContainers) {
let desc = "This encoder is not configured to support multiple root containers."
throw EncodingError.invalidValue(self, EncodingError.Context(codingPath: self.codingPath, debugDescription: desc))
}
}
func values() -> Any {
if self.owner.options.contains(.multipleRootContainers) {
return self.children.content.map { $0.values() }
} else {
return self.children.content[0].values()
}
}
}
}
//
// MARK: Helpers
//
///
fileprivate extension CodingKey {
func value() -> String {
return self.stringValue
}
func value() -> Int {
if let i = self.intValue { return i }
fatalError("requires an integer coding key")
}
}
///
fileprivate protocol EncodingChildContainer {
///
func values() -> Any
}
fileprivate protocol EncoderEncodingChildContainer: Encoder, EncodingChildContainer {}
fileprivate protocol KeyedEncodingChildContainer: KeyedEncodingContainerProtocol, EncodingChildContainer {
mutating func encode<T: Encodable>(value: T, forKey: Key) throws
}
fileprivate protocol UnkeyedEncodingChildContainer: UnkeyedEncodingContainer, EncodingChildContainer {
mutating func encode<T: Encodable>(value: T) throws
}
fileprivate protocol SingleValueEncodingChildContainer: SingleValueEncodingContainer, EncodingChildContainer {
mutating func encodeNil() throws
mutating func encode<T: Encodable>(value: T) throws
}
fileprivate extension KeyedEncodingChildContainer {
mutating func encode(_ value: Bool, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Int, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Int8, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Int16, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Int32, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Int64, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: UInt, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: UInt8, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: UInt16, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: UInt32, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: UInt64, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Float, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: Double, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode(_ value: String, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
mutating func encode<T: Encodable>(_ value: T, forKey key: Key) throws {
try encode(value: value, forKey: key)
}
}
fileprivate extension UnkeyedEncodingChildContainer {
mutating func encode(_ value: Bool) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int8) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int16) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int32) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int64) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt8) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt16) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt32) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt64) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Float) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Double) throws {
try self.encode(value: value)
}
mutating func encode(_ value: String) throws {
try self.encode(value: value)
}
mutating func encode<T: Encodable>(_ value: T) throws {
try self.encode(value: value)
}
}
fileprivate extension SingleValueEncodingChildContainer {
mutating func encode(_ value: Bool) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int8) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int16) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int32) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Int64) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt8) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt16) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt32) throws {
try self.encode(value: value)
}
mutating func encode(_ value: UInt64) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Float) throws {
try self.encode(value: value)
}
mutating func encode(_ value: Double) throws {
try self.encode(value: value)
}
mutating func encode(_ value: String) throws {
try self.encode(value: value)
}
mutating func encode<T: Encodable>(_ value: T) throws {
try self.encode(value: value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment