mirror of
https://github.com/denoland/deno.git
synced 2024-11-22 15:06:54 -05:00
fix: edge case in toAsyncIterator (#2335)
This commit is contained in:
parent
cb93246f6d
commit
2c6b93e0a0
2 changed files with 47 additions and 1 deletions
|
@ -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"];
|
||||
|
|
16
js/io.ts
16
js/io.ts
|
@ -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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue