/
AsyncPrefixWhileSequence.swift
122 lines (110 loc) · 4.17 KB
/
AsyncPrefixWhileSequence.swift
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
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 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
@available(SwiftStdlib 5.1, *)
extension AsyncSequence {
/// Returns an asynchronous sequence, containing the initial, consecutive
/// elements of the base sequence that satisfy the given predicate.
///
/// Use `prefix(while:)` to produce values while elements from the base
/// sequence meet a condition you specify. The modified sequence ends when
/// the predicate closure returns `false`.
///
/// In this example, an asynchronous sequence called `Counter` produces `Int`
/// values from `1` to `10`. The `prefix(while:)` method causes the modified
/// sequence to pass along values so long as they aren’t divisible by `2` and
/// `3`. Upon reaching `6`, the sequence ends:
///
/// let stream = Counter(howHigh: 10)
/// .prefix { $0 % 2 != 0 || $0 % 3 != 0 }
/// for try await number in stream {
/// print("\(number) ", terminator: " ")
/// }
/// // prints "1 2 3 4 5"
///
/// - Parameter predicate: A closure that takes an element as a parameter and
/// returns a Boolean value indicating whether the element should be
/// included in the modified sequence.
/// - Returns: An asynchronous sequence of the initial, consecutive
/// elements that satisfy `predicate`.
@inlinable
public __consuming func prefix(
while predicate: @escaping (Element) async -> Bool
) rethrows -> AsyncPrefixWhileSequence<Self> {
return AsyncPrefixWhileSequence(self, predicate: predicate)
}
}
/// An asynchronous sequence, containing the initial, consecutive
/// elements of the base sequence that satisfy a given predicate.
@available(SwiftStdlib 5.1, *)
public struct AsyncPrefixWhileSequence<Base: AsyncSequence> {
@usableFromInline
let base: Base
@usableFromInline
let predicate: (Base.Element) async -> Bool
@usableFromInline
init(
_ base: Base,
predicate: @escaping (Base.Element) async -> Bool
) {
self.base = base
self.predicate = predicate
}
}
@available(SwiftStdlib 5.1, *)
extension AsyncPrefixWhileSequence: AsyncSequence {
/// The type of element produced by this asynchronous sequence.
///
/// The prefix-while sequence produces whatever type of element its base
/// iterator produces.
public typealias Element = Base.Element
/// The type of iterator that produces elements of the sequence.
public typealias AsyncIterator = Iterator
/// The iterator that produces elements of the prefix-while sequence.
public struct Iterator: AsyncIteratorProtocol {
@usableFromInline
var predicateHasFailed = false
@usableFromInline
var baseIterator: Base.AsyncIterator
@usableFromInline
let predicate: (Base.Element) async -> Bool
@usableFromInline
init(
_ baseIterator: Base.AsyncIterator,
predicate: @escaping (Base.Element) async -> Bool
) {
self.baseIterator = baseIterator
self.predicate = predicate
}
/// Produces the next element in the prefix-while sequence.
///
/// If the predicate hasn't yet failed, this method gets the next element
/// from the base sequence and calls the predicate with it. If this call
/// succeeds, this method passes along the element. Otherwise, it returns
/// `nil`, ending the sequence.
@inlinable
public mutating func next() async rethrows -> Base.Element? {
if !predicateHasFailed, let nextElement = try await baseIterator.next() {
if await predicate(nextElement) {
return nextElement
} else {
predicateHasFailed = true
}
}
return nil
}
}
@inlinable
public __consuming func makeAsyncIterator() -> Iterator {
return Iterator(base.makeAsyncIterator(), predicate: predicate)
}
}