diff options
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/deno.ts | 3 | ||||
-rw-r--r-- | cli/js/io.ts | 47 | ||||
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 54 | ||||
-rw-r--r-- | cli/js/tests/files_test.ts | 91 | ||||
-rw-r--r-- | cli/js/web/fetch.ts | 2 |
5 files changed, 169 insertions, 28 deletions
diff --git a/cli/js/deno.ts b/cli/js/deno.ts index e35e8c161..b75df4a9d 100644 --- a/cli/js/deno.ts +++ b/cli/js/deno.ts @@ -42,7 +42,8 @@ export { FsEvent, fsEvents } from "./ops/fs_events.ts"; export { EOF, copy, - toAsyncIterator, + iter, + iterSync, SeekMode, Reader, SyncReader, diff --git a/cli/js/io.ts b/cli/js/io.ts index b5af34224..023718100 100644 --- a/cli/js/io.ts +++ b/cli/js/io.ts @@ -84,23 +84,32 @@ export async function copy(dst: Writer, src: Reader): Promise<number> { return n; } -export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array> { - const b = new Uint8Array(1024); - return { - [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> { - return this; - }, - - async next(): Promise<IteratorResult<Uint8Array>> { - const result = await r.read(b); - if (result === EOF) { - return { value: new Uint8Array(), done: true }; - } - - return { - value: b.subarray(0, result), - done: false, - }; - }, - }; +export async function* iter( + r: Reader, + bufSize?: number +): AsyncIterableIterator<Uint8Array> { + const b = new Uint8Array(bufSize ?? 1024); + while (true) { + const result = await r.read(b); + if (result === EOF) { + break; + } + + yield b.subarray(0, result); + } +} + +export function* iterSync( + r: SyncReader, + bufSize?: number +): IterableIterator<Uint8Array> { + const b = new Uint8Array(bufSize ?? 1024); + while (true) { + const result = r.readSync(b); + if (result === EOF) { + break; + } + + yield b.subarray(0, result); + } } diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index 9f2c854d9..ed2e40f84 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -573,13 +573,61 @@ declare namespace Deno { */ export function copy(dst: Writer, src: Reader): Promise<number>; - /** Turns a Reader, `r`, into an async iterator. + /** **UNSTABLE**: new API, yet to be vetted + * Turns a Reader, `r`, into an async iterator. + * + * let f = await open("/etc/passwd"); + * for await (const chunk of iter(f)) { + * console.log(chunk); + * } + * f.close(); + * + * Second argument can be used to tune size of a buffer. + * Default size of the buffer is 1024 bytes. * - * for await (const chunk of toAsyncIterator(reader)) { + * let f = await open("/etc/passwd"); + * for await (const chunk of iter(f, 1024 * 1024)) { * console.log(chunk); * } + * f.close(); + * + * Iterator uses internal buffer of fixed size for efficiency returning + * a view on that buffer on each iteration. It it therefore callers + * responsibility to copy contents of the buffer if needed; otherwise + * next iteration will overwrite contents of previously returned chunk. + */ + export function iter( + r: Reader, + bufSize?: number + ): AsyncIterableIterator<Uint8Array>; + + /** **UNSTABLE**: new API, yet to be vetted + * Turns a SyncReader, `r`, into an iterator. + * + * let f = await open("/etc/passwd"); + * for (const chunk of iterSync(reader)) { + * console.log(chunk); + * } + * f.close(); + * + * Second argument can be used to tune size of a buffer. + * Default size of the buffer is 1024 bytes. + * + * let f = await open("/etc/passwd"); + * for (const chunk of iterSync(reader, 1024 * 1024)) { + * console.log(chunk); + * } + * f.close() + * + * Iterator uses internal buffer of fixed size for efficiency returning + * a view on that buffer on each iteration. It it therefore callers + * responsibility to copy contents of the buffer if needed; otherwise + * next iteration will overwrite contents of previously returned chunk. */ - export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array>; + export function iterSync( + r: SyncReader, + bufSize?: number + ): IterableIterator<Uint8Array>; /** Synchronously open a file and return an instance of `Deno.File`. The * file does not need to previously exist if using the `create` or `createNew` diff --git a/cli/js/tests/files_test.ts b/cli/js/tests/files_test.ts index 1f7352afc..f68e5def4 100644 --- a/cli/js/tests/files_test.ts +++ b/cli/js/tests/files_test.ts @@ -25,23 +25,71 @@ unitTest({ perms: { read: true } }, async function filesCopyToStdout(): Promise< file.close(); }); +unitTest({ perms: { read: true } }, async function filesIter(): Promise<void> { + const filename = "cli/tests/hello.txt"; + const file = await Deno.open(filename); + + let totalSize = 0; + for await (const buf of Deno.iter(file)) { + totalSize += buf.byteLength; + } + + assertEquals(totalSize, 12); + file.close(); +}); + unitTest( { perms: { read: true } }, - async function filesToAsyncIterator(): Promise<void> { + async function filesIterCustomBufSize(): Promise<void> { const filename = "cli/tests/hello.txt"; const file = await Deno.open(filename); let totalSize = 0; - for await (const buf of Deno.toAsyncIterator(file)) { + let iterations = 0; + for await (const buf of Deno.iter(file, 6)) { + totalSize += buf.byteLength; + iterations += 1; + } + + assertEquals(totalSize, 12); + assertEquals(iterations, 2); + file.close(); + } +); + +unitTest({ perms: { read: true } }, function filesIterSync(): void { + const filename = "cli/tests/hello.txt"; + const file = Deno.openSync(filename); + + let totalSize = 0; + for (const buf of Deno.iterSync(file)) { + totalSize += buf.byteLength; + } + + assertEquals(totalSize, 12); + file.close(); +}); + +unitTest( + { perms: { read: true } }, + function filesIterSyncCustomBufSize(): void { + const filename = "cli/tests/hello.txt"; + const file = Deno.openSync(filename); + + let totalSize = 0; + let iterations = 0; + for (const buf of Deno.iterSync(file, 6)) { totalSize += buf.byteLength; + iterations += 1; } assertEquals(totalSize, 12); + assertEquals(iterations, 2); file.close(); } ); -unitTest(async function readerToAsyncIterator(): Promise<void> { +unitTest(async function readerIter(): Promise<void> { // ref: https://github.com/denoland/deno/issues/2330 const encoder = new TextEncoder(); @@ -69,7 +117,42 @@ unitTest(async function readerToAsyncIterator(): Promise<void> { const reader = new TestReader("hello world!"); let totalSize = 0; - for await (const buf of Deno.toAsyncIterator(reader)) { + for await (const buf of Deno.iter(reader)) { + totalSize += buf.byteLength; + } + + assertEquals(totalSize, 12); +}); + +unitTest(async function readerIterSync(): Promise<void> { + // ref: https://github.com/denoland/deno/issues/2330 + const encoder = new TextEncoder(); + + class TestReader implements Deno.SyncReader { + #offset = 0; + #buf: Uint8Array; + + constructor(s: string) { + this.#buf = new Uint8Array(encoder.encode(s)); + } + + readSync(p: Uint8Array): number | Deno.EOF { + const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset); + p.set(this.#buf.slice(this.#offset, this.#offset + n)); + this.#offset += n; + + if (n === 0) { + return Deno.EOF; + } + + return n; + } + } + + const reader = new TestReader("hello world!"); + + let totalSize = 0; + for await (const buf of Deno.iterSync(reader)) { totalSize += buf.byteLength; } diff --git a/cli/js/web/fetch.ts b/cli/js/web/fetch.ts index 2c16d5fb0..abb5f2aa2 100644 --- a/cli/js/web/fetch.ts +++ b/cli/js/web/fetch.ts @@ -248,7 +248,7 @@ class Body implements domTypes.Body, ReadableStream<Uint8Array>, io.ReadCloser { } [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> { - return io.toAsyncIterator(this); + return io.iter(this); } get bodyUsed(): boolean { |