diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index f396c8e..e311e42 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -159,6 +159,7 @@ D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCBA23C65BC300C44CC4 /* Percent.swift */; }; D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */; }; EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */; }; + EA09CD99282BF83600A7835F /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CD98282BF83600A7835F /* DecodableDefault.swift */; }; EA3B264C25FC0B7600008074 /* ModelHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */; }; /* End PBXBuildFile section */ @@ -309,6 +310,7 @@ D2DEDCBA23C65BC300C44CC4 /* Percent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Percent.swift; sourceTree = ""; }; D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateObject.swift; sourceTree = ""; }; EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decoder+UserInfo.swift"; sourceTree = ""; }; + EA09CD98282BF83600A7835F /* DecodableDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodableDefault.swift; sourceTree = ""; }; EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHandlerProtocol.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -688,6 +690,7 @@ D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */, D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */, D2DEDCBA23C65BC300C44CC4 /* Percent.swift */, + EA09CD98282BF83600A7835F /* DecodableDefault.swift */, ); path = PropertyWrappers; sourceTree = ""; @@ -915,6 +918,7 @@ AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */, AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */, EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */, + EA09CD99282BF83600A7835F /* DecodableDefault.swift in Sources */, 01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */, D27073D125BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift in Sources */, AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */, diff --git a/MVMCore/MVMCore/Utility/PropertyWrappers/DecodableDefault.swift b/MVMCore/MVMCore/Utility/PropertyWrappers/DecodableDefault.swift new file mode 100644 index 0000000..b891942 --- /dev/null +++ b/MVMCore/MVMCore/Utility/PropertyWrappers/DecodableDefault.swift @@ -0,0 +1,87 @@ +// +// DecoderDefault.swift +// MVMCore +// +// Created by Matt Bruce on 5/11/22. +// Copyright © 2022 myverizon. All rights reserved. +// + +import Foundation + +/// https://www.swiftbysundell.com/tips/default-decoding-values/ +/// This code is used for Decodable objects that allow Default Values to be added. +public protocol DecodableDefaultSource { + associatedtype Value: Decodable + static var defaultValue: Value { get } +} + +public enum DecodableDefault {} + +extension DecodableDefault { + @propertyWrapper + public struct Wrapper { + public typealias Value = Source.Value + public var wrappedValue = Source.defaultValue + public init() {} + } +} + +extension DecodableDefault.Wrapper: Decodable { + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + wrappedValue = try container.decode(Value.self) + } +} + +extension KeyedDecodingContainer { + public func decode(_ type: DecodableDefault.Wrapper.Type, + forKey key: Key) throws -> DecodableDefault.Wrapper { + try decodeIfPresent(type, forKey: key) ?? .init() + } +} + +extension DecodableDefault { + public typealias Source = DecodableDefaultSource + public typealias List = Decodable & ExpressibleByArrayLiteral + public typealias Map = Decodable & ExpressibleByDictionaryLiteral + + public 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 { [:] } + } + } +} + +extension DecodableDefault { + public typealias True = Wrapper + public typealias False = Wrapper + public typealias EmptyString = Wrapper + public typealias EmptyList = Wrapper> + public typealias EmptyMap = 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) + } +}