Skip to content

Commit 04465e8

Browse files
Added AsyncReadSequence protocol
1 parent bef63de commit 04465e8

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// AsyncReadSequence.swift
3+
// AsyncSequenceReader
4+
//
5+
// Created by Dimitri Bouniol on 2021-11-17.
6+
// Copyright © 2021 Mochi Development, Inc. All rights reserved.
7+
//
8+
9+
#if compiler(>=5.5) && canImport(_Concurrency)
10+
11+
/// An AsyncSequence subtype suitable for reading an existing iterator in place.
12+
///
13+
/// Note that to conform to this protocol, your type must be a reference type. After iterating, you'll also likely want to copy the base iterator back into your starting iterator, as shown in ``AsyncIteratorProtocol.transform(with:readSequenceFactory:)``.
14+
public protocol AsyncReadSequence : AsyncSequence, AnyObject {
15+
associatedtype BaseIterator : AsyncIteratorProtocol where BaseIterator.Element == Element
16+
17+
@inlinable
18+
var baseIterator: AsyncBufferedIterator<BaseIterator> { get }
19+
}
20+
21+
extension AsyncIteratorProtocol {
22+
/// Transform the receiving iterator using the specified sequence transformer and configured read sequence.
23+
///
24+
/// - Note: Iterating over the read sequence multiple times will result in undefined behavior.
25+
///
26+
/// - Parameter sequenceTransform: A transformation that accepts a sequence that can be read from, or stopped prematurely by returning `nil`. The receiving iterator will have moved forward by the same amount of items consumed within `sequenceTransform`.
27+
/// - Parameter readSequenceFactory: A factory to create a suitable ``AsyncReadSequence`` that will determine the logical bounds of the transformation within the receiving iterator.
28+
/// - Returns: A transformed value read from the iterator, or `nil` if there were no values left to read.
29+
public mutating func transform<Transformed, ReadSequence: AsyncReadSequence>(
30+
with sequenceTransform: (ReadSequence) async throws -> Transformed,
31+
readSequenceFactory: (inout AsyncBufferedIterator<Self>) -> ReadSequence
32+
) async rethrows -> Transformed? where ReadSequence.BaseIterator == Self {
33+
var results: Transformed? = nil
34+
var wrappedIterator = AsyncBufferedIterator(self)
35+
if try await wrappedIterator.hasMoreData() {
36+
let readSequence = readSequenceFactory(&wrappedIterator)
37+
results = try await sequenceTransform(readSequence)
38+
wrappedIterator = readSequence.baseIterator
39+
}
40+
self = wrappedIterator.baseIterator
41+
42+
return results
43+
}
44+
}
45+
46+
extension AsyncBufferedIterator {
47+
/// Transform the receiving iterator using the specified sequence transformer and configured read sequence.
48+
///
49+
/// - Note: Iterating over the read sequence multiple times will result in undefined behavior.
50+
///
51+
/// - Parameter sequenceTransform: A transformation that accepts a sequence that can be read from, or stopped prematurely by returning `nil`. The receiving iterator will have moved forward by the same amount of items consumed within `sequenceTransform`.
52+
/// - Parameter readSequenceFactory: A factory to create a suitable ``AsyncReadSequence`` that will determine the logical bounds of the transformation within the receiving iterator.
53+
/// - Returns: A transformed value read from the iterator, or `nil` if there were no values left to read.
54+
public mutating func transform<Transformed, ReadSequence: AsyncReadSequence>(
55+
with sequenceTransform: (ReadSequence) async throws -> Transformed,
56+
readSequenceFactory: (inout Self) -> ReadSequence
57+
) async rethrows -> Transformed? where ReadSequence.BaseIterator == BaseIterator {
58+
59+
var results: Transformed? = nil
60+
if try await self.hasMoreData() {
61+
let readSequence = readSequenceFactory(&self)
62+
results = try await sequenceTransform(readSequence)
63+
self = readSequence.baseIterator
64+
}
65+
66+
return results
67+
}
68+
}
69+
70+
#endif

0 commit comments

Comments
 (0)