File: AsyncSequence.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 (486 lines) | stat: -rw-r--r-- 20,035 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
//===----------------------------------------------------------------------===//
//
// 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 provides asynchronous, sequential, iterated access to its
/// elements.
///
/// An `AsyncSequence` resembles the `Sequence` type --- offering a list of
/// values you can step through one at a time --- and adds asynchronicity. An
/// `AsyncSequence` may have all, some, or none of its values available when
/// you first use it. Instead, you use `await` to receive values as they become
/// available.
///
/// As with `Sequence`, you typically iterate through an `AsyncSequence` with a
/// `for await`-`in` loop. However, because the caller must potentially wait for values,
/// you use the `await` keyword. The following example shows how to iterate
/// over `Counter`, a custom `AsyncSequence` that produces `Int` values from
/// `1` up to a `howHigh` value:
///
///     for await number in Counter(howHigh: 10) {
///         print(number, terminator: " ")
///     }
///     // Prints "1 2 3 4 5 6 7 8 9 10 "
///
/// An `AsyncSequence` doesn't generate or contain the values; it just defines
/// how you access them. Along with defining the type of values as an associated
/// type called `Element`, the `AsyncSequence` defines a `makeAsyncIterator()`
/// method. This returns an instance of type `AsyncIterator`. Like the standard
/// `IteratorProtocol`, the `AsyncIteratorProtocol` defines a single `next()`
/// method to produce elements. The difference is that the `AsyncIterator`
/// defines its `next()` method as `async`, which requires a caller to wait for
/// the next value with the `await` keyword.
///
/// `AsyncSequence` also defines methods for processing the elements you
/// receive, modeled on the operations provided by the basic `Sequence` in the
/// standard library. There are two categories of methods: those that return a
/// single value, and those that return another `AsyncSequence`.
///
/// Single-value methods eliminate the need for a `for await`-`in` loop, and instead
/// let you make a single `await` call. For example, the `contains(_:)` method
/// returns a Boolean value that indicates if a given value exists in the
/// `AsyncSequence`. Given the `Counter` sequence from the previous example,
/// you can test for the existence of a sequence member with a one-line call:
///
///     let found = await Counter(howHigh: 10).contains(5) // true
///
/// Methods that return another `AsyncSequence` return a type specific to the
/// method's semantics. For example, the `.map(_:)` method returns a
/// `AsyncMapSequence` (or a `AsyncThrowingMapSequence`, if the closure you
/// provide to the `map(_:)` method can throw an error). These returned
/// sequences don't eagerly await the next member of the sequence, which allows
/// the caller to decide when to start work. Typically, you'll iterate over
/// these sequences with `for await`-`in`, like the base `AsyncSequence` you started
/// with. In the following example, the `map(_:)` method transforms each `Int`
/// received from a `Counter` sequence into a `String`:
///
///     let stream = Counter(howHigh: 10)
///         .map { $0 % 2 == 0 ? "Even" : "Odd" }
///     for await s in stream {
///         print(s, terminator: " ")
///     }
///     // Prints "Odd Even Odd Even Odd Even Odd Even Odd Even "
///
@available(SwiftStdlib 5.1, *)
public protocol AsyncSequence<Element, Failure> {
  /// The type of asynchronous iterator that produces elements of this
  /// asynchronous sequence.
  associatedtype AsyncIterator: AsyncIteratorProtocol where AsyncIterator.Element == Element
  /// The type of element produced by this asynchronous sequence.
  associatedtype Element

  /// The type of errors produced when iteration over the sequence fails.
  @available(SwiftStdlib 6.0, *)
  associatedtype Failure: Error = any Error
      where AsyncIterator.Failure == Failure

  /// Creates the asynchronous iterator that produces elements of this
  /// asynchronous sequence.
  ///
  /// - Returns: An instance of the `AsyncIterator` type used to produce
  /// elements of the asynchronous sequence.
  __consuming func makeAsyncIterator() -> AsyncIterator
}

@available(SwiftStdlib 5.1, *)
extension AsyncSequence {
  /// Returns the result of combining the elements of the asynchronous sequence
  /// using the given closure.
  ///
  /// Use the `reduce(_:_:)` method to produce a single value from the elements of
  /// an entire sequence. For example, you can use this method on an sequence of
  /// numbers to find their sum or product.
  ///
  /// The `nextPartialResult` closure executes sequentially with an accumulating
  /// value initialized to `initialResult` and each element of the sequence.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `4`. The `reduce(_:_:)` method sums the values
  /// received from the asynchronous sequence.
  ///
  ///     let sum = await Counter(howHigh: 4)
  ///         .reduce(0) {
  ///             $0 + $1
  ///         }
  ///     print(sum)
  ///     // Prints "10"
  ///
  ///
  /// - Parameters:
  ///   - initialResult: The value to use as the initial accumulating value.
  ///     The `nextPartialResult` closure receives `initialResult` the first
  ///     time the closure runs.
  ///   - nextPartialResult: A closure that combines an accumulating value and
  ///     an element of the asynchronous sequence into a new accumulating value,
  ///     for use in the next call of the `nextPartialResult` closure or
  ///     returned to the caller.
  /// - Returns: The final accumulated value. If the sequence has no elements,
  ///   the result is `initialResult`.
  @inlinable
  public func reduce<Result>(
    _ initialResult: Result,
    _ nextPartialResult:
      (_ partialResult: Result, Element) async throws -> Result
  ) async rethrows -> Result {
    var accumulator = initialResult
    var iterator = makeAsyncIterator()
    while let element = try await iterator.next() {
      accumulator = try await nextPartialResult(accumulator, element)
    }
    return accumulator
  }

  /// Returns the result of combining the elements of the asynchronous sequence
  /// using the given closure, given a mutable initial value.
  ///
  /// Use the `reduce(into:_:)` method to produce a single value from the
  /// elements of an entire sequence. For example, you can use this method on a
  /// sequence of numbers to find their sum or product.
  ///
  /// The `nextPartialResult` closure executes sequentially with an accumulating
  /// value initialized to `initialResult` and each element of the sequence.
  ///
  /// Prefer this method over `reduce(_:_:)` for efficiency when the result is
  /// a copy-on-write type, for example an `Array` or `Dictionary`.
  ///
  /// - Parameters:
  ///   - initialResult: The value to use as the initial accumulating value.
  ///     The `nextPartialResult` closure receives `initialResult` the first
  ///     time the closure executes.
  ///   - nextPartialResult: A closure that combines an accumulating value and
  ///     an element of the asynchronous sequence into a new accumulating value,
  ///     for use in the next call of the `nextPartialResult` closure or
  ///     returned to the caller.
  /// - Returns: The final accumulated value. If the sequence has no elements,
  ///   the result is `initialResult`.
  @inlinable
  public func reduce<Result>(
    into initialResult: __owned Result,
    _ updateAccumulatingResult:
      (_ partialResult: inout Result, Element) async throws -> Void
  ) async rethrows -> Result {
    var accumulator = initialResult
    var iterator = makeAsyncIterator()
    while let element = try await iterator.next() {
      try await updateAccumulatingResult(&accumulator, element)
    }
    return accumulator
  }
}

@available(SwiftStdlib 5.1, *)
@inlinable
@inline(__always)
func _contains<Source: AsyncSequence>(
  _ self: Source,
  where predicate: (Source.Element) async throws -> Bool
) async rethrows -> Bool {
  for try await element in self {
    if try await predicate(element) {
      return true
    }
  }
  return false
}

@available(SwiftStdlib 5.1, *)
extension AsyncSequence {
  /// Returns a Boolean value that indicates whether the asynchronous sequence
  /// contains an element that satisfies the given predicate.
  ///
  /// You can use the predicate to check for an element of a type that doesn’t
  /// conform to the `Equatable` protocol, or to find an element that satisfies
  /// a general condition.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `10`. The `contains(where:)` method checks to see
  /// whether the sequence produces a value divisible by `3`:
  ///
  ///     let containsDivisibleByThree = await Counter(howHigh: 10)
  ///         .contains { $0 % 3 == 0 }
  ///     print(containsDivisibleByThree)
  ///     // Prints "true"
  ///
  /// The predicate executes each time the asynchronous sequence produces an
  /// element, until either the predicate finds a match or the sequence ends.
  ///
  /// - Parameter predicate: A closure that takes an element of the asynchronous
  ///   sequence as its argument and returns a Boolean value that indicates
  ///   whether the passed element represents a match.
  /// - Returns: `true` if the sequence contains an element that satisfies
  ///   predicate; otherwise, `false`.
  @inlinable
  public func contains(
    where predicate: (Element) async throws -> Bool
  ) async rethrows -> Bool {
    return try await _contains(self, where: predicate)
  }
  
  /// Returns a Boolean value that indicates whether all elements produced by the
  /// asynchronous sequence satisfy the given predicate.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `10`. The `allSatisfy(_:)` method checks to see whether
  /// all elements produced by the sequence are less than `10`.
  ///
  ///     let allLessThanTen = await Counter(howHigh: 10)
  ///         .allSatisfy { $0 < 10 }
  ///     print(allLessThanTen)
  ///     // Prints "false"
  ///
  /// The predicate executes each time the asynchronous sequence produces an
  /// element, until either the predicate returns `false` or the sequence ends.
  ///
  /// If the asynchronous sequence is empty, this method returns `true`.
  ///
  /// - Parameter predicate: A closure that takes an element of the asynchronous
  ///   sequence as its argument and returns a Boolean value that indicates
  ///   whether the passed element satisfies a condition.
  /// - Returns: `true` if the sequence contains only elements that satisfy
  ///   `predicate`; otherwise, `false`.
  @inlinable
  public func allSatisfy(
    _ predicate: (Element) async throws -> Bool
  ) async rethrows -> Bool {
    return try await !contains { try await !predicate($0) }
  }
}

@available(SwiftStdlib 5.1, *)
extension AsyncSequence where Element: Equatable {
  /// Returns a Boolean value that indicates whether the asynchronous sequence
  /// contains the given element.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `10`. The `contains(_:)` method checks to see whether
  /// the sequence produces the value `5`:
  ///
  ///     let containsFive = await Counter(howHigh: 10)
  ///         .contains(5)
  ///     print(containsFive)
  ///     // Prints "true"
  ///
  /// - Parameter search: The element to find in the asynchronous sequence.
  /// - Returns: `true` if the method found the element in the asynchronous
  ///   sequence; otherwise, `false`.
  @inlinable
  public func contains(_ search: Element) async rethrows -> Bool {
    for try await element in self {
      if element == search {
        return true
      }
    }
    return false
  }
}

@available(SwiftStdlib 5.1, *)
@inlinable
@inline(__always)
func _first<Source: AsyncSequence>(
  _ self: Source,
  where predicate: (Source.Element) async throws -> Bool
) async rethrows -> Source.Element? {
  for try await element in self {
    if try await predicate(element) {
      return element
    }
  }
  return nil
}

@available(SwiftStdlib 5.1, *)
extension AsyncSequence {
  /// Returns the first element of the sequence that satisfies the given
  /// predicate.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `10`. The `first(where:)` method returns the first
  /// member of the sequence that's evenly divisible by both `2` and `3`.
  ///
  ///     let divisibleBy2And3 = await Counter(howHigh: 10)
  ///         .first { $0 % 2 == 0 && $0 % 3 == 0 }
  ///     print(divisibleBy2And3 ?? "none")
  ///     // Prints "6"
  ///
  /// The predicate executes each time the asynchronous sequence produces an
  /// element, until either the predicate finds a match or the sequence ends.
  ///
  /// - Parameter predicate: A closure that takes an element of the asynchronous
  ///  sequence as its argument and returns a Boolean value that indicates
  ///  whether the element is a match.
  /// - Returns: The first element of the sequence that satisfies `predicate`,
  ///   or `nil` if there is no element that satisfies `predicate`.
  @inlinable
  public func first(
    where predicate: (Element) async throws -> Bool
  ) async rethrows -> Element? {
    return try await _first(self, where: predicate)
  }
}

@available(SwiftStdlib 5.1, *)
extension AsyncSequence {
  /// Returns the minimum element in the asynchronous sequence, using the given
  /// predicate as the comparison between elements.
  ///
  /// Use this method when the asynchronous sequence's values don't conform
  /// to `Comparable`, or when you want to apply a custom ordering to the
  /// sequence.
  ///
  /// The predicate must be a *strict weak ordering* over the elements. That is,
  /// for any elements `a`, `b`, and `c`, the following conditions must hold:
  ///
  /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
  /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
  ///   both `true`, then `areInIncreasingOrder(a, c)` is also
  ///   `true`. (Transitive comparability)
  /// - Two elements are *incomparable* if neither is ordered before the other
  ///   according to the predicate. If `a` and `b` are incomparable, and `b`
  ///   and `c` are incomparable, then `a` and `c` are also incomparable.
  ///   (Transitive incomparability)
  ///
  /// The following example uses an enumeration of playing cards ranks, `Rank`,
  /// which ranges from `ace` (low) to `king` (high). An asynchronous sequence
  /// called `RankCounter` produces all elements of the array. The predicate
  /// provided to the `min(by:)` method sorts ranks based on their `rawValue`:
  ///
  ///     enum Rank: Int {
  ///         case ace = 1, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king
  ///     }
  ///
  ///     let min = await RankCounter()
  ///         .min { $0.rawValue < $1.rawValue }
  ///     print(min ?? "none")
  ///     // Prints "ace"
  ///
  /// - Parameter areInIncreasingOrder: A predicate that returns `true` if its
  ///   first argument should be ordered before its second argument; otherwise,
  ///   `false`.
  /// - Returns: The sequence’s minimum element, according to
  ///   `areInIncreasingOrder`. If the sequence has no elements, returns `nil`.
  @inlinable
  @warn_unqualified_access
  public func min(
    by areInIncreasingOrder: (Element, Element) async throws -> Bool
  ) async rethrows -> Element? {
    var it = makeAsyncIterator()
    guard var result = try await it.next() else { 
      return nil 
    }
    while let e = try await it.next() {
      if try await areInIncreasingOrder(e, result) { 
        result = e 
      }
    }
    return result
  }
  
  /// Returns the maximum element in the asynchronous sequence, using the given
  /// predicate as the comparison between elements.
  ///
  /// Use this method when the asynchronous sequence's values don't conform
  /// to `Comparable`, or when you want to apply a custom ordering to the
  /// sequence.
  ///
  /// The predicate must be a *strict weak ordering* over the elements. That is,
  /// for any elements `a`, `b`, and `c`, the following conditions must hold:
  ///
  /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
  /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
  ///   both `true`, then `areInIncreasingOrder(a, c)` is also
  ///   `true`. (Transitive comparability)
  /// - Two elements are *incomparable* if neither is ordered before the other
  ///   according to the predicate. If `a` and `b` are incomparable, and `b`
  ///   and `c` are incomparable, then `a` and `c` are also incomparable.
  ///   (Transitive incomparability)
  ///
  /// The following example uses an enumeration of playing cards ranks, `Rank`,
  /// which ranges from `ace` (low) to `king` (high). An asynchronous sequence
  /// called `RankCounter` produces all elements of the array. The predicate
  /// provided to the `max(by:)` method sorts ranks based on their `rawValue`:
  ///
  ///     enum Rank: Int {
  ///         case ace = 1, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king
  ///     }
  ///
  ///     let max = await RankCounter()
  ///         .max { $0.rawValue < $1.rawValue }
  ///     print(max ?? "none")
  ///     // Prints "king"
  ///
  /// - Parameter areInIncreasingOrder: A predicate that returns `true` if its
  ///   first argument should be ordered before its second argument; otherwise,
  ///   `false`.
  /// - Returns: The sequence’s minimum element, according to
  ///   `areInIncreasingOrder`. If the sequence has no elements, returns `nil`.
  @inlinable
  @warn_unqualified_access
  public func max(
    by areInIncreasingOrder: (Element, Element) async throws -> Bool
  ) async rethrows -> Element? {
    var it = makeAsyncIterator()
    guard var result = try await it.next() else { 
      return nil 
    }
    while let e = try await it.next() {
      if try await areInIncreasingOrder(result, e) { 
        result = e 
      }
    }
    return result
  }
}

@available(SwiftStdlib 5.1, *)
extension AsyncSequence where Element: Comparable {
  /// Returns the minimum element in an asynchronous sequence of comparable
  /// elements.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `10`. The `min()` method returns the minimum value
  /// of the sequence.
  ///
  ///     let min = await Counter(howHigh: 10)
  ///         .min()
  ///     print(min ?? "none")
  ///     // Prints "1"
  ///
  /// - Returns: The sequence’s minimum element. If the sequence has no
  ///   elements, returns `nil`.
  @inlinable
  @warn_unqualified_access
  public func min() async rethrows -> Element? {
    return try await self.min(by: <)
  }

  /// Returns the maximum element in an asynchronous sequence of comparable
  /// elements.
  ///
  /// In this example, an asynchronous sequence called `Counter` produces `Int`
  /// values from `1` to `10`. The `max()` method returns the max value
  /// of the sequence.
  ///
  ///     let max = await Counter(howHigh: 10)
  ///         .max()
  ///     print(max ?? "none")
  ///     // Prints "10"
  ///
  /// - Returns: The sequence’s maximum element. If the sequence has no
  ///   elements, returns `nil`.
  @inlinable
  @warn_unqualified_access
  public func max() async rethrows -> Element? {
    return try await self.max(by: <)
  }
}