diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/buffer.ts | 29 | ||||
-rw-r--r-- | js/buffer_test.ts | 10 | ||||
-rw-r--r-- | js/deno.ts | 2 | ||||
m--------- | js/deps/https/deno.land/std | 0 | ||||
-rw-r--r-- | js/fetch.ts | 2 | ||||
-rw-r--r-- | js/files.ts | 29 | ||||
-rw-r--r-- | js/files_test.ts | 13 | ||||
-rw-r--r-- | js/io.ts | 49 | ||||
-rw-r--r-- | js/net.ts | 4 | ||||
-rw-r--r-- | js/net_test.ts | 27 | ||||
-rw-r--r-- | js/process_test.ts | 25 | ||||
-rw-r--r-- | js/xeval.ts | 11 |
12 files changed, 96 insertions, 105 deletions
diff --git a/js/buffer.ts b/js/buffer.ts index 15a26fb28..1f597282d 100644 --- a/js/buffer.ts +++ b/js/buffer.ts @@ -4,8 +4,7 @@ // Copyright 2009 The Go Authors. All rights reserved. BSD license. // https://github.com/golang/go/blob/master/LICENSE -//import * as io from "./io"; -import { Reader, Writer, ReadResult, SyncReader, SyncWriter } from "./io"; +import { Reader, Writer, EOF, SyncReader, SyncWriter } from "./io"; import { assert } from "./util"; import { TextDecoder } from "./text_encoding"; import { DenoError, ErrorKind } from "./errors"; @@ -131,22 +130,22 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { * is drained. The return value n is the number of bytes read. If the * buffer has no data to return, eof in the response will be true. */ - readSync(p: Uint8Array): ReadResult { + readSync(p: Uint8Array): number | EOF { if (this.empty()) { // Buffer is empty, reset to recover space. this.reset(); if (p.byteLength === 0) { // this edge case is tested in 'bufferReadEmptyAtEOF' test - return { nread: 0, eof: false }; + return 0; } - return { nread: 0, eof: true }; + return EOF; } const nread = copyBytes(p, this.buf.subarray(this.off)); this.off += nread; - return { nread, eof: false }; + return nread; } - async read(p: Uint8Array): Promise<ReadResult> { + async read(p: Uint8Array): Promise<number | EOF> { const rr = this.readSync(p); return Promise.resolve(rr); } @@ -226,12 +225,12 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { const i = this._grow(MIN_READ); this._reslice(i); const fub = new Uint8Array(this.buf.buffer, i); - const { nread, eof } = await r.read(fub); - this._reslice(i + nread); - n += nread; - if (eof) { + const nread = await r.read(fub); + if (nread === EOF) { return n; } + this._reslice(i + nread); + n += nread; } catch (e) { return n; } @@ -247,12 +246,12 @@ export class Buffer implements Reader, SyncReader, Writer, SyncWriter { const i = this._grow(MIN_READ); this._reslice(i); const fub = new Uint8Array(this.buf.buffer, i); - const { nread, eof } = r.readSync(fub); - this._reslice(i + nread); - n += nread; - if (eof) { + const nread = r.readSync(fub); + if (nread === EOF) { return n; } + this._reslice(i + nread); + n += nread; } catch (e) { return n; } diff --git a/js/buffer_test.ts b/js/buffer_test.ts index b4ed3a58a..3b2f5d312 100644 --- a/js/buffer_test.ts +++ b/js/buffer_test.ts @@ -60,10 +60,10 @@ async function empty(buf: Buffer, s: string, fub: Uint8Array): Promise<void> { check(buf, s); while (true) { const r = await buf.read(fub); - if (r.nread == 0) { + if (r === Deno.EOF) { break; } - s = s.slice(r.nread); + s = s.slice(r); check(buf, s); } check(buf, ""); @@ -126,8 +126,7 @@ test(async function bufferReadEmptyAtEOF(): Promise<void> { let buf = new Buffer(); const zeroLengthTmp = new Uint8Array(0); let result = await buf.read(zeroLengthTmp); - assertEquals(result.nread, 0); - assertEquals(result.eof, false); + assertEquals(result, 0); }); test(async function bufferLargeByteWrites(): Promise<void> { @@ -217,7 +216,8 @@ test(async function bufferTestGrow(): Promise<void> { for (let growLen of [0, 100, 1000, 10000, 100000]) { const buf = new Buffer(xBytes.buffer as ArrayBuffer); // If we read, this affects buf.off, which is good to test. - const { nread } = await buf.read(tmp); + const result = await buf.read(tmp); + const nread = result === Deno.EOF ? 0 : result; buf.grow(growLen); const yBytes = repeat("y", growLen); await buf.write(yBytes); diff --git a/js/deno.ts b/js/deno.ts index 0bc3c95c7..f20b6eff1 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -20,9 +20,9 @@ export { OpenMode } from "./files"; export { + EOF, copy, toAsyncIterator, - ReadResult, SeekMode, Reader, SyncReader, diff --git a/js/deps/https/deno.land/std b/js/deps/https/deno.land/std -Subproject d99c15448dc6615bea372cc64453de3428c6ba2 +Subproject 6663e698d08147ae0a736d1df52ffd857729d3d diff --git a/js/fetch.ts b/js/fetch.ts index 3659710c5..9853b2194 100644 --- a/js/fetch.ts +++ b/js/fetch.ts @@ -218,7 +218,7 @@ class Body implements domTypes.Body, domTypes.ReadableStream, io.ReadCloser { return decoder.decode(ab); } - read(p: Uint8Array): Promise<io.ReadResult> { + read(p: Uint8Array): Promise<number | io.EOF> { return read(this.rid, p); } diff --git a/js/files.ts b/js/files.ts index 1479e4146..eb899d738 100644 --- a/js/files.ts +++ b/js/files.ts @@ -1,10 +1,10 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. import { + EOF, Reader, Writer, Seeker, Closer, - ReadResult, SeekMode, SyncReader, SyncWriter, @@ -71,47 +71,50 @@ function reqRead( return [builder, msg.Any.Read, inner, p]; } -function resRead(baseRes: null | msg.Base): ReadResult { +function resRead(baseRes: null | msg.Base): number | EOF { assert(baseRes != null); assert(msg.Any.ReadRes === baseRes!.innerType()); const res = new msg.ReadRes(); assert(baseRes!.inner(res) != null); - return { nread: res.nread(), eof: res.eof() }; + if (res.eof()) { + return EOF; + } + return res.nread(); } /** Read synchronously from a file ID into an array buffer. * - * Return `ReadResult` for the operation. + * Return `number | EOF` for the operation. * * const file = Deno.openSync("/foo/bar.txt"); * const buf = new Uint8Array(100); - * const { nread, eof } = Deno.readSync(file.rid, buf); + * const nread = Deno.readSync(file.rid, buf); * const text = new TextDecoder().decode(buf); * */ -export function readSync(rid: number, p: Uint8Array): ReadResult { +export function readSync(rid: number, p: Uint8Array): number | EOF { return resRead(dispatch.sendSync(...reqRead(rid, p))); } /** Read from a file ID into an array buffer. * - * Resolves with the `ReadResult` for the operation. + * Resolves with the `number | EOF` for the operation. * * (async () => { * const file = await Deno.open("/foo/bar.txt"); * const buf = new Uint8Array(100); - * const { nread, eof } = await Deno.read(file.rid, buf); + * const nread = await Deno.read(file.rid, buf); * const text = new TextDecoder().decode(buf); * })(); */ -export async function read(rid: number, p: Uint8Array): Promise<ReadResult> { +export async function read(rid: number, p: Uint8Array): Promise<number | EOF> { const nread = await sendAsyncMinimal(OP_READ, rid, p); if (nread < 0) { throw new Error("read error"); } else if (nread == 0) { - return { nread, eof: true }; + return EOF; } else { - return { nread, eof: false }; + return nread; } } @@ -227,11 +230,11 @@ export class File return writeSync(this.rid, p); } - read(p: Uint8Array): Promise<ReadResult> { + read(p: Uint8Array): Promise<number | EOF> { return read(this.rid, p); } - readSync(p: Uint8Array): ReadResult { + readSync(p: Uint8Array): number | EOF { return readSync(this.rid, p); } diff --git a/js/files_test.ts b/js/files_test.ts index 350c1eb41..babec1fc2 100644 --- a/js/files_test.ts +++ b/js/files_test.ts @@ -39,15 +39,16 @@ test(async function readerToAsyncIterator(): Promise<void> { constructor(private readonly s: string) {} - async read(p: Uint8Array): Promise<Deno.ReadResult> { + async read(p: Uint8Array): Promise<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; - return { - nread: n, - eof: this.offset === this.buf.byteLength - }; + if (n === 0) { + return Deno.EOF; + } + + return n; } } @@ -228,7 +229,7 @@ testPerm( const buf = new Uint8Array(20); await file.seek(0, Deno.SeekMode.SEEK_START); const result = await file.read(buf); - assertEquals(result.nread, 13); + assertEquals(result, 13); file.close(); await Deno.remove(tempDir, { recursive: true }); @@ -3,11 +3,11 @@ // Documentation liberally lifted from them too. // Thank you! We love Go! -// The bytes read during an I/O call and a boolean indicating EOF. -export interface ReadResult { - nread: number; - eof: boolean; -} +// 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 = null; +export type EOF = null; // Seek whence values. // https://golang.org/pkg/io/#pkg-constants @@ -21,36 +21,27 @@ export enum SeekMode { // 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 any error encountered. + * 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 an error or end-of-file condition after - * successfully reading `n` > `0` bytes, it returns the number of bytes read. - * It may return the (non-nil) error from the same call or return the error - * (and `n` == `0`) from a subsequent call. An instance of this general case - * is that a `Reader` returning a non-zero number of bytes at the end of the - * input stream may return either `err` == `EOF` or `err` == `null`. The next - * `read()` should return `0`, `EOF`. + * When `read()` encounters end-of-file condition, it returns EOF symbol. * - * 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. + * When `read()` encounters an error, it rejects with an error. * - * Implementations of `read()` are discouraged from returning a zero byte - * count with a `null` error, except when `p.byteLength` == `0`. Callers - * should treat a return of `0` and `null` as indicating that nothing - * happened; in particular it does not indicate `EOF`. + * 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<ReadResult>; + read(p: Uint8Array): Promise<number | EOF>; } export interface SyncReader { - readSync(p: Uint8Array): ReadResult; + readSync(p: Uint8Array): number | EOF; } // Writer is the interface that wraps the basic write() method. @@ -128,10 +119,11 @@ export async function copy(dst: Writer, src: Reader): Promise<number> { let gotEOF = false; while (gotEOF === false) { const result = await src.read(b); - if (result.eof) { + if (result === EOF) { gotEOF = true; + } else { + n += await dst.write(b.subarray(0, result)); } - n += await dst.write(b.subarray(0, result.nread)); } return n; } @@ -146,7 +138,7 @@ 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` + // 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. // @@ -164,10 +156,13 @@ export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array> { } const result = await r.read(b); - sawEof = result.eof; + if (result === EOF) { + sawEof = true; + return { value: new Uint8Array(), done: true }; + } return { - value: b.subarray(0, result.nread), + value: b.subarray(0, result), done: false }; } @@ -1,5 +1,5 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { ReadResult, Reader, Writer, Closer } from "./io"; +import { EOF, Reader, Writer, Closer } from "./io"; import * as msg from "gen/cli/msg_generated"; import { assert, notImplemented } from "./util"; import * as dispatch from "./dispatch"; @@ -55,7 +55,7 @@ class ConnImpl implements Conn { return write(this.rid, p); } - read(p: Uint8Array): Promise<ReadResult> { + read(p: Uint8Array): Promise<number | EOF> { return read(this.rid, p); } diff --git a/js/net_test.ts b/js/net_test.ts index 9f7e621bc..10652136c 100644 --- a/js/net_test.ts +++ b/js/net_test.ts @@ -53,20 +53,16 @@ testPerm({ net: true }, async function netDialListen(): Promise<void> { const conn = await Deno.dial("tcp", "127.0.0.1:4500"); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); - assertEquals(3, readResult.nread); + assertEquals(3, readResult); assertEquals(1, buf[0]); assertEquals(2, buf[1]); assertEquals(3, buf[2]); assert(conn.rid > 0); - // TODO Currently ReadResult does not properly transmit EOF in the same call. - // it requires a second call to get the EOF. Either ReadResult to be an - // integer in which 0 signifies EOF or the handler should be modified so that - // EOF is properly transmitted. - assertEquals(false, readResult.eof); + assert(readResult !== Deno.EOF); const readResult2 = await conn.read(buf); - assertEquals(true, readResult2.eof); + assertEquals(Deno.EOF, readResult2); listener.close(); conn.close(); @@ -85,20 +81,16 @@ testPerm({ net: true }, async function netListenAsyncIterator(): Promise<void> { const conn = await Deno.dial("tcp", "127.0.0.1:4500"); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); - assertEquals(3, readResult.nread); + assertEquals(3, readResult); assertEquals(1, buf[0]); assertEquals(2, buf[1]); assertEquals(3, buf[2]); assert(conn.rid > 0); - // TODO Currently ReadResult does not properly transmit EOF in the same call. - // it requires a second call to get the EOF. Either ReadResult to be an - // integer in which 0 signifies EOF or the handler should be modified so that - // EOF is properly transmitted. - assertEquals(false, readResult.eof); + assert(readResult !== Deno.EOF); const readResult2 = await conn.read(buf); - assertEquals(true, readResult2.eof); + assertEquals(Deno.EOF, readResult2); listener.close(); conn.close(); @@ -116,7 +108,7 @@ testPerm({ net: true }, async function netCloseReadSuccess() { await conn.write(new Uint8Array([1, 2, 3])); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); - assertEquals(3, readResult.nread); + assertEquals(3, readResult); assertEquals(4, buf[0]); assertEquals(5, buf[1]); assertEquals(6, buf[2]); @@ -128,8 +120,7 @@ testPerm({ net: true }, async function netCloseReadSuccess() { closeReadDeferred.resolve(); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); - assertEquals(0, readResult.nread); // No error, read nothing - assertEquals(true, readResult.eof); // with immediate EOF + assertEquals(Deno.EOF, readResult); // with immediate EOF // Ensure closeRead does not impact write await conn.write(new Uint8Array([4, 5, 6])); await closeDeferred.promise; @@ -181,7 +172,7 @@ testPerm({ net: true }, async function netCloseWriteSuccess() { const buf = new Uint8Array(1024); // Check read not impacted const readResult = await conn.read(buf); - assertEquals(3, readResult.nread); + assertEquals(3, readResult); assertEquals(1, buf[0]); assertEquals(2, buf[1]); assertEquals(3, buf[2]); diff --git a/js/process_test.ts b/js/process_test.ts index 6e5fe7947..874f59a81 100644 --- a/js/process_test.ts +++ b/js/process_test.ts @@ -156,13 +156,14 @@ testPerm({ run: true }, async function runStdoutPiped(): Promise<void> { const data = new Uint8Array(10); let r = await p.stdout.read(data); - assertEquals(r.nread, 5); - assertEquals(r.eof, false); - const s = new TextDecoder().decode(data.subarray(0, r.nread)); + if (r === Deno.EOF) { + throw new Error("p.stdout.read(...) should not be EOF"); + } + assertEquals(r, 5); + const s = new TextDecoder().decode(data.subarray(0, r)); assertEquals(s, "hello"); r = await p.stdout.read(data); - assertEquals(r.nread, 0); - assertEquals(r.eof, true); + assertEquals(r, Deno.EOF); p.stdout.close(); const status = await p.status(); @@ -182,13 +183,14 @@ testPerm({ run: true }, async function runStderrPiped(): Promise<void> { const data = new Uint8Array(10); let r = await p.stderr.read(data); - assertEquals(r.nread, 5); - assertEquals(r.eof, false); - const s = new TextDecoder().decode(data.subarray(0, r.nread)); + if (r === Deno.EOF) { + throw new Error("p.stderr.read should not return EOF here"); + } + assertEquals(r, 5); + const s = new TextDecoder().decode(data.subarray(0, r)); assertEquals(s, "hello"); r = await p.stderr.read(data); - assertEquals(r.nread, 0); - assertEquals(r.eof, true); + assertEquals(r, Deno.EOF); p.stderr.close(); const status = await p.status(); @@ -306,8 +308,7 @@ testPerm({ run: true }, async function runClose(): Promise<void> { const data = new Uint8Array(10); let r = await p.stderr.read(data); - assertEquals(r.nread, 0); - assertEquals(r.eof, true); + assertEquals(r, Deno.EOF); }); test(function signalNumbers(): void { diff --git a/js/xeval.ts b/js/xeval.ts index f769a2ead..81e79f590 100644 --- a/js/xeval.ts +++ b/js/xeval.ts @@ -1,7 +1,7 @@ import { Buffer } from "./buffer"; import { stdin } from "./files"; import { TextEncoder, TextDecoder } from "./text_encoding"; -import { Reader } from "./io"; +import { Reader, EOF } from "./io"; export type XevalFunc = (v: string) => void; @@ -35,12 +35,13 @@ async function* chunks( // Record how far we have gone with delimiter matching. let nextMatchIndex = 0; while (true) { - const rr = await reader.read(inspectArr); - if (rr.nread < 0) { + let result = await reader.read(inspectArr); + let rr = result === EOF ? 0 : result; + if (rr < 0) { // Silently fail. break; } - const sliceRead = inspectArr.subarray(0, rr.nread); + const sliceRead = inspectArr.subarray(0, rr); // Remember how far we have scanned through inspectArr. let nextSliceStartIndex = 0; for (let i = 0; i < sliceRead.length; i++) { @@ -74,7 +75,7 @@ async function* chunks( } // Write all unprocessed chunk to buffer for future inspection. await writeAll(inputBuffer, sliceRead.subarray(nextSliceStartIndex)); - if (rr.eof) { + if (result === EOF) { // Flush the remainder unprocessed chunk. const lastChunk = inputBuffer.toString(); yield lastChunk; |