-
Notifications
You must be signed in to change notification settings - Fork 664
feat(io): re-introduce IO functions #4128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5e60457
8833f98
efbe2e8
73c2cb1
b287471
d1ef968
c3638fb
e94b83f
46ef06a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
| // This module is browser compatible. | ||
|
|
||
| import type { Closer } from "./types.ts"; | ||
|
|
||
| export function isCloser(value: unknown): value is Closer { | ||
| return typeof value === "object" && value !== null && value !== undefined && | ||
| "close" in value && | ||
| // deno-lint-ignore no-explicit-any | ||
| typeof (value as Record<string, any>)["close"] === "function"; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
| // This module is browser compatible. | ||
|
|
||
| export const DEFAULT_CHUNK_SIZE = 16_640; | ||
| export const DEFAULT_BUFFER_SIZE = 32 * 1024; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
| // This module is browser compatible. | ||
|
|
||
| import { DEFAULT_BUFFER_SIZE } from "./_constants.ts"; | ||
| import type { Reader, Writer } from "./types.ts"; | ||
|
|
||
| /** | ||
| * Copies from `src` to `dst` until either EOF (`null`) is read from `src` or | ||
| * an error occurs. It resolves to the number of bytes copied or rejects with | ||
| * the first error encountered while copying. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { copy } from "https://deno.land/std@$STD_VERSION/io/copy.ts"; | ||
| * | ||
| * const source = await Deno.open("my_file.txt"); | ||
| * const bytesCopied1 = await copy(source, Deno.stdout); | ||
| * const destination = await Deno.create("my_file_2.txt"); | ||
| * const bytesCopied2 = await copy(source, destination); | ||
| * ``` | ||
| * | ||
| * @param src The source to copy from | ||
| * @param dst The destination to copy to | ||
| * @param options Can be used to tune size of the buffer. Default size is 32kB | ||
| */ | ||
| export async function copy( | ||
| src: Reader, | ||
| dst: Writer, | ||
| options?: { | ||
| bufSize?: number; | ||
| }, | ||
| ): Promise<number> { | ||
| let n = 0; | ||
| const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; | ||
| const b = new Uint8Array(bufSize); | ||
| let gotEOF = false; | ||
| while (gotEOF === false) { | ||
| const result = await src.read(b); | ||
| if (result === null) { | ||
| gotEOF = true; | ||
| } else { | ||
| let nwritten = 0; | ||
| while (nwritten < result) { | ||
| nwritten += await dst.write(b.subarray(nwritten, result)); | ||
| } | ||
| n += nwritten; | ||
| } | ||
| } | ||
| return n; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
| import { copy } from "./copy.ts"; | ||
| import { assertEquals } from "../assert/assert_equals.ts"; | ||
|
|
||
| const SRC_PATH = "./io/testdata/copy-src.txt"; | ||
| const DST_PATH = "./io/testdata/copy-dst.txt"; | ||
|
|
||
| Deno.test("copy()", async () => { | ||
| try { | ||
| using srcFile = await Deno.open(SRC_PATH); | ||
| using dstFile = await Deno.open(DST_PATH, { | ||
| create: true, | ||
| write: true, | ||
| }); | ||
| await copy(srcFile, dstFile); | ||
| const srcOutput = await Deno.readFile(SRC_PATH); | ||
| const dstOutput = await Deno.readFile(DST_PATH); | ||
| assertEquals(srcOutput, dstOutput); | ||
| } finally { | ||
| await Deno.remove(DST_PATH); | ||
| } | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
| // This module is browser compatible. | ||
|
|
||
| import { concat } from "../bytes/concat.ts"; | ||
| import { DEFAULT_CHUNK_SIZE } from "./_constants.ts"; | ||
| import type { Reader, ReaderSync } from "./types.ts"; | ||
|
|
||
| /** | ||
| * Read {@linkcode Reader} `r` until EOF (`null`) and resolve to the content as | ||
| * {@linkcode Uint8Array}. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { readAll } from "https://deno.land/std@$STD_VERSION/io/read_all.ts"; | ||
| * | ||
| * // Example from stdin | ||
| * const stdinContent = await readAll(Deno.stdin); | ||
| * | ||
| * // Example from file | ||
| * const file = await Deno.open("my_file.txt", {read: true}); | ||
| * const myFileContent = await readAll(file); | ||
| * file.close(); | ||
| * ``` | ||
| */ | ||
| export async function readAll(reader: Reader): Promise<Uint8Array> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function differs from |
||
| const chunks: Uint8Array[] = []; | ||
| while (true) { | ||
| let chunk = new Uint8Array(DEFAULT_CHUNK_SIZE); | ||
| const n = await reader.read(chunk); | ||
| if (n === null) { | ||
| break; | ||
| } | ||
| if (n < DEFAULT_CHUNK_SIZE) { | ||
| chunk = chunk.subarray(0, n); | ||
| } | ||
| chunks.push(chunk); | ||
| } | ||
| return concat(chunks); | ||
| } | ||
|
|
||
| /** | ||
| * Synchronously reads {@linkcode ReaderSync} `r` until EOF (`null`) and returns | ||
| * the content as {@linkcode Uint8Array}. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { readAllSync } from "https://deno.land/std@$STD_VERSION/io/read_all.ts"; | ||
| * | ||
| * // Example from stdin | ||
| * const stdinContent = readAllSync(Deno.stdin); | ||
| * | ||
| * // Example from file | ||
| * const file = Deno.openSync("my_file.txt", {read: true}); | ||
| * const myFileContent = readAllSync(file); | ||
| * file.close(); | ||
| * ``` | ||
| */ | ||
| export function readAllSync(reader: ReaderSync): Uint8Array { | ||
| const chunks: Uint8Array[] = []; | ||
| while (true) { | ||
| const chunk = new Uint8Array(DEFAULT_CHUNK_SIZE); | ||
| const n = reader.readSync(chunk); | ||
| if (n === null) { | ||
| break; | ||
| } | ||
| if (n < DEFAULT_CHUNK_SIZE) { | ||
| chunks.push(chunk.subarray(0, n)); | ||
| break; | ||
| } | ||
| chunks.push(chunk); | ||
| } | ||
| return concat(chunks); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
|
|
||
| import { assert, assertEquals } from "../assert/mod.ts"; | ||
| import { readAll, readAllSync } from "./read_all.ts"; | ||
| import { Buffer } from "./buffer.ts"; | ||
| import { init } from "./_test_common.ts"; | ||
|
|
||
| Deno.test("readAll()", async () => { | ||
| const testBytes = init(); | ||
| assert(testBytes); | ||
| const reader = new Buffer(testBytes.buffer); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We rely on |
||
| const actualBytes = await readAll(reader); | ||
| assertEquals(testBytes, actualBytes); | ||
| }); | ||
|
|
||
| Deno.test("readAllSync()", () => { | ||
| const testBytes = init(); | ||
| assert(testBytes); | ||
| const reader = new Buffer(testBytes.buffer); | ||
| const actualBytes = readAllSync(reader); | ||
| assertEquals(testBytes, actualBytes); | ||
| }); | ||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. | ||
| // This module is browser compatible. | ||
|
|
||
| import { DEFAULT_CHUNK_SIZE } from "./_constants.ts"; | ||
| import { isCloser } from "./_common.ts"; | ||
| import type { Closer, Reader } from "./types.ts"; | ||
|
|
||
| /** Options for {@linkcode toReadableStream}. */ | ||
| export interface ToReadableStreamOptions { | ||
| /** If the `reader` is also a `Closer`, automatically close the `reader` | ||
| * when `EOF` is encountered, or a read error occurs. | ||
| * | ||
| * @default {true} | ||
| */ | ||
| autoClose?: boolean; | ||
|
|
||
| /** The size of chunks to allocate to read, the default is ~16KiB, which is | ||
| * the maximum size that Deno operations can currently support. */ | ||
| chunkSize?: number; | ||
|
|
||
| /** The queuing strategy to create the `ReadableStream` with. */ | ||
| strategy?: QueuingStrategy<Uint8Array>; | ||
| } | ||
|
|
||
| /** | ||
| * Create a {@linkcode ReadableStream} of {@linkcode Uint8Array}s from a | ||
| * {@linkcode Reader}. | ||
| * | ||
| * When the pull algorithm is called on the stream, a chunk from the reader | ||
| * will be read. When `null` is returned from the reader, the stream will be | ||
| * closed along with the reader (if it is also a `Closer`). | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { toReadableStream } from "https://deno.land/std@$STD_VERSION/io/to_readable_stream.ts"; | ||
| * | ||
| * const file = await Deno.open("./file.txt", { read: true }); | ||
| * const fileStream = toReadableStream(file); | ||
| * ``` | ||
| */ | ||
| export function toReadableStream( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: renamed from |
||
| reader: Reader | (Reader & Closer), | ||
| { | ||
| autoClose = true, | ||
| chunkSize = DEFAULT_CHUNK_SIZE, | ||
| strategy, | ||
| }: ToReadableStreamOptions = {}, | ||
| ): ReadableStream<Uint8Array> { | ||
| return new ReadableStream({ | ||
| async pull(controller) { | ||
| const chunk = new Uint8Array(chunkSize); | ||
| try { | ||
| const read = await reader.read(chunk); | ||
| if (read === null) { | ||
| if (isCloser(reader) && autoClose) { | ||
| reader.close(); | ||
| } | ||
| controller.close(); | ||
| return; | ||
| } | ||
| controller.enqueue(chunk.subarray(0, read)); | ||
| } catch (e) { | ||
| controller.error(e); | ||
| if (isCloser(reader)) { | ||
| reader.close(); | ||
| } | ||
| } | ||
| }, | ||
| cancel() { | ||
| if (isCloser(reader) && autoClose) { | ||
| reader.close(); | ||
| } | ||
| }, | ||
| }, strategy); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note:
Buffer()is not imported here as it's deprecated.