diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2019-10-04 20:28:51 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-04 20:28:51 -0400 |
commit | b81e5db17aa8b3088d6034ddf86b79c69410f012 (patch) | |
tree | 579e4c23d60d1b0d038156bc28a04f74ea87b2f0 /cli/js/io.ts | |
parent | 9049213867d30f7df090a83b6baf3e0717a4d2d2 (diff) |
Merge deno_cli_snapshots into deno_cli (#3064)
Diffstat (limited to 'cli/js/io.ts')
-rw-r--r-- | cli/js/io.ts | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/cli/js/io.ts b/cli/js/io.ts new file mode 100644 index 000000000..1a7bf8c4c --- /dev/null +++ b/cli/js/io.ts @@ -0,0 +1,170 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +// Interfaces 100% copied from Go. +// Documentation liberally lifted from them too. +// Thank you! We love Go! + +// TODO(kt3k): EOF should be `unique symbol` type. +// That might require some changes of ts_library_builder. +// See #2591 for more details. +export const EOF = null; +export type EOF = null; + +// Seek whence values. +// https://golang.org/pkg/io/#pkg-constants +export enum SeekMode { + SEEK_START = 0, + SEEK_CURRENT = 1, + SEEK_END = 2 +} + +// Reader is the interface that wraps the basic read() method. +// https://golang.org/pkg/io/#Reader +export interface Reader { + /** Reads up to p.byteLength bytes into `p`. It resolves to the number + * of bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error encountered. + * Even if `read()` returns `n` < `p.byteLength`, it may use all of `p` as + * scratch space during the call. If some data is available but not + * `p.byteLength` bytes, `read()` conventionally returns what is available + * instead of waiting for more. + * + * When `read()` encounters end-of-file condition, it returns EOF symbol. + * + * When `read()` encounters an error, it rejects with an error. + * + * Callers should always process the `n` > `0` bytes returned before + * considering the EOF. Doing so correctly handles I/O errors that happen + * after reading some bytes and also both of the allowed EOF behaviors. + * + * Implementations must not retain `p`. + */ + read(p: Uint8Array): Promise<number | EOF>; +} + +export interface SyncReader { + readSync(p: Uint8Array): number | EOF; +} + +// Writer is the interface that wraps the basic write() method. +// https://golang.org/pkg/io/#Writer +export interface Writer { + /** Writes `p.byteLength` bytes from `p` to the underlying data + * stream. It resolves to the number of bytes written from `p` (`0` <= `n` <= + * `p.byteLength`) and any error encountered that caused the write to stop + * early. `write()` must return a non-null error if it returns `n` < + * `p.byteLength`. write() must not modify the slice data, even temporarily. + * + * Implementations must not retain `p`. + */ + write(p: Uint8Array): Promise<number>; +} + +export interface SyncWriter { + writeSync(p: Uint8Array): number; +} +// https://golang.org/pkg/io/#Closer +export interface Closer { + // The behavior of Close after the first call is undefined. Specific + // implementations may document their own behavior. + close(): void; +} + +// https://golang.org/pkg/io/#Seeker +export interface Seeker { + /** Seek sets the offset for the next `read()` or `write()` to offset, + * interpreted according to `whence`: `SeekStart` means relative to the start + * of the file, `SeekCurrent` means relative to the current offset, and + * `SeekEnd` means relative to the end. Seek returns the new offset relative + * to the start of the file and an error, if any. + * + * Seeking to an offset before the start of the file is an error. Seeking to + * any positive offset is legal, but the behavior of subsequent I/O operations + * on the underlying object is implementation-dependent. + */ + seek(offset: number, whence: SeekMode): Promise<void>; +} + +export interface SyncSeeker { + seekSync(offset: number, whence: SeekMode): void; +} + +// https://golang.org/pkg/io/#ReadCloser +export interface ReadCloser extends Reader, Closer {} + +// https://golang.org/pkg/io/#WriteCloser +export interface WriteCloser extends Writer, Closer {} + +// https://golang.org/pkg/io/#ReadSeeker +export interface ReadSeeker extends Reader, Seeker {} + +// https://golang.org/pkg/io/#WriteSeeker +export interface WriteSeeker extends Writer, Seeker {} + +// https://golang.org/pkg/io/#ReadWriteCloser +export interface ReadWriteCloser extends Reader, Writer, Closer {} + +// https://golang.org/pkg/io/#ReadWriteSeeker +export interface ReadWriteSeeker extends Reader, Writer, Seeker {} + +/** Copies from `src` to `dst` until either `EOF` is reached on `src` + * or an error occurs. It returns the number of bytes copied and the first + * error encountered while copying, if any. + * + * Because `copy()` is defined to read from `src` until `EOF`, it does not + * treat an `EOF` from `read()` as an error to be reported. + */ +// https://golang.org/pkg/io/#Copy +export async function copy(dst: Writer, src: Reader): Promise<number> { + let n = 0; + const b = new Uint8Array(32 * 1024); + let gotEOF = false; + while (gotEOF === false) { + const result = await src.read(b); + if (result === EOF) { + gotEOF = true; + } else { + n += await dst.write(b.subarray(0, result)); + } + } + return n; +} + +/** Turns `r` into async iterator. + * + * for await (const chunk of toAsyncIterator(reader)) { + * console.log(chunk) + * } + */ +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 `number | EOF` + // 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> { + return this; + }, + + async next(): Promise<IteratorResult<Uint8Array>> { + if (sawEof) { + return { value: new Uint8Array(), done: true }; + } + + const result = await r.read(b); + if (result === EOF) { + sawEof = true; + return { value: new Uint8Array(), done: true }; + } + + return { + value: b.subarray(0, result), + done: false + }; + } + }; +} |