// // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation // Based on https://www.swiftbysundell.com/tips/default-decoding-values/ public protocol DecodableDefaultSource { associatedtype Value: Decodable static var defaultValue: Value { get } } public enum DecodableDefault { @propertyWrapper public struct Wrapper { public typealias Value = Source.Value public var wrappedValue = Source.defaultValue public init() {} public init(wrappedValue: Value) { self.wrappedValue = wrappedValue } } } extension DecodableDefault.Wrapper: Decodable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() wrappedValue = try container.decode(Value.self) } } extension KeyedDecodingContainer { func decode( _ type: DecodableDefault.Wrapper.Type, forKey key: Key ) throws -> DecodableDefault.Wrapper { try decodeIfPresent(type, forKey: key) ?? .init() } } public extension DecodableDefault { typealias Source = DecodableDefaultSource typealias DecodableBooleanLiteral = Decodable & ExpressibleByBooleanLiteral typealias DecodableIntegerLiteral = Decodable & ExpressibleByIntegerLiteral typealias DecodableFloatLiteral = Decodable & ExpressibleByFloatLiteral typealias DecodableStringLiteral = Decodable & ExpressibleByStringLiteral typealias DecodableArrayLiteral = Decodable & ExpressibleByArrayLiteral typealias DecodableDictionaryLiteral = Decodable & ExpressibleByDictionaryLiteral enum Sources { public enum True: Source { public static var defaultValue: T { true } } public enum False: Source { public static var defaultValue: T { false } } public enum Zero: Source { public static var defaultValue: T { 0 } } public enum One: Source { public static var defaultValue: T { 1 } } public enum ZeroFloat: Source { public static var defaultValue: T { 0.0 } } public enum OneFloat: Source { public static var defaultValue: T { 1.0 } } public enum EmptyString: Source { public static var defaultValue: T { "" } } public enum EmptyArray: Source { public static var defaultValue: T { [] } } public enum EmptyDictionary: Source { public static var defaultValue: T { [:] } } public enum GenerateUUIDString: Source { public static var defaultValue: String { UUID().uuidString } } public enum OutgoingMessageSending: Source { public static var defaultValue: OWSOutgoingMessageRecipientState { .sending } } } } public extension DecodableDefault { typealias GenerateUUIDString = Wrapper typealias OutgoingMessageSending = Wrapper typealias True = Wrapper> typealias False = Wrapper> typealias Zero = Wrapper> typealias One = Wrapper> typealias ZeroFloat = Wrapper> typealias OneFloat = Wrapper> typealias EmptyString = Wrapper> typealias EmptyArray = Wrapper> typealias EmptyDictionary = Wrapper> } 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) } } extension DecodableDefault.Wrapper: CustomStringConvertible where Value: CustomStringConvertible { public var description: String { wrappedValue.description } } extension DecodableDefault.Wrapper: CustomDebugStringConvertible where Value: CustomDebugStringConvertible { public var debugDescription: String { wrappedValue.debugDescription } }