diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4fd148..c94528c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,10 +6,10 @@ on: workflow_dispatch: jobs: - xcode_14_3_1: + xcode_15_0_1: runs-on: macos-13 env: - DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_15.0.1.app/Contents/Developer steps: - name: Checkout uses: actions/checkout@v3 @@ -26,10 +26,10 @@ jobs: with: files: ./coverage_report.lcov - xcode_15: + xcode_14_3_1: runs-on: macos-13 env: - DEVELOPER_DIR: /Applications/Xcode_15.0.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer steps: - name: Checkout uses: actions/checkout@v3 @@ -40,9 +40,9 @@ jobs: - name: Test run: swift test --skip-build - linux_swift_5_9: + linux_swift_5_9_2: runs-on: ubuntu-latest - container: swift:5.9 + container: swift:5.9.2 steps: - name: Checkout uses: actions/checkout@v3 @@ -65,16 +65,3 @@ jobs: run: swift build --build-tests - name: Test run: swift test --skip-build - - linux_swift_5_7: - runs-on: ubuntu-latest - container: swift:5.7 - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Version - run: swift --version - - name: Build - run: swift build --build-tests - - name: Test - run: swift test --skip-build diff --git a/Package.swift b/Package.swift index 84e215f..a35182b 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.7 +// swift-tools-version:5.8 import PackageDescription let package = Package( @@ -15,12 +15,23 @@ let package = Package( targets: [ .target( name: "KeyValueCoder", - path: "Sources" + path: "Sources", + swiftSettings: .upcomingFeatures ), .testTarget( name: "KeyValueCoderTests", dependencies: ["KeyValueCoder"], - path: "Tests" + path: "Tests", + swiftSettings: .upcomingFeatures ) ] ) + +extension Array where Element == SwiftSetting { + + static var upcomingFeatures: [SwiftSetting] { + [ + .enableUpcomingFeature("ExistentialAny") + ] + } +} diff --git a/README.md b/README.md index 58bd27e..c561967 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build](https://github.com/swhitty/KeyValueCoder/actions/workflows/build.yml/badge.svg)](https://github.com/swhitty/KeyValueCoder/actions/workflows/build.yml) [![CodeCov](https://codecov.io/gh/swhitty/KeyValueCoder/branch/main/graphs/badge.svg)](https://codecov.io/gh/swhitty/KeyValueCoder/branch/main) -[![Swift 5.9](https://img.shields.io/badge/swift-5.7%20–%205.9-red.svg?style=flat)](https://developer.apple.com/swift) +[![Swift 5.9](https://img.shields.io/badge/swift-5.8%20–%205.9-red.svg?style=flat)](https://developer.apple.com/swift) [![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://opensource.org/licenses/MIT) [![Twitter](https://img.shields.io/badge/twitter-@simonwhitty-blue.svg)](http://twitter.com/simonwhitty) diff --git a/Sources/KeyValueDecoder.swift b/Sources/KeyValueDecoder.swift index 2a952dc..6c08430 100644 --- a/Sources/KeyValueDecoder.swift +++ b/Sources/KeyValueDecoder.swift @@ -78,7 +78,7 @@ private extension KeyValueDecoder { struct Decoder: Swift.Decoder { private let container: SingleContainer - let codingPath: [CodingKey] + let codingPath: [any CodingKey] let userInfo: [CodingUserInfoKey: Any] init(container: SingleContainer) { @@ -97,25 +97,25 @@ private extension KeyValueDecoder { return KeyedDecodingContainer(keyed) } - func unkeyedContainer() throws -> UnkeyedDecodingContainer { + func unkeyedContainer() throws -> any UnkeyedDecodingContainer { let storage = try container.decode([Any].self) return UnkeyedContainer(codingPath: codingPath, storage: storage, userInfo: userInfo, nilDecodingStrategy: container.nilDecodingStrategy) } - func singleValueContainer() throws -> SingleValueDecodingContainer { + func singleValueContainer() throws -> any SingleValueDecodingContainer { container } } struct SingleContainer: SingleValueDecodingContainer { - let codingPath: [CodingKey] + let codingPath: [any CodingKey] let userInfo: [CodingUserInfoKey: Any] let nilDecodingStrategy: NilDecodingStrategy private var value: Any - init(value: Any, codingPath: [CodingKey], userInfo: [CodingUserInfoKey: Any], nilDecodingStrategy: NilDecodingStrategy) { + init(value: Any, codingPath: [any CodingKey], userInfo: [CodingUserInfoKey: Any], nilDecodingStrategy: NilDecodingStrategy) { self.value = value self.codingPath = codingPath self.userInfo = userInfo @@ -297,11 +297,11 @@ private extension KeyValueDecoder { struct KeyedContainer: KeyedDecodingContainerProtocol { let storage: [String: Any] - let codingPath: [CodingKey] + let codingPath: [any CodingKey] private let userInfo: [CodingUserInfoKey: Any] private let nilDecodingStrategy: NilDecodingStrategy - init(codingPath: [CodingKey], storage: [String: Any], userInfo: [CodingUserInfoKey: Any], nilDecodingStrategy: NilDecodingStrategy) { + init(codingPath: [any CodingKey], storage: [String: Any], userInfo: [CodingUserInfoKey: Any], nilDecodingStrategy: NilDecodingStrategy) { self.codingPath = codingPath self.storage = storage self.userInfo = userInfo @@ -407,7 +407,7 @@ private extension KeyValueDecoder { return KeyedDecodingContainer(keyed) } - func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { + func nestedUnkeyedContainer(forKey key: Key) throws -> any UnkeyedDecodingContainer { let container = try container(for: key) return try UnkeyedContainer( codingPath: container.codingPath, @@ -417,25 +417,25 @@ private extension KeyValueDecoder { ) } - func superDecoder() throws -> Swift.Decoder { + func superDecoder() throws -> any Swift.Decoder { let container = SingleContainer(value: storage, codingPath: codingPath, userInfo: userInfo, nilDecodingStrategy: nilDecodingStrategy) return Decoder(container: container) } - func superDecoder(forKey key: Key) throws -> Swift.Decoder { + func superDecoder(forKey key: Key) throws -> any Swift.Decoder { try Decoder(container: container(for: key)) } } struct UnkeyedContainer: UnkeyedDecodingContainer { - let codingPath: [CodingKey] + let codingPath: [any CodingKey] let storage: [Any] private let userInfo: [CodingUserInfoKey: Any] private let nilDecodingStrategy: NilDecodingStrategy - init(codingPath: [CodingKey], storage: [Any], userInfo: [CodingUserInfoKey: Any], nilDecodingStrategy: NilDecodingStrategy) { + init(codingPath: [any CodingKey], storage: [Any], userInfo: [CodingUserInfoKey: Any], nilDecodingStrategy: NilDecodingStrategy) { self.codingPath = codingPath self.storage = storage self.userInfo = userInfo @@ -541,13 +541,13 @@ private extension KeyValueDecoder { return result } - mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { + mutating func nestedUnkeyedContainer() throws -> any UnkeyedDecodingContainer { let result = try Decoder(container: nextContainer()).unkeyedContainer() currentIndex = storage.index(after: currentIndex) return result } - mutating func superDecoder() -> Swift.Decoder { + mutating func superDecoder() -> any Swift.Decoder { let container = SingleContainer(value: storage, codingPath: codingPath, userInfo: userInfo, nilDecodingStrategy: nilDecodingStrategy) return Decoder(container: container) } diff --git a/Sources/KeyValueEncoder.swift b/Sources/KeyValueEncoder.swift index 683001b..69a2b90 100644 --- a/Sources/KeyValueEncoder.swift +++ b/Sources/KeyValueEncoder.swift @@ -145,11 +145,11 @@ private extension KeyValueEncoder { final class Encoder: Swift.Encoder { - let codingPath: [CodingKey] + let codingPath: [any CodingKey] let userInfo: [CodingUserInfoKey: Any] let nilEncodingStrategy: NilEncodingStrategy - init(codingPath: [CodingKey] = [], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { + init(codingPath: [any CodingKey] = [], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { self.codingPath = codingPath self.userInfo = userInfo self.nilEncodingStrategy = nilEncodingStrategy @@ -174,13 +174,13 @@ private extension KeyValueEncoder { return KeyedEncodingContainer(keyed) } - func unkeyedContainer() -> UnkeyedEncodingContainer { + func unkeyedContainer() -> any UnkeyedEncodingContainer { let unkeyed = UnkeyedContainer(codingPath: codingPath, userInfo: userInfo, nilEncodingStrategy: nilEncodingStrategy) container = .provider(unkeyed.getEncodedValue) return unkeyed } - func singleValueContainer() -> SingleValueEncodingContainer { + func singleValueContainer() -> any SingleValueEncodingContainer { let single = SingleContainer(codingPath: codingPath, userInfo: userInfo, nilEncodingStrategy: nilEncodingStrategy) container = .provider(single.getEncodedValue) return single @@ -201,11 +201,11 @@ private extension KeyValueEncoder { final class KeyedContainer: KeyedEncodingContainerProtocol { typealias Key = K - let codingPath: [CodingKey] + let codingPath: [any CodingKey] private let userInfo: [CodingUserInfoKey: Any] private let nilEncodingStrategy: NilEncodingStrategy - init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { + init(codingPath: [any CodingKey], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { self.codingPath = codingPath self.storage = [:] self.userInfo = userInfo @@ -307,18 +307,18 @@ private extension KeyValueEncoder { return KeyedEncodingContainer(keyed) } - func nestedUnkeyedContainer(forKey key: K) -> UnkeyedEncodingContainer { + func nestedUnkeyedContainer(forKey key: K) -> any UnkeyedEncodingContainer { let path = codingPath.appending(key: key) let unkeyed = UnkeyedContainer(codingPath: path, userInfo: userInfo, nilEncodingStrategy: nilEncodingStrategy) storage[key.stringValue] = .provider(unkeyed.getEncodedValue) return unkeyed } - func superEncoder() -> Swift.Encoder { + func superEncoder() -> any Swift.Encoder { return superEncoder(forKey: Key(stringValue: "super")!) } - func superEncoder(forKey key: Key) -> Swift.Encoder { + func superEncoder(forKey key: Key) -> any Swift.Encoder { let path = codingPath.appending(key: key) let encoder = Encoder(codingPath: path, userInfo: userInfo, nilEncodingStrategy: nilEncodingStrategy) storage[key.stringValue] = .provider(encoder.getEncodedValue) @@ -328,11 +328,11 @@ private extension KeyValueEncoder { final class UnkeyedContainer: Swift.UnkeyedEncodingContainer { - let codingPath: [CodingKey] + let codingPath: [any CodingKey] private let userInfo: [CodingUserInfoKey: Any] private let nilEncodingStrategy: NilEncodingStrategy - init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { + init(codingPath: [any CodingKey], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { self.codingPath = codingPath self.userInfo = userInfo self.nilEncodingStrategy = nilEncodingStrategy @@ -437,14 +437,14 @@ private extension KeyValueEncoder { return KeyedEncodingContainer(keyed) } - func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + func nestedUnkeyedContainer() -> any UnkeyedEncodingContainer { let path = codingPath.appending(index: count) let unkeyed = UnkeyedContainer(codingPath: path, userInfo: userInfo, nilEncodingStrategy: nilEncodingStrategy) storage.append(.provider(unkeyed.getEncodedValue)) return unkeyed } - func superEncoder() -> Swift.Encoder { + func superEncoder() -> any Swift.Encoder { let path = codingPath.appending(index: count) let encoder = Encoder(codingPath: path, userInfo: userInfo, nilEncodingStrategy: nilEncodingStrategy) storage.append(.provider(encoder.getEncodedValue)) @@ -454,11 +454,11 @@ private extension KeyValueEncoder { final class SingleContainer: SingleValueEncodingContainer { - let codingPath: [CodingKey] + let codingPath: [any CodingKey] private let userInfo: [CodingUserInfoKey: Any] private let nilEncodingStrategy: NilEncodingStrategy - init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { + init(codingPath: [any CodingKey], userInfo: [CodingUserInfoKey: Any], nilEncodingStrategy: NilEncodingStrategy) { self.codingPath = codingPath self.userInfo = userInfo self.nilEncodingStrategy = nilEncodingStrategy @@ -547,21 +547,21 @@ private extension KeyValueEncoder { } } -extension Array where Element == CodingKey { +extension Array where Element == any CodingKey { - func appending(key codingKey: CodingKey) -> [CodingKey] { + func appending(key codingKey: any CodingKey) -> [any CodingKey] { var path = self path.append(codingKey) return path } - func appending(index: Int) -> [CodingKey] { + func appending(index: Int) -> [any CodingKey] { var path = self path.append(AnyCodingKey(intValue: index)) return path } - func makeKeyPath(appending key: CodingKey? = nil) -> String { + func makeKeyPath(appending key: (any CodingKey)? = nil) -> String { var path = map(\.keyPath) if let key = key { path.append(key.keyPath) diff --git a/Tests/KeyValueDecoderTests.swift b/Tests/KeyValueDecoderTests.swift index 066571d..e381e1b 100644 --- a/Tests/KeyValueDecoderTests.swift +++ b/Tests/KeyValueDecoderTests.swift @@ -809,7 +809,7 @@ private extension KeyValueDecoder { return proxy.result! } - static func decodeUnkeyedValue(from value: [Any], with closure: @escaping (inout UnkeyedDecodingContainer) throws -> T) throws -> T { + static func decodeUnkeyedValue(from value: [Any], with closure: @escaping (inout any UnkeyedDecodingContainer) throws -> T) throws -> T { let proxy = StubDecoder.Proxy { decoder in var container = try decoder.unkeyedContainer() return try closure(&container) @@ -835,20 +835,20 @@ private extension CodingUserInfoKey { private struct StubDecoder: Decodable { final class Proxy { - private let closure: (Decoder) throws -> T + private let closure: (any Decoder) throws -> T private(set) var result: T? - init(_ closure: @escaping (Decoder) throws -> T) { + init(_ closure: @escaping (any Decoder) throws -> T) { self.closure = closure } - func decode(from decoder: Decoder) throws { + func decode(from decoder: any Decoder) throws { self.result = try closure(decoder) } } - init(from decoder: Decoder) throws { - let closure = decoder.userInfo[.decoder] as! (Decoder) throws -> Void + init(from decoder: any Decoder) throws { + let closure = decoder.userInfo[.decoder] as! (any Decoder) throws -> Void try closure(decoder) } } diff --git a/Tests/KeyValueEncoderTests.swift b/Tests/KeyValueEncoderTests.swift index 20056f4..c9dfd9a 100644 --- a/Tests/KeyValueEncoderTests.swift +++ b/Tests/KeyValueEncoderTests.swift @@ -668,7 +668,7 @@ final class KeyValueEncodedTests: XCTestCase { private extension KeyValueEncoder { static func encodeSingleValue(nilEncodingStrategy: NilEncodingStrategy = .default, - with closure: (inout SingleValueEncodingContainer) throws -> Void) throws -> EncodedValue { + with closure: (inout any SingleValueEncodingContainer) throws -> Void) throws -> EncodedValue { let encoder = KeyValueEncoder() encoder.nilEncodingStrategy = nilEncodingStrategy return try encoder.encodeValue { @@ -677,7 +677,7 @@ private extension KeyValueEncoder { } } - static func encodeUnkeyedValue(with closure: (inout UnkeyedEncodingContainer) throws -> Void) throws -> EncodedValue { + static func encodeUnkeyedValue(with closure: (inout any UnkeyedEncodingContainer) throws -> Void) throws -> EncodedValue { try KeyValueEncoder().encodeValue { var container = $0.unkeyedContainer() try closure(&container) @@ -695,7 +695,7 @@ private extension KeyValueEncoder { } } - func encodeValue(with closure: (Encoder) throws -> Void) throws -> EncodedValue { + func encodeValue(with closure: (any Encoder) throws -> Void) throws -> EncodedValue { try withoutActuallyEscaping(closure) { try self.encodeValue(StubEncoder(closure: $0)) } @@ -709,9 +709,9 @@ private extension KeyValueEncoder { } private struct StubEncoder: Encodable { - var closure: (Encoder) throws -> Void + var closure: (any Encoder) throws -> Void - func encode(to encoder: Encoder) throws { + func encode(to encoder: any Encoder) throws { try closure(encoder) } } @@ -783,11 +783,11 @@ private extension JSONDecoder { } private struct Empty: Encodable { - func encode(to encoder: Encoder) throws { } + func encode(to encoder: any Encoder) throws { } } private struct Null: Encodable { - func encode(to encoder: Encoder) throws { + func encode(to encoder: any Encoder) throws { var container = encoder.singleValueContainer() try container.encodeNil() }