forked from apple/swift-async-algorithms
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathAsyncReader+forEach.swift
More file actions
102 lines (96 loc) · 3.53 KB
/
Copy pathAsyncReader+forEach.swift
File metadata and controls
102 lines (96 loc) · 3.53 KB
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
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Async Algorithms open source project
//
// Copyright (c) 2026 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
//
//===----------------------------------------------------------------------===//
#if UnstableAsyncStreaming && compiler(>=6.4)
public import ContainersPreview
// swift-format-ignore: AmbiguousTrailingClosureOverload
@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
extension AsyncReader where Self: ~Copyable, Self: ~Escapable {
/// Iterates over all chunks from the reader, executing the provided body for each span.
///
/// This method continuously reads chunks from the async reader until the stream ends,
/// executing the provided closure for each span of elements read. The iteration terminates
/// when the reader produces an empty span, indicating the end of the stream.
///
/// - Parameter body: An asynchronous closure that processes each span of elements read
/// from the stream. The closure receives a `Span<ReadElement>` for each read operation.
///
/// - Throws: An `EitherError` containing either a `ReadFailure` from the read operation
/// or a `Failure` from the body closure.
///
/// ## Example
///
/// ```swift
/// var fileReader: FileAsyncReader = ...
///
/// // Process each chunk of data from the file
/// try await fileReader.forEach { chunk in
/// print("Processing \(chunk.count) elements")
/// // Process the chunk
/// }
/// ```
public consuming func forEachChunk<Failure: Error>(
body: (consuming InputSpan<ReadElement>) async throws(Failure) -> Void
) async throws(EitherError<ReadFailure, Failure>) {
var shouldContinue = true
while shouldContinue {
try await self.read { (next) throws(Failure) -> Void in
guard next.count > 0 else {
shouldContinue = false
return
}
try await body(next)
}
}
}
/// Iterates over all chunks from the reader, executing the provided body for each span.
///
/// This method continuously reads chunks from the async reader until the stream ends,
/// executing the provided closure for each span of elements read. The iteration terminates
/// when the reader produces an empty span, indicating the end of the stream.
///
/// - Parameter body: An asynchronous closure that processes each span of elements read
/// from the stream. The closure receives a `Span<ReadElement>` for each read operation.
///
/// - Throws: An error of type `Failure` from the body closure. Since this reader never fails,
/// only the body closure can throw errors.
///
/// ## Example
///
/// ```swift
/// var fileReader: FileAsyncReader = ...
///
/// // Process each chunk of data from the file
/// try await fileReader.forEach { chunk in
/// print("Processing \(chunk.count) elements")
/// // Process the chunk
/// }
/// ```
@inlinable
public consuming func forEachChunk(
body: (consuming InputSpan<ReadElement>) async -> Void
) async where ReadFailure == Never {
var shouldContinue = true
while shouldContinue {
do {
try await self.read { (next) -> Void in
guard next.count > 0 else {
shouldContinue = false
return
}
await body(next)
}
} catch {
fatalError()
}
}
}
}
#endif