// Copyright © 2020 Metabolist. All rights reserved. import Foundation // Thank you https://www.swiftbysundell.com/tips/default-decoding-values/ public protocol DecodableDefaultSource { associatedtype Value: Decodable static var defaultValue: Value { get } } public enum DecodableDefault {} // swiftlint:disable nesting extension DecodableDefault { @propertyWrapper public struct Wrapper { public typealias Value = Source.Value public var wrappedValue = Source.defaultValue public init() {} } } public extension DecodableDefault { typealias Source = DecodableDefaultSource typealias List = Decodable & ExpressibleByArrayLiteral typealias Map = Decodable & ExpressibleByDictionaryLiteral enum Sources { public enum True: Source { public static var defaultValue: Bool { true } } public enum False: Source { public static var defaultValue: Bool { false } } public enum EmptyString: Source { public static var defaultValue: String { "" } } public enum EmptyList: Source { public static var defaultValue: T { [] } } public enum EmptyMap: Source { public static var defaultValue: T { [:] } } public enum Zero: Source { public static var defaultValue: Int { 0 } } public enum StatusVisibilityPublic: Source { public static var defaultValue: Status.Visibility { .public } } public enum ExpandMediaDefault: Source { public static var defaultValue: MastodonPreferences.ExpandMedia { .default } } } } // swiftlint:enable nesting public extension DecodableDefault { typealias True = Wrapper typealias False = Wrapper typealias EmptyString = Wrapper typealias EmptyList = Wrapper> typealias EmptyMap = Wrapper> typealias Zero = Wrapper typealias StatusVisibilityPublic = Wrapper typealias ExpandMediaDefault = Wrapper } extension DecodableDefault.Wrapper: Decodable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() wrappedValue = try container.decode(Value.self) } } extension DecodableDefault.Wrapper: Equatable where Value: Equatable {} extension DecodableDefault.Wrapper: Hashable where Value: Hashable {} extension DecodableDefault.Wrapper: Encodable where Value: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(wrappedValue) } } public extension KeyedDecodingContainer { func decode(_ type: DecodableDefault.Wrapper.Type, forKey key: Key) throws -> DecodableDefault.Wrapper { try decodeIfPresent(type, forKey: key) ?? .init() } }