From 9813dc726c78014de2cec49f18c577b742ca01f6 Mon Sep 17 00:00:00 2001 From: Dimitri Bouniol Date: Wed, 22 Jul 2026 04:36:12 -0700 Subject: [PATCH 1/2] Added a public constructor for buffered iterators --- .../AsyncBufferedIterator.swift | 6 ++++ .../AsyncReadSequence.swift | 2 +- .../AsyncBufferedIteratorTests.swift | 31 +++++++++++++++++++ .../AsyncSequenceReaderTests.swift | 4 +-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Sources/AsyncSequenceReader/AsyncBufferedIterator.swift b/Sources/AsyncSequenceReader/AsyncBufferedIterator.swift index 76950b1..1d3ec64 100644 --- a/Sources/AsyncSequenceReader/AsyncBufferedIterator.swift +++ b/Sources/AsyncSequenceReader/AsyncBufferedIterator.swift @@ -76,3 +76,9 @@ public struct AsyncBufferedIterator: AsyncI } extension AsyncBufferedIterator: Sendable where BaseIterator.Element: Sendable {} + +extension AsyncSequence { + public func makeBufferedIterator() -> AsyncBufferedIterator { + AsyncBufferedIterator(makeAsyncIterator()) + } +} diff --git a/Sources/AsyncSequenceReader/AsyncReadSequence.swift b/Sources/AsyncSequenceReader/AsyncReadSequence.swift index 74ec61c..99ba115 100644 --- a/Sources/AsyncSequenceReader/AsyncReadSequence.swift +++ b/Sources/AsyncSequenceReader/AsyncReadSequence.swift @@ -39,7 +39,7 @@ extension AsyncIteratorProtocol { results = try await sequenceTransform(readSequence) wrappedIterator = readSequence.baseIterator } - precondition(wrappedIterator.unconsumedBuffer.isEmpty, "A transform was requested, but the sequence was left in a state where the next value will never be read (fix: Use AnyReadableSequence(iterator) instead of calling `.transform` on `iterator` directly)") + precondition(wrappedIterator.unconsumedBuffer.isEmpty, "A transform was requested, but the sequence was left in a state where the next value will never be read (fix: Use `sequence.makeBufferedIterator()` instead of calling `.transform` on `iterator` directly)") self = wrappedIterator.baseIterator return results diff --git a/Tests/AsyncSequenceReaderTests/AsyncBufferedIteratorTests.swift b/Tests/AsyncSequenceReaderTests/AsyncBufferedIteratorTests.swift index 6cdb69c..46067aa 100644 --- a/Tests/AsyncSequenceReaderTests/AsyncBufferedIteratorTests.swift +++ b/Tests/AsyncSequenceReaderTests/AsyncBufferedIteratorTests.swift @@ -48,6 +48,37 @@ import Testing #expect(await bufferedIterator.next() == nil) } + @Test func bufferIteratorFromStreamConstructor() async throws { + let testStream = AsyncStream { continuation in + for value in 0..<10 { + continuation.yield(value) + } + continuation.finish() + } + + var iterator = testStream.makeBufferedIterator() + + #expect(await iterator.next() == 0) + #expect(await iterator.next() == 1) + #expect(await iterator.next() == 2) + #expect(await iterator.next() == 3) + #expect(await iterator.next() == 4) + #expect(await iterator.hasMoreData() == true) + #expect(await iterator.hasMoreData() == true) + #expect(await iterator.hasMoreData() == true) + #expect(await iterator.next() == 5) + #expect(try await iterator.nonIsolatedNext() == 6) + #expect(await iterator.next() == 7) + #expect(await iterator.next() == 8) + #expect(await iterator.hasMoreData() == true) + #expect(await iterator.next() == 9) + #expect(await iterator.hasMoreData() == false) + #expect(await iterator.next() == nil) + #expect(await iterator.hasMoreData() == false) + #expect(await iterator.hasMoreData() == false) + #expect(await iterator.next() == nil) + } + @Test func bufferIteratorFromTestSequence() async throws { let testStream = TestSequence(base: 0..<10) diff --git a/Tests/AsyncSequenceReaderTests/AsyncSequenceReaderTests.swift b/Tests/AsyncSequenceReaderTests/AsyncSequenceReaderTests.swift index c6e0439..cc64968 100644 --- a/Tests/AsyncSequenceReaderTests/AsyncSequenceReaderTests.swift +++ b/Tests/AsyncSequenceReaderTests/AsyncSequenceReaderTests.swift @@ -294,7 +294,7 @@ import Testing }) } #if DEBUG - #expect(result?.standardErrorUTF8Lines.first == "AsyncSequenceReader/AsyncReadSequence.swift:42: Precondition failed: A transform was requested, but the sequence was left in a state where the next value will never be read (fix: Use AnyReadableSequence(iterator) instead of calling `.transform` on `iterator` directly)") + #expect(result?.standardErrorUTF8Lines.first == "AsyncSequenceReader/AsyncReadSequence.swift:42: Precondition failed: A transform was requested, but the sequence was left in a state where the next value will never be read (fix: Use `sequence.makeBufferedIterator()` instead of calling `.transform` on `iterator` directly)") #endif } @@ -313,7 +313,7 @@ import Testing }) } #if DEBUG - #expect(result?.standardErrorUTF8Lines.first == "AsyncSequenceReader/AsyncReadSequence.swift:42: Precondition failed: A transform was requested, but the sequence was left in a state where the next value will never be read (fix: Use AnyReadableSequence(iterator) instead of calling `.transform` on `iterator` directly)") + #expect(result?.standardErrorUTF8Lines.first == "AsyncSequenceReader/AsyncReadSequence.swift:42: Precondition failed: A transform was requested, but the sequence was left in a state where the next value will never be read (fix: Use `sequence.makeBufferedIterator()` instead of calling `.transform` on `iterator` directly)") #endif } } From 6f8cb0e40903da3582d8e97e63639c4a65947752 Mon Sep 17 00:00:00 2001 From: Dimitri Bouniol Date: Wed, 22 Jul 2026 04:36:51 -0700 Subject: [PATCH 2/2] Updated README for Version 0.4.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b70bb5..7a701ca 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Please check the [releases](https://github.com/mochidev/AsyncSequenceReader/rele ```swift dependencies: [ - .package(url: "https://github.com/mochidev/AsyncSequenceReader.git", .upToNextMinor(from: "0.4.0")), + .package(url: "https://github.com/mochidev/AsyncSequenceReader.git", .upToNextMinor(from: "0.4.1")), ], ... targets: [