@@ -44,6 +44,17 @@ public func withThrowingTimeout<T>(
4444 isolation: isolated ( any Actor ) ? = #isolation,
4545 seconds: TimeInterval ,
4646 body: ( ) async throws -> sending T
47+ ) async throws -> sending T {
48+ try await _withThrowingTimeout ( isolation: isolation, body: { _ in try await body ( ) } ) {
49+ try await Task . sleep ( nanoseconds: UInt64 ( seconds * 1_000_000_000 ) )
50+ throw TimeoutError ( " Task timed out before completion. Timeout: \( seconds) seconds. " )
51+ } . value
52+ }
53+
54+ public func withThrowingTimeout< T> (
55+ isolation: isolated ( any Actor ) ? = #isolation,
56+ seconds: TimeInterval ,
57+ body: ( Timeout ) async throws -> sending T
4758) async throws -> sending T {
4859 try await _withThrowingTimeout ( isolation: isolation, body: body) {
4960 try await Task . sleep ( nanoseconds: UInt64 ( seconds * 1_000_000_000 ) )
@@ -59,7 +70,7 @@ public func withThrowingTimeout<T, C: Clock>(
5970 clock: C ,
6071 body: ( ) async throws -> sending T
6172) async throws -> sending T {
62- try await _withThrowingTimeout ( isolation: isolation, body: body) {
73+ try await _withThrowingTimeout ( isolation: isolation, body: { _ in try await body ( ) } ) {
6374 try await Task . sleep ( until: instant, tolerance: tolerance, clock: clock)
6475 throw TimeoutError ( " Task timed out before completion. Deadline: \( instant) . " )
6576 } . value
@@ -72,39 +83,41 @@ public func withThrowingTimeout<T>(
7283 tolerance: ContinuousClock . Instant . Duration ? = nil ,
7384 body: ( ) async throws -> sending T
7485) async throws -> sending T {
75- try await _withThrowingTimeout ( isolation: isolation, body: body) {
86+ try await _withThrowingTimeout ( isolation: isolation, body: { _ in try await body ( ) } ) {
7687 try await Task . sleep ( until: instant, tolerance: tolerance, clock: ContinuousClock ( ) )
7788 throw TimeoutError ( " Task timed out before completion. Deadline: \( instant) . " )
7889 } . value
7990}
8091
8192private func _withThrowingTimeout< T> (
8293 isolation: isolated ( any Actor ) ? = #isolation,
83- body: ( ) async throws -> sending T,
84- timeout: @Sendable @escaping ( ) async throws -> Never
94+ body: ( Timeout ) async throws -> sending T,
95+ timeout closure : @Sendable @escaping ( ) async throws -> Never
8596) async throws -> Transferring < T > {
8697 try await withoutActuallyEscaping ( body) { escapingBody in
87- let bodyTask = Task {
88- defer { _ = isolation }
89- return try await Transferring ( escapingBody ( ) )
90- }
91- let timeoutTask = Task {
92- defer { bodyTask. cancel ( ) }
93- try await timeout ( )
94- }
98+ try await withNonEscapingTimeout ( closure) { timeout in
99+ let bodyTask = Task {
100+ defer { _ = isolation }
101+ return try await Transferring ( escapingBody ( timeout) )
102+ }
103+ let timeoutTask = Task {
104+ defer { bodyTask. cancel ( ) }
105+ try await timeout. waitForTimeout ( )
106+ }
95107
96- let bodyResult = await withTaskCancellationHandler {
97- await bodyTask. result
98- } onCancel: {
99- bodyTask. cancel ( )
100- }
101- timeoutTask. cancel ( )
108+ let bodyResult = await withTaskCancellationHandler {
109+ await bodyTask. result
110+ } onCancel: {
111+ bodyTask. cancel ( )
112+ }
113+ timeoutTask. cancel ( )
102114
103- if case . failure( let timeoutError) = await timeoutTask. result,
104- timeoutError is TimeoutError {
105- throw timeoutError
106- } else {
107- return try bodyResult. get ( )
115+ if case . failure( let timeoutError) = await timeoutTask. result,
116+ timeoutError is TimeoutError {
117+ throw timeoutError
118+ } else {
119+ return try bodyResult. get ( )
120+ }
108121 }
109122 }
110123}
0 commit comments