diff --git a/bufio.ts b/bufio.ts index a1f673653e..b412cbce83 100644 --- a/bufio.ts +++ b/bufio.ts @@ -162,6 +162,30 @@ export class BufReader implements Reader { return rr; } + /** reads exactly len(p) bytes into p. + * Ported from https://golang.org/pkg/io/#ReadFull + * It returns the number of bytes copied and an error if fewer bytes were read. + * The error is EOF only if no bytes were read. + * If an EOF happens after reading some but not all the bytes, + * readFull returns ErrUnexpectedEOF. ("EOF" for current impl) + * On return, n == len(p) if and only if err == nil. + * If r returns an error having read at least len(buf) bytes, + * the error is dropped. + */ + async readFull(p: Uint8Array): Promise<[number, BufState]> { + let rr = await this.read(p); + let nread = rr.nread; + if (rr.eof) { + return [nread, nread < p.length ? "EOF" : null]; + } + while (!rr.eof && nread < p.length) { + rr = await this.read(p.subarray(nread)); + nread += rr.nread; + } + return [nread, nread < p.length ? "EOF" : null]; + } + + /** Returns the next byte [0, 255] or -1 if EOF. */ async readByte(): Promise { while (this.r === this.w) { diff --git a/bufio_test.ts b/bufio_test.ts index 839e613882..19954bdf6e 100644 --- a/bufio_test.ts +++ b/bufio_test.ts @@ -321,3 +321,25 @@ test(async function bufioWriter() { } } }); + +test(async function bufReaderReadFull() { + const enc = new TextEncoder(); + const dec = new TextDecoder(); + const text = "Hello World"; + const data = new Buffer(enc.encode(text)); + const bufr = new BufReader(data, 3); + { + const buf = new Uint8Array(6); + const [nread, err] = await bufr.readFull(buf); + assertEqual(nread, 6); + assert(!err); + assertEqual(dec.decode(buf), "Hello "); + } + { + const buf = new Uint8Array(6); + const [nread, err] = await bufr.readFull(buf); + assertEqual(nread, 5); + assertEqual(err, "EOF"); + assertEqual(dec.decode(buf.subarray(0, 5)), "World"); + } +}); diff --git a/test.ts b/test.ts index c298b7aab1..7c395663e8 100644 --- a/test.ts +++ b/test.ts @@ -10,7 +10,7 @@ const fileServer = run({ args: ["deno", "--allow-net", "file_server.ts", "."] }); // I am also too lazy to do this properly LOL -runTests(new Promise(res => setTimeout(res, 1000))); +runTests(new Promise(res => setTimeout(res, 5000))); (async () => { await completePromise; fileServer.close();