diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ResilientDecoding.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ResilientDecoding.xcscheme index b4c5b51..33eb1be 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ResilientDecoding.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/ResilientDecoding.xcscheme @@ -41,10 +41,21 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + + skipped = "NO" + parallelizable = "YES"> (novelValue: T) { + public init(novelValue: T) { self.novelValue = novelValue } diff --git a/Sources/ResilientDecoding/Resilient.swift b/Sources/ResilientDecoding/Resilient.swift index 71bfbd1..0b63e2f 100644 --- a/Sources/ResilientDecoding/Resilient.swift +++ b/Sources/ResilientDecoding/Resilient.swift @@ -6,7 +6,7 @@ import Foundation // MARK: - Resilient @propertyWrapper -public struct Resilient: Decodable { +public struct Resilient: Decodable, Sendable { /** If this initializer is called it is likely because a property was marked as `Resilient` despite the underlying type not supporting resilient decoding. For instance, a developer may write `@Resilient var numberOfThings: Int`, but since `Int` doesn't provide a mechanism for recovering from a decoding failure (like `Array`s and `Optional`s do) wrapping the property in `Resilient` does nothing. @@ -77,7 +77,7 @@ public struct Resilient: Decodable { /** The outcome of decoding a `Resilient` type */ -public enum ResilientDecodingOutcome { +public enum ResilientDecodingOutcome: Sendable { /** A value was decoded successfully */ diff --git a/Sources/ResilientDecoding/ResilientArray+DecodingOutcome.swift b/Sources/ResilientDecoding/ResilientArray+DecodingOutcome.swift index 460dbd9..77e3000 100644 --- a/Sources/ResilientDecoding/ResilientArray+DecodingOutcome.swift +++ b/Sources/ResilientDecoding/ResilientArray+DecodingOutcome.swift @@ -5,18 +5,18 @@ import Foundation extension Resilient { - init(_ results: [Result]) where Value == [T] { + init(_ results: [Result]) where Value == [T] { self.init(results, transform: { $0 }) } - init(_ results: [Result]) where Value == [T]? { + init(_ results: [Result]) where Value == [T]? { self.init(results, transform: { $0 }) } /** - parameter transform: While the two lines above both say `{ $0 }` they are actually different because the first one is of type `([T]) -> [T]` and the second is of type `([T]) -> [T]?`. */ - private init(_ results: [Result], transform: ([T]) -> Value) { + private init(_ results: [Result], transform: ([T]) -> Value) { let elements = results.compactMap { try? $0.get() } let value = transform(elements) if elements.count == results.count { @@ -41,7 +41,7 @@ extension ResilientDecodingOutcome { /** A type representing some number of errors encountered while decoding an array */ - public struct ArrayDecodingError: Error { + public struct ArrayDecodingError: Error { public let results: [Result] public var errors: [Error] { results.compactMap { result in diff --git a/Sources/ResilientDecoding/ResilientArray.swift b/Sources/ResilientDecoding/ResilientArray.swift index a72507e..9ba7e49 100644 --- a/Sources/ResilientDecoding/ResilientArray.swift +++ b/Sources/ResilientDecoding/ResilientArray.swift @@ -22,7 +22,7 @@ extension KeyedDecodingContainer { /** Decodes a `Resilient` array, omitting elements as errors are encountered. */ - public func decode(_ type: Resilient<[Element]>.Type, forKey key: Key) throws -> Resilient<[Element]> + public func decode(_ type: Resilient<[Element]>.Type, forKey key: Key) throws -> Resilient<[Element]> where Element: Decodable { @@ -32,7 +32,7 @@ extension KeyedDecodingContainer { /** Decodes an optional `Resilient` array. A missing key or `nil` value will silently set the property to `nil`. */ - public func decode(_ type: Resilient<[Element]?>.Type, forKey key: Key) throws -> Resilient<[Element]?> { + public func decode(_ type: Resilient<[Element]?>.Type, forKey key: Key) throws -> Resilient<[Element]?> { resilientlyDecode(valueForKey: key, fallback: nil) { $0.resilientlyDecodeArray().map { $0 } } } @@ -40,7 +40,7 @@ extension KeyedDecodingContainer { extension Decoder { - func resilientlyDecodeArray() -> Resilient<[Element]> + func resilientlyDecodeArray() -> Resilient<[Element]> { resilientlyDecodeArray(of: Element.self, transform: { $0 }) } @@ -48,7 +48,7 @@ extension Decoder { /** We can't just use `map` because the transform needs to happen _before_ we wrap the value in `Resilient` so that that the element type of `ArrayDecodingError` is correct. */ - func resilientlyDecodeArray( + func resilientlyDecodeArray( of intermediateElementType: IntermediateElement.Type, transform: (IntermediateElement) -> Element) -> Resilient<[Element]> { @@ -83,11 +83,11 @@ extension Decoder { For the following cases, the user probably meant to use `[T]` as the property type. */ extension KeyedDecodingContainer { - public func decode(_ type: Resilient<[T?]>.Type, forKey key: Key) throws -> Resilient<[T?]> { + public func decode(_ type: Resilient<[T?]>.Type, forKey key: Key) throws -> Resilient<[T?]> { assertionFailure() return try decode(Resilient<[T]>.self, forKey: key).map { $0 } } - public func decode(_ type: Resilient<[T?]?>.Type, forKey key: Key) throws -> Resilient<[T?]?> { + public func decode(_ type: Resilient<[T?]?>.Type, forKey key: Key) throws -> Resilient<[T?]?> { assertionFailure() return try decode(Resilient<[T]>.self, forKey: key).map { $0 } } diff --git a/Sources/ResilientDecoding/ResilientDictionary+DecodingOutcome.swift b/Sources/ResilientDecoding/ResilientDictionary+DecodingOutcome.swift index de63011..495950e 100644 --- a/Sources/ResilientDecoding/ResilientDictionary+DecodingOutcome.swift +++ b/Sources/ResilientDecoding/ResilientDictionary+DecodingOutcome.swift @@ -5,18 +5,18 @@ import Foundation extension Resilient { - init(_ results: [String: Result]) where Value == [String: T] { + init(_ results: [String: Result]) where Value == [String: T] { self.init(results, transform: { $0 }) } - init(_ results: [String: Result]) where Value == [String: T]? { + init(_ results: [String: Result]) where Value == [String: T]? { self.init(results, transform: { $0 }) } /** - parameter transform: While the two lines above both say `{ $0 }` they are actually different because the first one is of type `([String: T]) -> [String: T]` and the second is of type `([String: T]) -> [String: T]?`. */ - private init(_ results: [String: Result], transform: ([String: T]) -> Value) { + private init(_ results: [String: Result], transform: ([String: T]) -> Value) { let dictionary = results.compactMapValues { try? $0.get() } let value = transform(dictionary) if dictionary.count == results.count { @@ -41,7 +41,7 @@ extension ResilientDecodingOutcome { /** A type representing some number of errors encountered while decoding a dictionary */ - public struct DictionaryDecodingError: Error { + public struct DictionaryDecodingError: Error { public let results: [String: Result] public var errors: [Error] { /// It is currently impossible to have both a `topLevelError` and `results` at the same time, but this code is simpler than having an `enum` nested in this type. diff --git a/Sources/ResilientDecoding/ResilientDictionary.swift b/Sources/ResilientDecoding/ResilientDictionary.swift index 28b91ea..bd700e3 100644 --- a/Sources/ResilientDecoding/ResilientDictionary.swift +++ b/Sources/ResilientDecoding/ResilientDictionary.swift @@ -20,7 +20,7 @@ extension KeyedDecodingContainer { /** Decodes a `Resilient` dictionary, omitting values as errors are encountered. */ - public func decode(_ type: Resilient<[String: Value]>.Type, forKey key: Key) throws -> Resilient<[String: Value]> + public func decode(_ type: Resilient<[String: Value]>.Type, forKey key: Key) throws -> Resilient<[String: Value]> { resilientlyDecode(valueForKey: key, fallback: [:]) { $0.resilientlyDecodeDictionary() } } @@ -28,7 +28,7 @@ extension KeyedDecodingContainer { /** Decodes an optional `Resilient` dictionary. If the field is missing or the value is `nil` the decoded property will also be `nil`. */ - public func decode(_ type: Resilient<[String: Value]?>.Type, forKey key: Key) throws -> Resilient<[String: Value]?> { + public func decode(_ type: Resilient<[String: Value]?>.Type, forKey key: Key) throws -> Resilient<[String: Value]?> { resilientlyDecode(valueForKey: key, fallback: nil) { $0.resilientlyDecodeDictionary().map { $0 } } } @@ -36,7 +36,7 @@ extension KeyedDecodingContainer { extension Decoder { - func resilientlyDecodeDictionary() -> Resilient<[String: Value]> + func resilientlyDecodeDictionary() -> Resilient<[String: Value]> { resilientlyDecodeDictionary(of: Value.self, transform: { $0 }) } @@ -44,7 +44,7 @@ extension Decoder { /** We can't just use `map` because the transform needs to happen _before_ we wrap the value in `Resilient` so that that the value type of `DictionaryDecodingError` is correct. */ - func resilientlyDecodeDictionary( + func resilientlyDecodeDictionary( of intermediateValueType: IntermediateValue.Type, transform: (IntermediateValue) -> Value) -> Resilient<[String: Value]> { @@ -86,11 +86,11 @@ private struct DecodingResultContainer: Decodable { For the following cases, the user probably meant to use `[String: T]` as the property type. */ extension KeyedDecodingContainer { - public func decode(_ type: Resilient<[String: T?]>.Type, forKey key: Key) throws -> Resilient<[T?]> { + public func decode(_ type: Resilient<[String: T?]>.Type, forKey key: Key) throws -> Resilient<[T?]> { assertionFailure() return try decode(Resilient<[T]>.self, forKey: key).map { $0 } } - public func decode(_ type: Resilient<[String: T?]?>.Type, forKey key: Key) throws -> Resilient<[T?]?> { + public func decode(_ type: Resilient<[String: T?]?>.Type, forKey key: Key) throws -> Resilient<[T?]?> { assertionFailure() return try decode(Resilient<[T]>.self, forKey: key).map { $0 } } diff --git a/Sources/ResilientDecoding/ResilientRawRepresentable.swift b/Sources/ResilientDecoding/ResilientRawRepresentable.swift index dfc62a9..4f2b398 100644 --- a/Sources/ResilientDecoding/ResilientRawRepresentable.swift +++ b/Sources/ResilientDecoding/ResilientRawRepresentable.swift @@ -16,7 +16,7 @@ import Foundation ``` then any struct with a `Resilient` property with that type (for instance `@Resilient var myEnum: MyEnum`) will be set to `.unknown` in the event of a decoding failure. */ -public protocol ResilientRawRepresentable: Decodable, RawRepresentable where RawValue: Decodable { +public protocol ResilientRawRepresentable: Decodable, Sendable, RawRepresentable where RawValue: Decodable & Sendable { associatedtype DecodingFallback diff --git a/Tests/ResilientDecodingTests/BugTests.swift b/Tests/ResilientDecodingTests/BugTests.swift index 74493f8..281742d 100644 --- a/Tests/ResilientDecodingTests/BugTests.swift +++ b/Tests/ResilientDecodingTests/BugTests.swift @@ -20,7 +20,7 @@ final class BugTests: XCTestCase { let rawValue: URL static var isFrozen: Bool { true } } - struct Mock: Decodable { + struct Mock: Decodable, Sendable { @Resilient var optional: URL? @Resilient var array: [URL] @Resilient var dictionary: [String: URL] diff --git a/Tests/ResilientDecodingTests/ResilientArrayTests.swift b/Tests/ResilientDecodingTests/ResilientArrayTests.swift index 4847146..f176bec 100644 --- a/Tests/ResilientDecodingTests/ResilientArrayTests.swift +++ b/Tests/ResilientDecodingTests/ResilientArrayTests.swift @@ -4,7 +4,7 @@ import ResilientDecoding import XCTest -private struct ResilientArrayWrapper: Decodable { +private struct ResilientArrayWrapper: Decodable, Sendable { @Resilient var resilientArray: [Int] @Resilient var optionalResilientArray: [Int]? } diff --git a/Tests/ResilientDecodingTests/ResilientDecodingErrorReporterTests.swift b/Tests/ResilientDecodingTests/ResilientDecodingErrorReporterTests.swift index 2153916..8751e64 100644 --- a/Tests/ResilientDecodingTests/ResilientDecodingErrorReporterTests.swift +++ b/Tests/ResilientDecodingTests/ResilientDecodingErrorReporterTests.swift @@ -4,7 +4,7 @@ import ResilientDecoding import XCTest -private struct ResilientArrayWrapper: Decodable { +private struct ResilientArrayWrapper: Decodable, Sendable { @Resilient var resilientArray: [Int] @Resilient var resilientEnum: ResilientEnum? } diff --git a/Tests/ResilientDecodingTests/ResilientDictionaryTests.swift b/Tests/ResilientDecodingTests/ResilientDictionaryTests.swift index 876d656..65a7f57 100644 --- a/Tests/ResilientDecodingTests/ResilientDictionaryTests.swift +++ b/Tests/ResilientDecodingTests/ResilientDictionaryTests.swift @@ -10,7 +10,7 @@ import ResilientDecoding #endif import XCTest -private struct ResilientDictionaryWrapper: Decodable { +private struct ResilientDictionaryWrapper: Decodable, Sendable { @Resilient var resilientDictionary: [String: Int] @Resilient var optionalResilientDictionary: [String: Int]? } diff --git a/Tests/ResilientDecodingTests/ResilientOptionalTests.swift b/Tests/ResilientDecodingTests/ResilientOptionalTests.swift index 121a69a..e1be44d 100644 --- a/Tests/ResilientDecodingTests/ResilientOptionalTests.swift +++ b/Tests/ResilientDecodingTests/ResilientOptionalTests.swift @@ -4,7 +4,7 @@ import ResilientDecoding import XCTest -private struct ResilientOptionalWrapper: Decodable { +private struct ResilientOptionalWrapper: Decodable, Sendable { @Resilient var resilientOptional: Int? } diff --git a/Tests/ResilientDecodingTests/ResilientRawRepresentableArrayTests.swift b/Tests/ResilientDecodingTests/ResilientRawRepresentableArrayTests.swift index a867817..70d7541 100644 --- a/Tests/ResilientDecodingTests/ResilientRawRepresentableArrayTests.swift +++ b/Tests/ResilientDecodingTests/ResilientRawRepresentableArrayTests.swift @@ -4,7 +4,7 @@ import ResilientDecoding import XCTest -private struct ResilientRawRepresentableArrayWrapper: Decodable { +private struct ResilientRawRepresentableArrayWrapper: Decodable, Sendable { @Resilient var resilientArray: [ResilientEnum] @Resilient var optionalResilientArray: [ResilientEnum]? @Resilient var resilientArrayOfFrozenType: [ResilientFrozenEnum] diff --git a/Tests/ResilientDecodingTests/ResilientRawRepresentableDictionaryTests.swift b/Tests/ResilientDecodingTests/ResilientRawRepresentableDictionaryTests.swift index e28f500..a94c3c6 100644 --- a/Tests/ResilientDecodingTests/ResilientRawRepresentableDictionaryTests.swift +++ b/Tests/ResilientDecodingTests/ResilientRawRepresentableDictionaryTests.swift @@ -4,7 +4,7 @@ import ResilientDecoding import XCTest -private struct ResilientRawRepresentableDictionaryWrapper: Decodable { +private struct ResilientRawRepresentableDictionaryWrapper: Decodable, Sendable { @Resilient var resilientDictionary: [String: ResilientEnum] @Resilient var optionalResilientDictionary: [String: ResilientEnum]? @Resilient var resilientDictionaryOfFrozenType: [String: ResilientFrozenEnum] diff --git a/Tests/ResilientDecodingTests/ResilientRawRepresentableTests.swift b/Tests/ResilientDecodingTests/ResilientRawRepresentableTests.swift index 0665f2f..8f12030 100644 --- a/Tests/ResilientDecodingTests/ResilientRawRepresentableTests.swift +++ b/Tests/ResilientDecodingTests/ResilientRawRepresentableTests.swift @@ -4,7 +4,7 @@ import XCTest import ResilientDecoding -private struct ResilientRawRepresentableEnumWrapper: Decodable { +private struct ResilientRawRepresentableEnumWrapper: Decodable, Sendable { @Resilient var resilientEnumWithFallback: ResilientEnumWithFallback @Resilient var resilientFrozenEnumWithFallback: ResilientFrozenEnumWithFallback @Resilient var optionalResilientEnum: ResilientEnum?