Skip to content

Commit 89f4442

Browse files
authored
Merge pull request #10 from swhitty/nonisolated(nonsending)
use nonisolated(nonsending) in Swift 6.2
2 parents cba5a29 + 2835256 commit 89f4442

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

Sources/withThrowingTimeout.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,88 @@ public struct TimeoutError: LocalizedError {
4040
}
4141
}
4242

43+
#if compiler(>=6.2)
44+
45+
nonisolated(nonsending) public func withThrowingTimeout<T>(
46+
seconds: TimeInterval,
47+
body: () async throws -> T
48+
) async throws -> T {
49+
try await _withThrowingTimeout(body: { _ in try await body() }) {
50+
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
51+
throw TimeoutError("Task timed out before completion. Timeout: \(seconds) seconds.")
52+
}.value
53+
}
54+
55+
nonisolated(nonsending) public func withThrowingTimeout<T>(
56+
seconds: TimeInterval,
57+
body: (TimeoutController) async throws -> T
58+
) async throws -> T {
59+
try await _withThrowingTimeout(body: body) {
60+
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
61+
throw TimeoutError("Task timed out before completion. Timeout: \(seconds) seconds.")
62+
}.value
63+
}
64+
65+
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
66+
nonisolated(nonsending) public func withThrowingTimeout<T, C: Clock>(
67+
after instant: C.Instant,
68+
tolerance: C.Instant.Duration? = nil,
69+
clock: C,
70+
body: () async throws -> sending T
71+
) async throws -> sending T {
72+
try await _withThrowingTimeout(body: { _ in try await body() }) {
73+
try await Task.sleep(until: instant, tolerance: tolerance, clock: clock)
74+
throw TimeoutError("Task timed out before completion. Deadline: \(instant).")
75+
}.value
76+
}
77+
78+
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
79+
nonisolated(nonsending) public func withThrowingTimeout<T>(
80+
after instant: ContinuousClock.Instant,
81+
tolerance: ContinuousClock.Instant.Duration? = nil,
82+
body: () async throws -> sending T
83+
) async throws -> sending T {
84+
try await _withThrowingTimeout(body: { _ in try await body() }) {
85+
try await Task.sleep(until: instant, tolerance: tolerance, clock: ContinuousClock())
86+
throw TimeoutError("Task timed out before completion. Deadline: \(instant).")
87+
}.value
88+
}
89+
90+
private func _withThrowingTimeout<T>(
91+
isolation: isolated (any Actor)? = #isolation,
92+
body: (TimeoutController) async throws -> T,
93+
timeout closure: @Sendable @escaping () async throws -> Never
94+
) async throws -> Transferring<T> {
95+
try await withoutActuallyEscaping(body) { escapingBody in
96+
try await withNonEscapingTimeout(closure) { timeout in
97+
let bodyTask = Task {
98+
defer { _ = isolation }
99+
return try await Transferring(escapingBody(timeout))
100+
}
101+
let timeoutTask = Task {
102+
defer { bodyTask.cancel() }
103+
try await timeout.waitForTimeout()
104+
}
105+
106+
let bodyResult = await withTaskCancellationHandler {
107+
await bodyTask.result
108+
} onCancel: {
109+
bodyTask.cancel()
110+
}
111+
timeoutTask.cancel()
112+
113+
if case .failure(let timeoutError) = await timeoutTask.result,
114+
timeoutError is TimeoutError {
115+
throw timeoutError
116+
} else {
117+
return try bodyResult.get()
118+
}
119+
}
120+
}
121+
}
122+
123+
#else
124+
43125
public func withThrowingTimeout<T>(
44126
isolation: isolated (any Actor)? = #isolation,
45127
seconds: TimeInterval,
@@ -121,3 +203,5 @@ private func _withThrowingTimeout<T>(
121203
}
122204
}
123205
}
206+
207+
#endif

0 commit comments

Comments
 (0)