Skip to content

Commit 6e3c3cc

Browse files
authored
feat: Support Swift 6 & strict concurrency (#110)
* chore: Swift 6 * chore: Swift 6 and Sendable --------- Co-authored-by: danthorpe <danthorpe@users.noreply.github.com>
1 parent ab0e574 commit 6e3c3cc

File tree

15 files changed

+85
-38
lines changed

15 files changed

+85
-38
lines changed

Package.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
// swift-tools-version: 5.9
2-
import PackageDescription
3-
4-
var package = Package(name: "swift-networking")
1+
// swift-tools-version: 6.0
2+
@preconcurrency import PackageDescription
3+
4+
var package = Package(
5+
name: "swift-networking",
6+
swiftLanguageModes: [
7+
.v5,
8+
.version("6"),
9+
]
10+
)
511

612
// MARK: 💫 Package Customization
713

@@ -158,9 +164,6 @@ extension Target.Dependency {
158164
static let deque: Target.Dependency = .product(
159165
name: "DequeModule", package: "swift-collections"
160166
)
161-
static let orderedCollections: Target.Dependency = .product(
162-
name: "OrderedCollections", package: "swift-collections"
163-
)
164167
static let httpTypes: Target.Dependency = .product(
165168
name: "HTTPTypes", package: "swift-http-types"
166169
)
@@ -405,7 +408,7 @@ infix operator <>
405408
extension String {
406409

407410
/// Adds the string as a module to the package, using the provided module
408-
static func <+ (lhs: String, rhs: Module) {
411+
@MainActor static func <+ (lhs: String, rhs: Module) {
409412
var module = rhs
410413
module.name = lhs
411414
package.add(module: module)
@@ -416,7 +419,7 @@ infix operator <+
416419
extension String {
417420

418421
/// Adds the string as a module to the package, allowing for inline customization
419-
static func <> (lhs: String, rhs: Module.Builder) {
422+
@MainActor static func <> (lhs: String, rhs: Module.Builder) {
420423
var module = Module(name: lhs)
421424
rhs(&module)
422425
package.add(module: module)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copied from: https://github.com/pointfreeco/swift-navigation/blob/main/Sources/SwiftNavigation/Internal/KeyPath%2BSendable.swift
2+
3+
#if compiler(>=6)
4+
package typealias _SendableKeyPath<Root, Value> = any KeyPath<Root, Value> & Sendable
5+
package typealias _SendableWritableKeyPath<Root, Value> = any WritableKeyPath<Root, Value>
6+
& Sendable
7+
#else
8+
package typealias _SendableKeyPath<Root, Value> = KeyPath<Root, Value>
9+
package typealias _SendableWritableKeyPath<Root, Value> = WritableKeyPath<Root, Value>
10+
#endif
11+
12+
// NB: Dynamic member lookup does not currently support sendable key paths and even breaks
13+
// autocomplete.
14+
//
15+
// * https://github.com/swiftlang/swift/issues/77035
16+
// * https://github.com/swiftlang/swift/issues/77105
17+
extension _AppendKeyPath {
18+
@_transparent
19+
package func unsafeSendable<Root, Value>() -> _SendableKeyPath<Root, Value>
20+
where Self == KeyPath<Root, Value> {
21+
#if compiler(>=6)
22+
unsafeBitCast(self, to: _SendableKeyPath<Root, Value>.self)
23+
#else
24+
self
25+
#endif
26+
}
27+
28+
@_transparent
29+
package func unsafeSendable<Root, Value>() -> _SendableWritableKeyPath<Root, Value>
30+
where Self == WritableKeyPath<Root, Value> {
31+
#if compiler(>=6)
32+
unsafeBitCast(self, to: _SendableWritableKeyPath<Root, Value>.self)
33+
#else
34+
self
35+
#endif
36+
}
37+
}

Sources/Networking/Components/Cached.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import Dependencies
22
import Foundation
33

44
extension NetworkingComponent {
5-
public func cached(in cache: Cache<AnyHashable, HTTPResponseData>) -> some NetworkingComponent {
5+
public func cached(in cache: Cache<HTTPRequestData, HTTPResponseData>) -> some NetworkingComponent {
66
modified(Cached()).networkEnvironment(\.cache) {
7-
CacheClient<AnyHashable, HTTPResponseData>.liveValue(with: cache)
7+
NetworkCacheClient.liveValue(with: cache)
88
}
99
}
1010
}

Sources/Networking/Components/Server/Server.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ extension NetworkingComponent {
1414
/// optional Logger if it's configured.
1515
/// - Returns: some ``NetworkingComponent``
1616
public func server<Value: Sendable>(
17-
mutate keyPath: WritableKeyPath<HTTPRequestData, Value>,
17+
mutate _keyPath: WritableKeyPath<HTTPRequestData, Value>,
1818
with transform: @escaping @Sendable (Value) -> Value,
1919
log: @escaping @Sendable (Logger?, HTTPRequestData) -> Void
2020
) -> some NetworkingComponent {
21-
server { request in
21+
let keyPath: _SendableWritableKeyPath<HTTPRequestData, Value> = _keyPath.unsafeSendable()
22+
return server { request in
2223
@NetworkEnvironment(\.logger) var logger
2324
let oldValue = request[keyPath: keyPath]
2425
let newValue = transform(oldValue)

Sources/Networking/Components/Traced.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ extension HTTPRequestData {
4949
}
5050

5151
public struct TraceParent: Sendable, Hashable, HTTPRequestDataOption {
52-
public static var defaultOption: Self?
52+
public static let defaultOption: Self? = nil
5353

5454
// Current version of the spec only supports 01 flag
5555
// Future versions of the spec will require support for bit-field mask

Sources/Networking/Core/Cache.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Dependencies
33
import DependenciesMacros
44
import Foundation
55

6-
public final class Cache<Key: Hashable, Value> {
6+
public final class Cache<Key: Hashable & Sendable, Value> {
77
private let _cache = NSCache<CacheKey, CacheObject>()
88
private let keyAccess = KeyAccess()
99

@@ -12,6 +12,8 @@ public final class Cache<Key: Hashable, Value> {
1212
}
1313
}
1414

15+
extension Cache: @unchecked Sendable where Value: Sendable { }
16+
1517
extension Cache {
1618
public var countLimit: Int {
1719
get { _cache.countLimit }
@@ -80,7 +82,7 @@ private extension Cache {
8082
}
8183

8284
extension Cache {
83-
final class CacheKey: NSObject {
85+
final class CacheKey: NSObject, Sendable {
8486
let key: Key
8587
override var hash: Int { key.hashValue }
8688
init(key: Key) {
@@ -91,7 +93,7 @@ extension Cache {
9193
return other.key == key
9294
}
9395
}
94-
final class CacheObject {
96+
final class CacheObject: NSObject {
9597
let cost: Int
9698
let key: Key
9799
let value: Value
@@ -103,7 +105,7 @@ extension Cache {
103105
self.expiresAt = expiresAt
104106
}
105107
}
106-
final class KeyAccess: NSObject, NSCacheDelegate {
108+
final class KeyAccess: NSObject, NSCacheDelegate, Sendable {
107109
let keys = LockIsolated<Set<Key>>([])
108110

109111
func insert(_ key: Key) {
@@ -160,7 +162,7 @@ extension Cache: Codable where Key: Codable, Value: Codable {
160162
}
161163

162164
@DependencyClient
163-
struct CacheClient<Key: Hashable, Value>: Sendable {
165+
struct CacheClient<Key: Hashable & Sendable, Value: Sendable>: Sendable {
164166
var insert: @Sendable (_ value: Value, _ forKey: Key, _ cost: Int, _ duration: TimeInterval?) -> Void
165167
var removeAll: @Sendable () -> Void
166168
var removeValue: @Sendable (_ forKey: Key) -> Void
@@ -185,11 +187,13 @@ extension CacheClient {
185187
}
186188
}
187189

188-
extension CacheClient: NetworkEnvironmentKey where Key == AnyHashable, Value == HTTPResponseData {}
190+
typealias NetworkCacheClient = CacheClient<HTTPRequestData, HTTPResponseData>
191+
192+
extension NetworkCacheClient: NetworkEnvironmentKey {}
189193

190194
extension NetworkEnvironmentValues {
191-
var cache: CacheClient<AnyHashable, HTTPResponseData>? {
192-
get { self[CacheClient<AnyHashable, HTTPResponseData>.self] }
193-
set { self[CacheClient<AnyHashable, HTTPResponseData>.self] = newValue }
195+
var cache: NetworkCacheClient? {
196+
get { self[NetworkCacheClient.self] }
197+
set { self[NetworkCacheClient.self] = newValue }
194198
}
195199
}

Sources/OAuth/ASWebAuthenticationSession+.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extension ASWebAuthenticationSession {
4343
}
4444
}
4545

46-
@MainActor public final class DefaultPresentationContext: NSObject, ASWebAuthenticationPresentationContextProviding {
46+
@MainActor public final class DefaultPresentationContext: NSObject, ASWebAuthenticationPresentationContextProviding, @unchecked Sendable {
4747
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
4848
#if os(macOS)
4949
ASPresentationAnchor()

Sources/OAuth/OAuthDelegate.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extension OAuth {
1111
let upstream: any NetworkingComponent
1212
var system: any OAuthSystem<Credentials>
1313

14-
var presentationContext: (any ASWebAuthenticationPresentationContextProviding)?
14+
var presentationContext: (any ASWebAuthenticationPresentationContextProviding & Sendable)?
1515

1616
@Dependency(\.webAuthenticationSession) var webAuthenticationSession
1717

@@ -24,7 +24,7 @@ extension OAuth {
2424
}
2525

2626
func set(
27-
presentationContext: any ASWebAuthenticationPresentationContextProviding
27+
presentationContext: any ASWebAuthenticationPresentationContextProviding & Sendable
2828
) {
2929
self.presentationContext = presentationContext
3030
}

Sources/OAuth/OAuthInstalledSystems.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import AuthenticationServices
22
import ConcurrencyExtras
33
import Dependencies
4+
import DependenciesMacros
45
import Helpers
56
import Networking
67
import Protected
@@ -17,6 +18,7 @@ extension OAuth {
1718
}
1819
}
1920

21+
@DependencyClient
2022
public struct InstalledSystems: Sendable {
2123
var set: @Sendable (_ container: Container) -> Void
2224
var get: @Sendable (_ key: ObjectIdentifier) -> Container?
@@ -37,8 +39,8 @@ extension OAuth {
3739
}
3840
}
3941

40-
extension OAuth.InstalledSystems: DependencyKey {
41-
public static var liveValue: OAuth.InstalledSystems = .basic()
42+
extension OAuth.InstalledSystems: TestDependencyKey {
43+
public static let testValue = OAuth.InstalledSystems()
4244

4345
public static func basic() -> Self {
4446
let storage = LockIsolated<[ObjectIdentifier: OAuth.Container]>([:])

Sources/OAuth/OAuthProxy.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Networking
44
public protocol OAuthProxy<Credentials>: Actor {
55
associatedtype Credentials: OAuthCredentials, Sendable
66

7-
func set(presentationContext: any ASWebAuthenticationPresentationContextProviding) async
7+
func set(presentationContext: any ASWebAuthenticationPresentationContextProviding & Sendable) async
88
func set(credentials: Credentials) async
99
func signIn() async throws
1010
func signOut() async
@@ -27,7 +27,7 @@ extension OAuth {
2727
await delegate.set(credentials: credentials)
2828
}
2929

30-
func set(presentationContext: any ASWebAuthenticationPresentationContextProviding) async {
30+
func set(presentationContext: any ASWebAuthenticationPresentationContextProviding & Sendable) async {
3131
await delegate.delegate.delegate.set(presentationContext: presentationContext)
3232
}
3333

0 commit comments

Comments
 (0)