mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
153 lines
4.0 KiB
TypeScript
153 lines
4.0 KiB
TypeScript
// Ported to Deno from:
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
import * as deno from "deno";
|
|
import { assert, copyBytes } from "./util.ts";
|
|
|
|
const DEFAULT_BUF_SIZE = 4096;
|
|
const MIN_BUF_SIZE = 16;
|
|
const MAX_CONSECUTIVE_EMPTY_READS = 100;
|
|
|
|
export class ErrNegativeRead extends Error {
|
|
constructor() {
|
|
super("bufio: reader returned negative count from Read");
|
|
this.name = "ErrNegativeRead";
|
|
}
|
|
}
|
|
|
|
export class Reader implements deno.Reader {
|
|
private buf: Uint8Array;
|
|
private rd: deno.Reader; // Reader provided by caller.
|
|
private r = 0; // buf read position.
|
|
private w = 0; // buf write position.
|
|
private lastByte: number;
|
|
private lastCharSize: number;
|
|
|
|
constructor(rd: deno.Reader, size = DEFAULT_BUF_SIZE) {
|
|
if (size < MIN_BUF_SIZE) {
|
|
size = MIN_BUF_SIZE;
|
|
}
|
|
this._reset(new Uint8Array(size), rd);
|
|
}
|
|
|
|
/** Returns the size of the underlying buffer in bytes. */
|
|
get byteLength(): number {
|
|
return this.buf.byteLength;
|
|
}
|
|
|
|
// Reads a new chunk into the buffer.
|
|
// Returns true if EOF, false on successful read.
|
|
async _fill(): Promise<boolean> {
|
|
// Slide existing data to beginning.
|
|
if (this.r > 0) {
|
|
this.buf.copyWithin(0, this.r, this.w);
|
|
this.w -= this.r;
|
|
this.r = 0;
|
|
}
|
|
|
|
if (this.w >= this.buf.byteLength) {
|
|
throw Error("bufio: tried to fill full buffer");
|
|
}
|
|
|
|
// Read new data: try a limited number of times.
|
|
for (let i = MAX_CONSECUTIVE_EMPTY_READS; i > 0; i--) {
|
|
const { nread, eof } = await this.rd.read(this.buf.subarray(this.w));
|
|
if (nread < 0) {
|
|
throw new ErrNegativeRead();
|
|
}
|
|
this.w += nread;
|
|
if (eof) {
|
|
return true;
|
|
}
|
|
if (nread > 0) {
|
|
return false;
|
|
}
|
|
}
|
|
throw Error("No Progress");
|
|
}
|
|
|
|
/** Discards any buffered data, resets all state, and switches
|
|
* the buffered reader to read from r.
|
|
*/
|
|
reset(r: deno.Reader): void {
|
|
this._reset(this.buf, r);
|
|
}
|
|
|
|
private _reset(buf: Uint8Array, rd: deno.Reader): void {
|
|
this.buf = buf;
|
|
this.rd = rd;
|
|
this.lastByte = -1;
|
|
this.lastCharSize = -1;
|
|
}
|
|
|
|
/** reads data into p.
|
|
* It returns the number of bytes read into p.
|
|
* The bytes are taken from at most one Read on the underlying Reader,
|
|
* hence n may be less than len(p).
|
|
* At EOF, the count will be zero and err will be io.EOF.
|
|
* To read exactly len(p) bytes, use io.ReadFull(b, p).
|
|
*/
|
|
async read(p: ArrayBufferView): Promise<deno.ReadResult> {
|
|
let rr: deno.ReadResult = { nread: p.byteLength, eof: false };
|
|
if (rr.nread === 0) {
|
|
return rr;
|
|
}
|
|
|
|
if (this.r === this.w) {
|
|
/*
|
|
if (this.err != null) {
|
|
throw this.readErr();
|
|
}
|
|
*/
|
|
if (p.byteLength >= this.buf.byteLength) {
|
|
// Large read, empty buffer.
|
|
// Read directly into p to avoid copy.
|
|
rr = await this.rd.read(p);
|
|
if (rr.nread < 0) {
|
|
throw new ErrNegativeRead();
|
|
}
|
|
if (rr.nread > 0) {
|
|
this.lastByte = p[rr.nread - 1];
|
|
// this.lastRuneSize = -1;
|
|
}
|
|
return rr;
|
|
}
|
|
// One read.
|
|
// Do not use this.fill, which will loop.
|
|
this.r = 0;
|
|
this.w = 0;
|
|
rr = await this.rd.read(this.buf);
|
|
if (rr.nread < 0) {
|
|
throw new ErrNegativeRead();
|
|
}
|
|
if (rr.nread === 0) {
|
|
return rr;
|
|
}
|
|
this.w += rr.nread;
|
|
}
|
|
|
|
// copy as much as we can
|
|
rr.nread = copyBytes(p as Uint8Array, this.buf.subarray(this.r, this.w), 0);
|
|
this.r += rr.nread;
|
|
this.lastByte = this.buf[this.r - 1];
|
|
// this.lastRuneSize = -1;
|
|
return rr;
|
|
}
|
|
|
|
/** Returns the next byte [0, 255] or -1 if EOF. */
|
|
async readByte(): Promise<number> {
|
|
while (this.r === this.w) {
|
|
const eof = await this._fill(); // buffer is empty.
|
|
if (eof) {
|
|
return -1;
|
|
}
|
|
}
|
|
const c = this.buf[this.r];
|
|
this.r++;
|
|
this.lastByte = c;
|
|
return c;
|
|
}
|
|
}
|