Slide 29
Slide 29 text
Implementation of DictionaryEncoder
import Foundation
open class DictionaryEncoder: Encoder {
open var codingPath: [CodingKey] = []
open var userInfo: [CodingUserInfoKey: Any] = [:]
private var storage = Storage()
public init() {}
open func container(keyedBy type: Key.Type) -> KeyedEncodingContainer {
return KeyedEncodingContainer(KeyedContainer(encoder: self, codingPath: codingPath))
}
open func unkeyedContainer() -> UnkeyedEncodingContainer {
return UnkeyedContanier(encoder: self, codingPath: codingPath)
}
open func singleValueContainer() -> SingleValueEncodingContainer {
return UnkeyedContanier(encoder: self, codingPath: codingPath)
}
private func box(_ value: T) throws -> Any {
try value.encode(to: self)
return storage.popContainer()
}
}
extension DictionaryEncoder {
open func encode(_ value: T) throws -> [String: Any] {
do {
return try castOrThrow([String: Any].self, try box(value))
} catch (let error) {
throw EncodingError.invalidValue(value,
EncodingError.Context(codingPath: [],
debugDescription: "Top-evel \(T.self) did not encode any values.",
underlyingError: error)
)
}
}
}
extension DictionaryEncoder {
private class KeyedContainer: KeyedEncodingContainerProtocol {
private var encoder: DictionaryEncoder
private(set) var codingPath: [CodingKey]
private var storage: Storage
init(encoder: DictionaryEncoder, codingPath: [CodingKey]) {
self.encoder = encoder
self.codingPath = codingPath
self.storage = encoder.storage
storage.push(container: [:] as [String: Any])
}
deinit {
guard let dictionary = storage.popContainer() as? [String: Any] else {
assertionFailure(); return
}
storage.push(container: dictionary)
}
private func set(_ value: Any, forKey key: String) {
guard var dictionary = storage.popContainer() as? [String: Any] else { assertionFailure(); return }
dictionary[key] = value
storage.push(container: dictionary)
}
func encodeNil(forKey key: Key) throws {}
func encode(_ value: Bool, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Int, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Int8, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Int16, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Int32, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Int64, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: UInt, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: UInt8, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: UInt16, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: UInt32, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: UInt64, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Float, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: Double, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: String, forKey key: Key) throws { set(value, forKey: key.stringValue) }
func encode(_ value: T, forKey key: Key) throws {
encoder.codingPath.append(key)
defer { encoder.codingPath.removeLast() }
set(try encoder.box(value), forKey: key.stringValue)
}
func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer {
codingPath.append(key)
defer { codingPath.removeLast() }
return KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath))
}
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
codingPath.append(key)
defer { codingPath.removeLast() }
return UnkeyedContanier(encoder: encoder, codingPath: codingPath)
}
func superEncoder() -> Encoder {
return encoder
}
func superEncoder(forKey key: Key) -> Encoder {
return encoder
}
}
private class UnkeyedContanier: UnkeyedEncodingContainer, SingleValueEncodingContainer {
var encoder: DictionaryEncoder
private(set) var codingPath: [CodingKey]
private var storage: Storage
var count: Int { return (storage.last as? [Any])?.count ?? 0 }
init(encoder: DictionaryEncoder, codingPath: [CodingKey]) {
self.encoder = encoder
self.codingPath = codingPath
self.storage = encoder.storage
storage.push(container: [] as [Any])
}
deinit {
guard let array = storage.popContainer() as? [Any] else {
assertionFailure(); return
}
storage.push(container: array)
}
private func push(_ value: Any) {
guard var array = storage.popContainer() as? [Any] else { assertionFailure(); return }
array.append(value)
storage.push(container: array)
}
func encodeNil() throws {}
func encode(_ value: Bool) throws {}
func encode(_ value: Int) throws { push(value) }
func encode(_ value: Int8) throws { push(value) }
func encode(_ value: Int16) throws { push(value) }
func encode(_ value: Int32) throws { push(value) }
func encode(_ value: Int64) throws { push(value) }
func encode(_ value: UInt) throws { push(value) }
func encode(_ value: UInt8) throws { push(value) }
func encode(_ value: UInt16) throws { push(value) }
func encode(_ value: UInt32) throws { push(value) }
func encode(_ value: UInt64) throws { push(value) }
func encode(_ value: Float) throws { push(value) }
func encode(_ value: Double) throws { push(value) }
func encode(_ value: String) throws { push(value) }
func encode(_ value: T) throws {
encoder.codingPath.append(AnyCodingKey(index: count))
defer { encoder.codingPath.removeLast() }
push(try encoder.box(value))
}
func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey : CodingKey {
codingPath.append(AnyCodingKey(index: count))
defer { codingPath.removeLast() }
return KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath))
}
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
codingPath.append(AnyCodingKey(index: count))
defer { codingPath.removeLast() }
return UnkeyedContanier(encoder: encoder, codingPath: codingPath)
}
func superEncoder() -> Encoder {
return encoder
}
}
}
final class Storage {
private(set) var containers: [Any] = []
var count: Int {
return containers.count
}
var last: Any? {
return containers.last
}
func push(container: Any) {
containers.append(container)
}
@discardableResult
func popContainer() -> Any {
precondition(containers.count > 0, "Empty container stack.")
return containers.popLast()!
}
}
struct AnyCodingKey : CodingKey {
public var stringValue: String
public var intValue: Int?
public init?(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
public init?(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
init(index: Int) {
self.stringValue = "Index \(index)"
self.intValue = index
}
static let `super` = AnyCodingKey(stringValue: "super")!
}
public enum MoreCodableError: Error {
case cast
case unwrapped
case tryValue
}
func castOrThrow(_ resultType: T.Type, _ object: Any, error: Error = MoreCodableError.cast) throws -> T {
guard let returnValue = object as? T else {
throw error
}
return returnValue
}
extension Optional {
func unwrapOrThrow(error: Error = MoreCodableError.unwrapped) throws -> Wrapped {
guard let unwrapped = self else {
throw error
}
return unwrapped
}
}
extension Dictionary {
func tryValue(forKey key: Key, error: Error = MoreCodableError.tryValue) throws -> Value {
guard let value = self[key] else { throw error }
return value
}
}
M
ake
sense?