Skip to content

Commit 8578584

Browse files
authored
Implementations for operators and async functions on AsyncSequence per SE-0298 (#35740)
* Implementations for operators and async functions on AsyncSequence per SE-0298 * Add trailing new lines to AsyncSequence adopter files * Remove extra // from preambles * Transition sequence properties and sequence initializers to internal * Rename Upstream to Base * Rename "Failable" asynchronous sequences to "Throwing" * Make iteration consistent with closure lifetimes and track failure via state * Use for await syntax for async function extensions on AsyncSequence * Work-around rethrows calculations being incorrect for conformance + closure rethrowing * Update testing names to reflect Throwing versus Failable * Incorperate runAsyncAndBlock into the test function for suite calls * Remove @Frozen from AsyncSequence operators * Back out reduce family functions for now due to IRGen bug * Additional corrections for throwing cases and fix up potential linux crasher * Add a upstream and throwing tests and correct flatMap's throwing behavior * Unify parameter names to count * Add a more helpful precondition on prefix * Add tests for throwing cases of non closure async functions on AsyncSequence * Correct missing count transition in dropFirst * Correct missing , in assertion * [NFC] add commentary on optimization in dropFirst on dropFirst * Disable collect tests for non macOS platforms for now * Disable all async sequence tests for non macOS platforms for now
1 parent 8564c94 commit 8578584

18 files changed

+2456
-23
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Swift
14+
15+
extension AsyncSequence {
16+
@inlinable
17+
public __consuming func compactMap<ElementOfResult>(
18+
_ transform: @escaping (Element) async -> ElementOfResult?
19+
) -> AsyncCompactMapSequence<Self, ElementOfResult> {
20+
return AsyncCompactMapSequence(self, transform: transform)
21+
}
22+
}
23+
24+
public struct AsyncCompactMapSequence<Base: AsyncSequence, ElementOfResult> {
25+
@usableFromInline
26+
let base: Base
27+
28+
@usableFromInline
29+
let transform: (Base.Element) async -> ElementOfResult?
30+
31+
@usableFromInline
32+
init(
33+
_ base: Base,
34+
transform: @escaping (Base.Element) async -> ElementOfResult?
35+
) {
36+
self.base = base
37+
self.transform = transform
38+
}
39+
}
40+
41+
extension AsyncCompactMapSequence: AsyncSequence {
42+
public typealias Element = ElementOfResult
43+
public typealias AsyncIterator = Iterator
44+
45+
public struct Iterator: AsyncIteratorProtocol {
46+
public typealias Element = ElementOfResult
47+
48+
@usableFromInline
49+
var baseIterator: Base.AsyncIterator
50+
51+
@usableFromInline
52+
let transform: (Base.Element) async -> ElementOfResult?
53+
54+
@usableFromInline
55+
init(
56+
_ baseIterator: Base.AsyncIterator,
57+
transform: @escaping (Base.Element) async -> ElementOfResult?
58+
) {
59+
self.baseIterator = baseIterator
60+
self.transform = transform
61+
}
62+
63+
@inlinable
64+
public mutating func next() async rethrows -> ElementOfResult? {
65+
while true {
66+
guard let element = try await baseIterator.next() else {
67+
return nil
68+
}
69+
70+
if let transformed = await transform(element) {
71+
return transformed
72+
}
73+
}
74+
}
75+
}
76+
77+
@inlinable
78+
public __consuming func makeAsyncIterator() -> Iterator {
79+
return Iterator(base.makeAsyncIterator(), transform: transform)
80+
}
81+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Swift
14+
15+
extension AsyncSequence {
16+
@inlinable
17+
public __consuming func dropFirst(
18+
_ count: Int = 1
19+
) -> AsyncDropFirstSequence<Self> {
20+
precondition(count >= 0,
21+
"Can't drop a negative number of elements from an async sequence")
22+
return AsyncDropFirstSequence(self, dropping: count)
23+
}
24+
}
25+
26+
public struct AsyncDropFirstSequence<Base: AsyncSequence> {
27+
@usableFromInline
28+
let base: Base
29+
30+
@usableFromInline
31+
let count: Int
32+
33+
@usableFromInline
34+
init(_ base: Base, dropping count: Int) {
35+
self.base = base
36+
self.count = count
37+
}
38+
}
39+
40+
extension AsyncDropFirstSequence: AsyncSequence {
41+
public typealias Element = Base.Element
42+
public typealias AsyncIterator = Iterator
43+
44+
public struct Iterator: AsyncIteratorProtocol {
45+
@usableFromInline
46+
var baseIterator: Base.AsyncIterator
47+
48+
@usableFromInline
49+
var count: Int
50+
51+
@usableFromInline
52+
init(_ baseIterator: Base.AsyncIterator, count: Int) {
53+
self.baseIterator = baseIterator
54+
self.count = count
55+
}
56+
57+
@inlinable
58+
public mutating func next() async rethrows -> Base.Element? {
59+
var remainingToDrop = count
60+
while remainingToDrop > 0 {
61+
guard try await baseIterator.next() != nil else {
62+
count = 0
63+
return nil
64+
}
65+
remainingToDrop -= 1
66+
}
67+
count = 0
68+
return try await baseIterator.next()
69+
}
70+
}
71+
72+
@inlinable
73+
public __consuming func makeAsyncIterator() -> Iterator {
74+
return Iterator(base.makeAsyncIterator(), count: count)
75+
}
76+
}
77+
78+
extension AsyncDropFirstSequence {
79+
@inlinable
80+
public __consuming func dropFirst(
81+
_ count: Int = 1
82+
) -> AsyncDropFirstSequence<Base> {
83+
// If this is already a AsyncDropFirstSequence, we can just sum the current
84+
// drop count and additional drop count.
85+
precondition(count >= 0,
86+
"Can't drop a negative number of elements from an async sequence")
87+
return AsyncDropFirstSequence(base, dropping: self.count + count)
88+
}
89+
}
90+
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Swift
14+
15+
extension AsyncSequence {
16+
@inlinable
17+
public __consuming func drop(
18+
while predicate: @escaping (Element) async -> Bool
19+
) -> AsyncDropWhileSequence<Self> {
20+
AsyncDropWhileSequence(self, predicate: predicate)
21+
}
22+
}
23+
24+
public struct AsyncDropWhileSequence<Base: AsyncSequence> {
25+
@usableFromInline
26+
let base: Base
27+
28+
@usableFromInline
29+
let predicate: (Base.Element) async -> Bool
30+
31+
@usableFromInline
32+
init(
33+
_ base: Base,
34+
predicate: @escaping (Base.Element) async -> Bool
35+
) {
36+
self.base = base
37+
self.predicate = predicate
38+
}
39+
}
40+
41+
extension AsyncDropWhileSequence: AsyncSequence {
42+
public typealias Element = Base.Element
43+
public typealias AsyncIterator = Iterator
44+
45+
public struct Iterator: AsyncIteratorProtocol {
46+
@usableFromInline
47+
var baseIterator: Base.AsyncIterator
48+
49+
@usableFromInline
50+
var predicate: ((Base.Element) async -> Bool)?
51+
52+
@usableFromInline
53+
init(
54+
_ baseIterator: Base.AsyncIterator,
55+
predicate: @escaping (Base.Element) async -> Bool
56+
) {
57+
self.baseIterator = baseIterator
58+
self.predicate = predicate
59+
}
60+
61+
@inlinable
62+
public mutating func next() async rethrows -> Base.Element? {
63+
while let predicate = self.predicate {
64+
guard let element = try await baseIterator.next() else {
65+
return nil
66+
}
67+
if await predicate(element) == false {
68+
self.predicate = nil
69+
return element
70+
}
71+
}
72+
return try await baseIterator.next()
73+
}
74+
}
75+
76+
@inlinable
77+
public __consuming func makeAsyncIterator() -> Iterator {
78+
return Iterator(base.makeAsyncIterator(), predicate: predicate)
79+
}
80+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Swift
14+
15+
extension AsyncSequence {
16+
@inlinable
17+
public __consuming func filter(
18+
_ isIncluded: @escaping (Element) async -> Bool
19+
) -> AsyncFilterSequence<Self> {
20+
return AsyncFilterSequence(self, isIncluded: isIncluded)
21+
}
22+
}
23+
24+
public struct AsyncFilterSequence<Base: AsyncSequence> {
25+
@usableFromInline
26+
let base: Base
27+
28+
@usableFromInline
29+
let isIncluded: (Element) async -> Bool
30+
31+
@usableFromInline
32+
init(
33+
_ base: Base,
34+
isIncluded: @escaping (Base.Element) async -> Bool
35+
) {
36+
self.base = base
37+
self.isIncluded = isIncluded
38+
}
39+
}
40+
41+
extension AsyncFilterSequence: AsyncSequence {
42+
public typealias Element = Base.Element
43+
public typealias AsyncIterator = Iterator
44+
45+
public struct Iterator: AsyncIteratorProtocol {
46+
@usableFromInline
47+
var baseIterator: Base.AsyncIterator
48+
49+
@usableFromInline
50+
let isIncluded: (Base.Element) async -> Bool
51+
52+
@usableFromInline
53+
init(
54+
_ baseIterator: Base.AsyncIterator,
55+
isIncluded: @escaping (Base.Element) async -> Bool
56+
) {
57+
self.baseIterator = baseIterator
58+
self.isIncluded = isIncluded
59+
}
60+
61+
@inlinable
62+
public mutating func next() async rethrows -> Base.Element? {
63+
while true {
64+
guard let element = try await baseIterator.next() else {
65+
return nil
66+
}
67+
if await isIncluded(element) {
68+
return element
69+
}
70+
}
71+
}
72+
}
73+
74+
@inlinable
75+
public __consuming func makeAsyncIterator() -> Iterator {
76+
return Iterator(base.makeAsyncIterator(), isIncluded: isIncluded)
77+
}
78+
}

0 commit comments

Comments
 (0)