diff --git a/Makefile b/Makefile index 4b84880939..ca2135445f 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,6 @@ test: deno test.ts fmt: - prettier *.ts --write + prettier *.md *.ts --write .PHONY: test fmt diff --git a/README.md b/README.md index f27d51a8bf..614e530875 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,12 @@ [![Build Status](https://travis-ci.com/denoland/net.svg?branch=master)](https://travis-ci.com/denoland/net) - Usage: + ```typescript -import { Reader } from "https://deno.land/x/net/bufio.ts"; -// TODO Example. +import { serve } from "https://deno.land/x/net/http.ts"; +const s = serve("0.0.0.0:8000"); +for await (const req of s) { + req.respond({ body: "Hello World\n" }); +} ``` diff --git a/bufio.ts b/bufio.ts index 3480047e93..d736e1fc4d 100644 --- a/bufio.ts +++ b/bufio.ts @@ -47,7 +47,6 @@ export class BufReader implements Reader { } // Reads a new chunk into the buffer. - // Returns true if EOF, false on successful read. private async _fill(): Promise { // Slide existing data to beginning. if (this.r > 0) { @@ -287,4 +286,40 @@ export class BufReader implements Reader { return [line, err]; } + + /** Peek returns the next n bytes without advancing the reader. The bytes stop + * being valid at the next read call. If Peek returns fewer than n bytes, it + * also returns an error explaining why the read is short. The error is + * ErrBufferFull if n is larger than b's buffer size. + */ + async peek(n: number): Promise<[Uint8Array, BufState]> { + if (n < 0) { + throw Error("negative count"); + } + + while ( + this.w - this.r < n && + this.w - this.r < this.buf.byteLength && + this.err == null + ) { + await this._fill(); // this.w - this.r < len(this.buf) => buffer is not full + } + + if (n > this.buf.byteLength) { + return [this.buf.subarray(this.r, this.w), "BufferFull"]; + } + + // 0 <= n <= len(this.buf) + let err: BufState; + let avail = this.w - this.r; + if (avail < n) { + // not enough data in buffer + n = avail; + err = this._readErr(); + if (!err) { + err = "BufferFull"; + } + } + return [this.buf.subarray(this.r, this.r + n), err]; + } } diff --git a/bufio_test.ts b/bufio_test.ts index 4319a337d6..80068f2d39 100644 --- a/bufio_test.ts +++ b/bufio_test.ts @@ -217,3 +217,80 @@ test(async function bufioReadLine() { await testReadLine(testInput); await testReadLine(testInputrn); }); + +test(async function bufioPeek() { + const decoder = new TextDecoder(); + let p = new Uint8Array(10); + // string is 16 (minReadBufferSize) long. + let buf = new BufReader( + stringsReader("abcdefghijklmnop"), + MIN_READ_BUFFER_SIZE + ); + + let [actual, err] = await buf.peek(1); + assertEqual(decoder.decode(actual), "a"); + assert(err == null); + + [actual, err] = await buf.peek(4); + assertEqual(decoder.decode(actual), "abcd"); + assert(err == null); + + [actual, err] = await buf.peek(32); + assertEqual(decoder.decode(actual), "abcdefghijklmnop"); + assertEqual(err, "BufferFull"); + + await buf.read(p.subarray(0, 3)); + assertEqual(decoder.decode(p.subarray(0, 3)), "abc"); + + [actual, err] = await buf.peek(1); + assertEqual(decoder.decode(actual), "d"); + assert(err == null); + + [actual, err] = await buf.peek(1); + assertEqual(decoder.decode(actual), "d"); + assert(err == null); + + [actual, err] = await buf.peek(1); + assertEqual(decoder.decode(actual), "d"); + assert(err == null); + + [actual, err] = await buf.peek(2); + assertEqual(decoder.decode(actual), "de"); + assert(err == null); + + let { eof } = await buf.read(p.subarray(0, 3)); + assertEqual(decoder.decode(p.subarray(0, 3)), "def"); + assert(!eof); + assert(err == null); + + [actual, err] = await buf.peek(4); + assertEqual(decoder.decode(actual), "ghij"); + assert(err == null); + + await buf.read(p); + assertEqual(decoder.decode(p), "ghijklmnop"); + + [actual, err] = await buf.peek(0); + assertEqual(decoder.decode(actual), ""); + assert(err == null); + + [actual, err] = await buf.peek(1); + assertEqual(decoder.decode(actual), ""); + assert(err == "EOF"); + /* TODO + // Test for issue 3022, not exposing a reader's error on a successful Peek. + buf = NewReaderSize(dataAndEOFReader("abcd"), 32) + if s, err := buf.Peek(2); string(s) != "ab" || err != nil { + t.Errorf(`Peek(2) on "abcd", EOF = %q, %v; want "ab", nil`, string(s), err) + } + if s, err := buf.Peek(4); string(s) != "abcd" || err != nil { + t.Errorf(`Peek(4) on "abcd", EOF = %q, %v; want "abcd", nil`, string(s), err) + } + if n, err := buf.Read(p[0:5]); string(p[0:n]) != "abcd" || err != nil { + t.Fatalf("Read after peek = %q, %v; want abcd, EOF", p[0:n], err) + } + if n, err := buf.Read(p[0:1]); string(p[0:n]) != "" || err != io.EOF { + t.Fatalf(`second Read after peek = %q, %v; want "", EOF`, p[0:n], err) + } + */ +});