forked from shadowfacts/Tusker
283 lines
8.3 KiB
Swift
283 lines
8.3 KiB
Swift
//
|
|
// 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<Wrapped: Codable>: 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<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> 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<Key: CodingKey>: KeyedDecodingContainerProtocol {
|
|
let wrapped: KeyedDecodingContainer<Key>
|
|
|
|
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<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable {
|
|
if let type = type as? any PreferenceProtocol.Type,
|
|
!contains(key) {
|
|
func makePreference<P: PreferenceProtocol>(_: P.Type) -> T {
|
|
P() as! T
|
|
}
|
|
return _openExistential(type, do: makePreference)
|
|
}
|
|
return try wrapped.decode(type, forKey: key)
|
|
}
|
|
|
|
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> 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<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> 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<Key: CodingKey>: KeyedEncodingContainerProtocol {
|
|
var wrapped: KeyedEncodingContainer<Key>
|
|
|
|
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<T>(_ 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<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> 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)
|
|
}
|
|
|
|
|
|
}
|