From 36eb0ecd614d904d7353e0d0ecc65839f9004890 Mon Sep 17 00:00:00 2001 From: Philippe Hausler Date: Fri, 14 Oct 2022 11:43:58 -0700 Subject: [PATCH 1/2] Initial draft at a deadline algorithm --- Sources/AsyncAlgorithms/Deadline.swift | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Sources/AsyncAlgorithms/Deadline.swift diff --git a/Sources/AsyncAlgorithms/Deadline.swift b/Sources/AsyncAlgorithms/Deadline.swift new file mode 100644 index 00000000..60b6e508 --- /dev/null +++ b/Sources/AsyncAlgorithms/Deadline.swift @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Async Algorithms open source project +// +// Copyright (c) 2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +public struct TimeoutError: Error { + public let deadline: C.Instant + public let clock: C + + public init(_ deadline: C.Instant, _ clock: C) { + self.deadline = deadline + self.clock = clock + } +} + +@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +public func withDeadline( + _ deadline: C.Instant, + clock: C, + _ operation: @Sendable () async throws -> T +) async throws -> T { + return try await withoutActuallyEscaping(operation) { operation in + try await withThrowingTaskGroup(of: T.self) { group in + group.addTask(operation: operation) + group.addTask { + try await Task.sleep(until: deadline, clock: clock) + throw TimeoutError(deadline, clock) + } + defer { group.cancelAll() } + return try await group.next()! + } + } +} From 90f1cb52dec982f8b19c17b46f1832c5f49b2006 Mon Sep 17 00:00:00 2001 From: Philippe Hausler Date: Fri, 14 Oct 2022 13:29:27 -0700 Subject: [PATCH 2/2] Add timeout functions to take durations similar to Clock.sleep(for:) and Task.sleep(for:) --- Sources/AsyncAlgorithms/Deadline.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Sources/AsyncAlgorithms/Deadline.swift b/Sources/AsyncAlgorithms/Deadline.swift index 60b6e508..603361fc 100644 --- a/Sources/AsyncAlgorithms/Deadline.swift +++ b/Sources/AsyncAlgorithms/Deadline.swift @@ -38,3 +38,23 @@ public func withDeadline( } } } + +@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +public func withTimeout( + in duration: C.Duration, + clock: C, + _ operation: @Sendable () async throws -> T +) async throws -> T { + try await withDeadline( + clock.now.advanced(by: duration), + clock: clock, + operation) +} + +@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +public func withTimeout( + in duration: Duration, + _ operation: @Sendable () async throws -> T +) async throws -> T { + try await withTimeout(in: duration, clock: .continuous, operation) +}