// // Coding.swift // TuskerPreferences // // Created by Shadowfacts on 4/13/24. // import Foundation private protocol PreferenceProtocol { associatedtype Key: PreferenceKey var storedValue: Key.Value? { get } init() } extension Preference: PreferenceProtocol { } struct PreferenceCoding: Codable { let wrapped: Wrapped init(wrapped: Wrapped) { self.wrapped = wrapped } init(from decoder: any Decoder) throws { self.wrapped = try Wrapped(from: PreferenceDecoder(wrapped: decoder)) } func encode(to encoder: any Encoder) throws { try wrapped.encode(to: PreferenceEncoder(wrapped: encoder)) } } private struct PreferenceDecoder: Decoder { let wrapped: any Decoder var codingPath: [any CodingKey] { wrapped.codingPath } var userInfo: [CodingUserInfoKey : Any] { wrapped.userInfo } func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer where Key : CodingKey { KeyedDecodingContainer(PreferenceDecodingContainer(wrapped: try wrapped.container(keyedBy: type))) } func unkeyedContainer() throws -> any UnkeyedDecodingContainer { throw Error.onlyKeyedContainerSupported } func singleValueContainer() throws -> any SingleValueDecodingContainer { throw Error.onlyKeyedContainerSupported } enum Error: Swift.Error { case onlyKeyedContainerSupported } } private struct PreferenceDecodingContainer: KeyedDecodingContainerProtocol { let wrapped: KeyedDecodingContainer var codingPath: [any CodingKey] { wrapped.codingPath } var allKeys: [Key] { wrapped.allKeys } func contains(_ key: Key) -> Bool { wrapped.contains(key) } func decodeNil(forKey key: Key) throws -> Bool { try wrapped.decodeNil(forKey: key) } func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { try wrapped.decode(type, forKey: key) } func decode(_ type: String.Type, forKey key: Key) throws -> String { try wrapped.decode(type, forKey: key) } func decode(_ type: Double.Type, forKey key: Key) throws -> Double { try wrapped.decode(type, forKey: key) } func decode(_ type: Float.Type, forKey key: Key) throws -> Float { try wrapped.decode(type, forKey: key) } func decode(_ type: Int.Type, forKey key: Key) throws -> Int { try wrapped.decode(type, forKey: key) } func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { try wrapped.decode(type, forKey: key) } func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { try wrapped.decode(type, forKey: key) } func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { try wrapped.decode(type, forKey: key) } func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { try wrapped.decode(type, forKey: key) } func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { try wrapped.decode(type, forKey: key) } func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { try wrapped.decode(type, forKey: key) } func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { try wrapped.decode(type, forKey: key) } func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { try wrapped.decode(type, forKey: key) } func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { try wrapped.decode(type, forKey: key) } func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { if let type = type as? any PreferenceProtocol.Type, !contains(key) { func makePreference(_: P.Type) -> T { P() as! T } return _openExistential(type, do: makePreference) } return try wrapped.decode(type, forKey: key) } func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { try wrapped.nestedContainer(keyedBy: type, forKey: key) } func nestedUnkeyedContainer(forKey key: Key) throws -> any UnkeyedDecodingContainer { try wrapped.nestedUnkeyedContainer(forKey: key) } func superDecoder() throws -> any Decoder { try wrapped.superDecoder() } func superDecoder(forKey key: Key) throws -> any Decoder { try wrapped.superDecoder(forKey: key) } } private struct PreferenceEncoder: Encoder { let wrapped: any Encoder var codingPath: [any CodingKey] { wrapped.codingPath } var userInfo: [CodingUserInfoKey : Any] { wrapped.userInfo } func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { KeyedEncodingContainer(PreferenceEncodingContainer(wrapped: wrapped.container(keyedBy: type))) } func unkeyedContainer() -> any UnkeyedEncodingContainer { fatalError("Only keyed containers supported") } func singleValueContainer() -> any SingleValueEncodingContainer { fatalError("Only keyed containers supported") } } private struct PreferenceEncodingContainer: KeyedEncodingContainerProtocol { var wrapped: KeyedEncodingContainer var codingPath: [any CodingKey] { wrapped.codingPath } mutating func encodeNil(forKey key: Key) throws { try wrapped.encodeNil(forKey: key) } mutating func encode(_ value: Bool, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: String, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Double, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Float, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Int, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Int8, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Int16, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Int32, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: Int64, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: UInt, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: UInt8, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: UInt16, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: UInt32, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: UInt64, forKey key: Key) throws { try wrapped.encode(value, forKey: key) } mutating func encode(_ value: T, forKey key: Key) throws where T : Encodable { if let value = value as? any PreferenceProtocol, value.storedValue == nil { return } try wrapped.encode(value, forKey: key) } mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer where NestedKey : CodingKey { wrapped.nestedContainer(keyedBy: keyType, forKey: key) } mutating func nestedUnkeyedContainer(forKey key: Key) -> any UnkeyedEncodingContainer { wrapped.nestedUnkeyedContainer(forKey: key) } mutating func superEncoder() -> any Encoder { wrapped.superEncoder() } mutating func superEncoder(forKey key: Key) -> any Encoder { wrapped.superEncoder(forKey: key) } }