diff --git a/bufio.ts b/bufio.ts index dccd3afc0d..2ad9bdd09b 100644 --- a/bufio.ts +++ b/bufio.ts @@ -3,7 +3,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -import { Reader, ReadResult } from "deno"; +import { Reader, ReadResult, Writer } from "deno"; import { assert, charCode, copyBytes } from "./util.ts"; const DEFAULT_BUF_SIZE = 4096; @@ -32,7 +32,7 @@ export class BufReader implements Reader { } /** Returns the size of the underlying buffer in bytes. */ - get byteLength(): number { + size(): number { return this.buf.byteLength; } @@ -332,4 +332,104 @@ export class BufReader implements Reader { * the underlying deno.Writer. */ export class BufWriter implements Writer { + buf: Uint8Array; + n: number = 0; + err: null | Error = null; + + constructor(private wr: Writer, size = DEFAULT_BUF_SIZE) { + if (size <= 0) { + size = DEFAULT_BUF_SIZE; + } + this.buf = new Uint8Array(size); + } + + /** Size returns the size of the underlying buffer in bytes. */ + size(): number { + return this.buf.byteLength; + } + + /** Discards any unflushed buffered data, clears any error, and + * resets b to write its output to w. + */ + reset(w: Writer): void { + this.err = null; + this.n = 0; + this.wr = w; + } + + /** Flush writes any buffered data to the underlying io.Writer. */ + async flush(): Promise { + if (this.err != null) { + throw this.err; + } + if (this.n == 0) { + return; + } + + let n: number; + let err: Error = null; + try { + n = await this.wr.write(this.buf.subarray(0, this.n)); + } catch (e) { + err = e; + } + + if (n < this.n && err == null) { + err = new Error("ShortWrite"); + } + + if (err != null) { + if (n > 0 && n < this.n) { + this.buf.copyWithin(0, n, this.n); + } + this.n -= n; + this.err = err; + return; + } + this.n = 0; + } + + /** Returns how many bytes are unused in the buffer. */ + available(): number { + return this.buf.byteLength - this.n; + } + + /** buffered returns the number of bytes that have been written into the + * current buffer. + */ + buffered(): number { + return this.n; + } + + /** Writes the contents of p into the buffer. + * Returns the number of bytes written. + */ + async write(p: Uint8Array): Promise { + let nn = 0; + let n: number; + while (p.byteLength > this.available() && !this.err) { + if (this.buffered() == 0) { + // Large write, empty buffer. + // Write directly from p to avoid copy. + try { + n = await this.wr.write(p); + } catch (e) { + this.err = e; + } + } else { + n = copyBytes(this.buf, p, this.n); + this.n += n; + this.flush(); + } + nn += n; + p = p.subarray(n); + } + if (this.err) { + throw this.err; + } + n = copyBytes(this.buf, p, this.n); + this.n += n; + nn += n; + return nn; + } } diff --git a/bufio_test.ts b/bufio_test.ts index 9c89f02168..f3430a755b 100644 --- a/bufio_test.ts +++ b/bufio_test.ts @@ -9,7 +9,7 @@ import { assert, assertEqual } from "https://deno.land/x/testing/testing.ts"; -import { BufReader, BufState } from "./bufio.ts"; +import { BufReader, BufState, BufWriter } from "./bufio.ts"; import { Buffer, stringsReader } from "./buffer.ts"; import * as iotest from "./iotest.ts"; import { charCode, copyBytes } from "./util.ts"; @@ -289,3 +289,36 @@ test(async function bufioPeek() { } */ }); + +test(async function bufioWriter() { + const data = new Uint8Array(8192); + + for (let i = 0; i < data.byteLength; i++) { + data[i] = charCode(" ") + i % (charCode("~") - charCode(" ")); + } + + const w = new Buffer(); + for (let nwrite of bufsizes) { + for (let bs of bufsizes) { + // Write nwrite bytes using buffer size bs. + // Check that the right amount makes it out + // and that the data is correct. + + w.reset(); + const buf = new BufWriter(w, bs); + + const context = `nwrite=${nwrite} bufsize=${bs}`; + const n = await buf.write(data.subarray(0, nwrite)); + assertEqual(n, nwrite, context); + + await buf.flush(); + + const written = w.bytes(); + assertEqual(written.byteLength, nwrite); + + for (let l = 0; l < written.byteLength; l++) { + assertEqual(written[l], data[l]); + } + } + } +}); diff --git a/http.ts b/http.ts index c33bc97a2d..0266501ae3 100644 --- a/http.ts +++ b/http.ts @@ -55,4 +55,3 @@ async function readRequest(b: BufReader): Promise { return req; } -