Skip to content

Instantly share code, notes, and snippets.

@moyerr
Created October 3, 2024 19:09
Show Gist options
  • Save moyerr/8778c755bbf6e584a1962bdb95ea7873 to your computer and use it in GitHub Desktop.
Save moyerr/8778c755bbf6e584a1962bdb95ea7873 to your computer and use it in GitHub Desktop.
An AsyncSequence that will terminate with a `Timeout` error if iteration time exceeds the provided `timeout`.
/// An AsyncSequence that will terminate with a `Timeout` error if
/// iteration time exceeds the provided `timeout`.
struct AsyncTimeoutSequence<Base: AsyncSequence, C: Clock> {
struct Timeout: Error {}
let base: Base
let timeout: C.Instant.Duration
let clock: C
init(_ base: Base, timeout: C.Instant.Duration, clock: C) {
self.base = base
self.timeout = timeout
self.clock = clock
}
}
extension AsyncTimeoutSequence: AsyncSequence {
typealias Element = Base.Element
struct AsyncIterator: AsyncIteratorProtocol {
var base: Base.AsyncIterator
let deadline: C.Instant
let clock: C
init(_ base: Base.AsyncIterator, timeout: C.Instant.Duration, clock: C) {
self.base = base
self.deadline = clock.now.advanced(by: timeout)
self.clock = clock
}
mutating func next() async throws -> Base.Element? {
guard clock.now < deadline else { throw Timeout() }
return try await base.next()
}
}
func makeAsyncIterator() -> AsyncIterator {
AsyncIterator(base.makeAsyncIterator(), timeout: timeout, clock: clock)
}
}
extension AsyncSequence {
func timeout(
after duration: Duration
) -> AsyncTimeoutSequence<Self, ContinuousClock> {
.init(self, timeout: duration, clock: .continuous)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment