File: AsyncIteratorProtocol.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (125 lines) | stat: -rw-r--r-- 4,846 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Swift

/// A type that asynchronously supplies the values of a sequence one at a
/// time.
///
/// The `AsyncIteratorProtocol` defines the type returned by the
/// `makeAsyncIterator()` method of the `AsyncSequence` protocol. In short,
/// the iterator is what produces the asynchronous sequence's values. The
/// protocol defines a single asynchronous method, `next()`, which either
/// produces the next element of the sequence, or returns `nil` to signal
/// the end of the sequence.
///
/// To implement your own `AsyncSequence`, implement a wrapped type that
/// conforms to `AsyncIteratorProtocol`. The following example shows a `Counter`
/// type that uses an inner iterator to monotonically generate `Int` values
/// until reaching a `howHigh` value. While this example isn't itself
/// asynchronous, it shows the shape of a custom sequence and iterator, and how
/// to use it as if it were asynchronous:
///
///     struct Counter: AsyncSequence {
///         typealias Element = Int
///         let howHigh: Int
///
///         struct AsyncIterator: AsyncIteratorProtocol {
///             let howHigh: Int
///             var current = 1
///
///             mutating func next() async -> Int? {
///                 // A genuinely asynchronous implementation uses the `Task`
///                 // API to check for cancellation here and return early.
///                 guard current <= howHigh else {
///                     return nil
///                 }
///
///                 let result = current
///                 current += 1
///                 return result
///             }
///         }
///
///         func makeAsyncIterator() -> AsyncIterator {
///             return AsyncIterator(howHigh: howHigh)
///         }
///     }
///
/// At the call site, this looks like:
///
///     for await number in Counter(howHigh: 10) {
///       print(number, terminator: " ")
///     }
///     // Prints "1 2 3 4 5 6 7 8 9 10 "
///
/// ### End of Iteration
///
/// The iterator returns `nil` to indicate the end of the sequence. After
/// returning `nil` (or throwing an error) from `next()`, the iterator enters
/// a terminal state, and all future calls to `next()` must return `nil`.
///
/// ### Cancellation
///
/// Types conforming to `AsyncIteratorProtocol` should use the cancellation
/// primitives provided by Swift's `Task` API. The iterator can choose how to
/// handle and respond to cancellation, including:
///
/// - Checking the `isCancelled` value of the current `Task` inside `next()`
///   and returning `nil` to terminate the sequence.
/// - Calling `checkCancellation()` on the `Task`, which throws a
///   `CancellationError`.
/// - Implementing `next()` with a
///   `withTaskCancellationHandler(handler:operation:)` invocation to
///   immediately react to cancellation.
///
/// If the iterator needs to clean up on cancellation, it can do so after
/// checking for cancellation as described above, or in `deinit` if it's
/// a reference type.
@available(SwiftStdlib 5.1, *)
public protocol AsyncIteratorProtocol<Element, Failure> {
  associatedtype Element

  /// The type of failure produced by iteration.
  @available(SwiftStdlib 6.0, *)
  associatedtype Failure: Error = any Error

  /// Asynchronously advances to the next element and returns it, or ends the
  /// sequence if there is no next element.
  ///
  /// - Returns: The next element, if it exists, or `nil` to signal the end of
  ///   the sequence.
  mutating func next() async throws -> Element?

  /// Asynchronously advances to the next element and returns it, or ends the
  /// sequence if there is no next element.
  ///
  /// - Returns: The next element, if it exists, or `nil` to signal the end of
  ///   the sequence.
  @available(SwiftStdlib 6.0, *)
  mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> Element?
}

@available(SwiftStdlib 5.1, *)
extension AsyncIteratorProtocol {
  /// Default implementation of `next()` in terms of `next()`, which is
  /// required to maintain backward compatibility with existing async iterators.
  @available(SwiftStdlib 6.0, *)
  @inlinable
  public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> Element? {
    do {
      return try await next()
    } catch {
      throw error as! Failure
    }
  }
}