fix: edge case in toAsyncIterator (#2335)

This commit is contained in:
Bartek Iwańczuk 2019-05-11 16:05:56 +02:00 committed by Ryan Dahl
parent cb93246f6d
commit 2c6b93e0a0
2 changed files with 47 additions and 1 deletions

View File

@ -29,6 +29,38 @@ testPerm({ read: true }, async function filesToAsyncIterator(): Promise<void> {
assertEquals(totalSize, 12);
});
test(async function readerToAsyncIterator(): Promise<void> {
// ref: https://github.com/denoland/deno/issues/2330
const encoder = new TextEncoder();
class TestReader implements Deno.Reader {
private offset = 0;
private buf = new Uint8Array(encoder.encode(this.s));
constructor(private readonly s: string) {}
async read(p: Uint8Array): Promise<Deno.ReadResult> {
const n = Math.min(p.byteLength, this.buf.byteLength - this.offset);
p.set(this.buf.slice(this.offset, this.offset + n));
this.offset += n;
return {
nread: n,
eof: this.offset === this.buf.byteLength
};
}
}
const reader = new TestReader("hello world!");
let totalSize = 0;
for await (const buf of Deno.toAsyncIterator(reader)) {
totalSize += buf.byteLength;
}
assertEquals(totalSize, 12);
});
testPerm({ write: false }, async function writePermFailure(): Promise<void> {
const filename = "tests/hello.txt";
const writeModes: Deno.OpenMode[] = ["w", "a", "x"];

View File

@ -144,6 +144,14 @@ export async function copy(dst: Writer, src: Reader): Promise<number> {
*/
export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array> {
const b = new Uint8Array(1024);
// Keep track if end-of-file has been reached, then
// signal that iterator is done during subsequent next()
// call. This is required because `r` can return a `ReadResult`
// with data read and EOF reached. But if iterator returns
// `done` then `value` is discarded.
//
// See https://github.com/denoland/deno/issues/2330 for reference.
let sawEof = false;
return {
[Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {
@ -151,10 +159,16 @@ export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array> {
},
async next(): Promise<IteratorResult<Uint8Array>> {
if (sawEof) {
return { value: new Uint8Array(), done: true };
}
const result = await r.read(b);
sawEof = result.eof;
return {
value: b.subarray(0, result.nread),
done: result.eof
done: false
};
}
};