407 lines
14 KiB
Swift
407 lines
14 KiB
Swift
//
|
|
// TrackingEncoder.swift
|
|
//
|
|
//
|
|
// Created by Sergej Jaskiewicz on 08.11.2019.
|
|
//
|
|
|
|
final class TrackingEncoder {
|
|
|
|
enum Event: Equatable {
|
|
// Encoder
|
|
case getCodingPath
|
|
case getUserInfo
|
|
case containerKeyedBy
|
|
case unkeyedContainer
|
|
case singleValueContainer
|
|
|
|
// KeyedEncodingContainerProtocol
|
|
case keyedContainerCodingPath
|
|
case keyedContainerEncodeNil(String)
|
|
case keyedContainerEncodeBool(Bool, String)
|
|
case keyedContainerEncodeString(String, String)
|
|
case keyedContainerEncodeDouble(Double, String)
|
|
case keyedContainerEncodeFloat(Float, String)
|
|
case keyedContainerEncodeInt(Int, String)
|
|
case keyedContainerEncodeInt8(Int8, String)
|
|
case keyedContainerEncodeInt16(Int16, String)
|
|
case keyedContainerEncodeInt32(Int32, String)
|
|
case keyedContainerEncodeInt64(Int64, String)
|
|
case keyedContainerEncodeUInt(UInt, String)
|
|
case keyedContainerEncodeUInt8(UInt8, String)
|
|
case keyedContainerEncodeUInt16(UInt16, String)
|
|
case keyedContainerEncodeUInt32(UInt32, String)
|
|
case keyedContainerEncodeUInt64(UInt64, String)
|
|
case keyedContainerEncodeEncodable(String)
|
|
case keyedContainerNestedKeyedContainer(String)
|
|
case keyedContainerNestedUnkeyedContainer(String)
|
|
case keyedContainerSuperEncoder
|
|
case keyedContainerSuperEncoderForKey(String)
|
|
|
|
// UnkeyedEncodingContainer
|
|
case unkeyedContainerCodingPath
|
|
case unkeyedContainerCount
|
|
case unkeyedContainerEncodeNil
|
|
case unkeyedContainerEncodeBool(Bool)
|
|
case unkeyedContainerEncodeString(String)
|
|
case unkeyedContainerEncodeDouble(Double)
|
|
case unkeyedContainerEncodeFloat(Float)
|
|
case unkeyedContainerEncodeInt(Int)
|
|
case unkeyedContainerEncodeInt8(Int8)
|
|
case unkeyedContainerEncodeInt16(Int16)
|
|
case unkeyedContainerEncodeInt32(Int32)
|
|
case unkeyedContainerEncodeInt64(Int64)
|
|
case unkeyedContainerEncodeUInt(UInt)
|
|
case unkeyedContainerEncodeUInt8(UInt8)
|
|
case unkeyedContainerEncodeUInt16(UInt16)
|
|
case unkeyedContainerEncodeUInt32(UInt32)
|
|
case unkeyedContainerEncodeUInt64(UInt64)
|
|
case unkeyedContainerEncodeEncodable
|
|
case unkeyedContainerNestedKeyedContainer
|
|
case unkeyedContainerNestedUnkeyedContainer
|
|
case unkeyedContainerSuperEncoder
|
|
|
|
// SingleValueEncodingContainer
|
|
case singleValueContainerCodingPath
|
|
case singleValueContainerEncodeNil
|
|
case singleValueContainerEncodeBool(Bool)
|
|
case singleValueContainerEncodeString(String)
|
|
case singleValueContainerEncodeDouble(Double)
|
|
case singleValueContainerEncodeFloat(Float)
|
|
case singleValueContainerEncodeInt(Int)
|
|
case singleValueContainerEncodeInt8(Int8)
|
|
case singleValueContainerEncodeInt16(Int16)
|
|
case singleValueContainerEncodeInt32(Int32)
|
|
case singleValueContainerEncodeInt64(Int64)
|
|
case singleValueContainerEncodeUInt(UInt)
|
|
case singleValueContainerEncodeUInt8(UInt8)
|
|
case singleValueContainerEncodeUInt16(UInt16)
|
|
case singleValueContainerEncodeUInt32(UInt32)
|
|
case singleValueContainerEncodeUInt64(UInt64)
|
|
case singleValueContainerEncodeEncodable
|
|
}
|
|
|
|
fileprivate(set) var history: [Event] = []
|
|
|
|
fileprivate var _codingPath: [CodingKey] = []
|
|
|
|
fileprivate var _userInfo: [CodingUserInfoKey : Any] = [:]
|
|
|
|
fileprivate var _unkeyedContainerCount = 0
|
|
}
|
|
|
|
extension TrackingEncoder: Encoder {
|
|
|
|
var codingPath: [CodingKey] {
|
|
history.append(.getCodingPath)
|
|
return _codingPath
|
|
}
|
|
|
|
var userInfo: [CodingUserInfoKey : Any] {
|
|
history.append(.getUserInfo)
|
|
return _userInfo
|
|
}
|
|
|
|
func container<Key: CodingKey>(
|
|
keyedBy type: Key.Type
|
|
) -> KeyedEncodingContainer<Key> {
|
|
history.append(.containerKeyedBy)
|
|
return .init(TrackingKeyedEncoder(encoder: self))
|
|
}
|
|
|
|
func unkeyedContainer() -> UnkeyedEncodingContainer {
|
|
history.append(.unkeyedContainer)
|
|
return TrackingUnkeyedEncoder(encoder: self)
|
|
}
|
|
|
|
func singleValueContainer() -> SingleValueEncodingContainer {
|
|
history.append(.singleValueContainer)
|
|
return TrackingSingleValueEncoder(encoder: self)
|
|
}
|
|
}
|
|
|
|
private struct TrackingKeyedEncoder<Key: CodingKey>: KeyedEncodingContainerProtocol {
|
|
let encoder: TrackingEncoder
|
|
|
|
var codingPath: [CodingKey] {
|
|
encoder.history.append(.keyedContainerCodingPath)
|
|
return encoder._codingPath
|
|
}
|
|
|
|
mutating func encodeNil(forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeNil(key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Bool, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeBool(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: String, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeString(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Double, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeDouble(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Float, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeFloat(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Int, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeInt(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Int8, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeInt8(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Int16, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeInt16(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Int32, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeInt32(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: Int64, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeInt64(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeUInt(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt8, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeUInt8(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt16, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeUInt16(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt32, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeUInt32(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt64, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeUInt64(value, key.stringValue))
|
|
}
|
|
|
|
mutating func encode<Value: Encodable>(_ value: Value, forKey key: Key) throws {
|
|
encoder.history.append(.keyedContainerEncodeEncodable(key.stringValue))
|
|
try value.encode(to: encoder)
|
|
}
|
|
|
|
mutating func nestedContainer<NestedKey: CodingKey>(
|
|
keyedBy keyType: NestedKey.Type,
|
|
forKey key: Key
|
|
) -> KeyedEncodingContainer<NestedKey> {
|
|
encoder.history.append(.keyedContainerNestedKeyedContainer(key.stringValue))
|
|
return .init(TrackingKeyedEncoder<NestedKey>(encoder: encoder))
|
|
}
|
|
|
|
mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
|
|
encoder.history.append(.keyedContainerNestedUnkeyedContainer(key.stringValue))
|
|
return TrackingUnkeyedEncoder(encoder: encoder)
|
|
}
|
|
|
|
mutating func superEncoder() -> Encoder {
|
|
encoder.history.append(.keyedContainerSuperEncoder)
|
|
return encoder
|
|
}
|
|
|
|
mutating func superEncoder(forKey key: Key) -> Encoder {
|
|
encoder.history.append(.keyedContainerSuperEncoderForKey(key.stringValue))
|
|
return encoder
|
|
}
|
|
}
|
|
|
|
private struct TrackingUnkeyedEncoder: UnkeyedEncodingContainer {
|
|
|
|
let encoder: TrackingEncoder
|
|
|
|
var codingPath: [CodingKey] {
|
|
encoder.history.append(.unkeyedContainerCodingPath)
|
|
return encoder._codingPath
|
|
}
|
|
|
|
var count: Int {
|
|
encoder.history.append(.unkeyedContainerCount)
|
|
return encoder._unkeyedContainerCount
|
|
}
|
|
|
|
mutating func encodeNil() throws {
|
|
encoder.history.append(.unkeyedContainerEncodeNil)
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Bool) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeBool(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: String) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeString(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Double) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeDouble(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Float) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeFloat(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Int) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeInt(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Int8) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeInt8(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Int16) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeInt16(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Int32) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeInt32(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: Int64) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeInt64(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: UInt) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeUInt(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: UInt8) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeUInt8(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: UInt16) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeUInt16(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: UInt32) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeUInt32(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode(_ value: UInt64) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeUInt64(value))
|
|
encoder._unkeyedContainerCount += 1
|
|
}
|
|
|
|
mutating func encode<Value: Encodable>(_ value: Value) throws {
|
|
encoder.history.append(.unkeyedContainerEncodeEncodable)
|
|
encoder._unkeyedContainerCount += 1
|
|
try value.encode(to: encoder)
|
|
}
|
|
|
|
func nestedContainer<NestedKey: CodingKey>(
|
|
keyedBy keyType: NestedKey.Type
|
|
) -> KeyedEncodingContainer<NestedKey> {
|
|
encoder.history.append(.unkeyedContainerNestedKeyedContainer)
|
|
return .init(TrackingKeyedEncoder(encoder: encoder))
|
|
}
|
|
|
|
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
|
|
encoder.history.append(.unkeyedContainerNestedUnkeyedContainer)
|
|
return self
|
|
}
|
|
|
|
func superEncoder() -> Encoder {
|
|
encoder.history.append(.unkeyedContainerSuperEncoder)
|
|
return encoder
|
|
}
|
|
}
|
|
|
|
private struct TrackingSingleValueEncoder: SingleValueEncodingContainer {
|
|
|
|
let encoder: TrackingEncoder
|
|
|
|
var codingPath: [CodingKey] {
|
|
encoder.history.append(.singleValueContainerCodingPath)
|
|
return encoder._codingPath
|
|
}
|
|
|
|
mutating func encodeNil() throws {
|
|
encoder.history.append(.singleValueContainerEncodeNil)
|
|
}
|
|
|
|
mutating func encode(_ value: Bool) throws {
|
|
encoder.history.append(.singleValueContainerEncodeBool(value))
|
|
}
|
|
|
|
mutating func encode(_ value: String) throws {
|
|
encoder.history.append(.singleValueContainerEncodeString(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Double) throws {
|
|
encoder.history.append(.singleValueContainerEncodeDouble(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Float) throws {
|
|
encoder.history.append(.singleValueContainerEncodeFloat(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Int) throws {
|
|
encoder.history.append(.singleValueContainerEncodeInt(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Int8) throws {
|
|
encoder.history.append(.singleValueContainerEncodeInt8(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Int16) throws {
|
|
encoder.history.append(.singleValueContainerEncodeInt16(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Int32) throws {
|
|
encoder.history.append(.singleValueContainerEncodeInt32(value))
|
|
}
|
|
|
|
mutating func encode(_ value: Int64) throws {
|
|
encoder.history.append(.singleValueContainerEncodeInt64(value))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt) throws {
|
|
encoder.history.append(.singleValueContainerEncodeUInt(value))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt8) throws {
|
|
encoder.history.append(.singleValueContainerEncodeUInt8(value))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt16) throws {
|
|
encoder.history.append(.singleValueContainerEncodeUInt16(value))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt32) throws {
|
|
encoder.history.append(.singleValueContainerEncodeUInt32(value))
|
|
}
|
|
|
|
mutating func encode(_ value: UInt64) throws {
|
|
encoder.history.append(.singleValueContainerEncodeUInt64(value))
|
|
}
|
|
|
|
mutating func encode<Value: Encodable>(_ value: Value) throws {
|
|
encoder.history.append(.singleValueContainerEncodeEncodable)
|
|
try value.encode(to: encoder)
|
|
}
|
|
}
|