@@ -176,18 +176,46 @@ package func withTimeout<T: Sendable>(
176176 _ duration: Duration ,
177177 _ body: @escaping @Sendable ( ) async throws -> T
178178) async throws -> T {
179- try await withThrowingTaskGroup ( of: T . self) { taskGroup in
180- taskGroup. addTask {
181- try await Task . sleep ( for: duration)
182- throw TimeoutError ( )
179+ var mutableTasks : [ Task < Void , Error > ] = [ ]
180+ let stream = AsyncThrowingStream < T , Error > { continuation in
181+ let bodyTask = Task < Void , Error > {
182+ do {
183+ let result = try await body ( )
184+ continuation. yield ( result)
185+ } catch {
186+ continuation. yield ( with: . failure( error) )
187+ }
183188 }
184- taskGroup. addTask {
185- return try await body ( )
189+
190+ let timeoutTask = Task {
191+ try await Task . sleep ( for: duration)
192+ bodyTask. cancel ( )
193+ continuation. yield ( with: . failure( TimeoutError ( ) ) )
186194 }
187- for try await value in taskGroup {
188- taskGroup. cancelAll ( )
195+ mutableTasks = [ bodyTask, timeoutTask]
196+ }
197+
198+ let tasks = mutableTasks
199+
200+ return try await withTaskPriorityChangedHandler {
201+ for try await value in stream {
189202 return value
190203 }
191- throw CancellationError ( )
204+ // The only reason for the loop above to terminate is if the Task got cancelled or if the continuation finishes
205+ // (which it never does).
206+ if Task . isCancelled {
207+ for task in tasks {
208+ task. cancel ( )
209+ }
210+ throw CancellationError ( )
211+ } else {
212+ preconditionFailure ( " Continuation never finishes " )
213+ }
214+ } taskPriorityChanged: {
215+ for task in tasks {
216+ Task ( priority: Task . currentPriority) {
217+ _ = try ? await task. value
218+ }
219+ }
192220 }
193221}
0 commit comments