docs(io): document std/io (#5656)

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
This commit is contained in:
Yoshiya Hinosawa 2024-08-08 16:20:43 +02:00 committed by GitHub
parent 8e32dac73f
commit d93b33aff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 1344 additions and 162 deletions

View File

@ -50,6 +50,7 @@ const ENTRY_POINTS = [
"../http/mod.ts",
"../ini/mod.ts",
"../internal/mod.ts",
"../io/mod.ts",
"../json/mod.ts",
"../jsonc/mod.ts",
"../media_types/mod.ts",

View File

@ -11,10 +11,49 @@ const CR = "\r".charCodeAt(0);
const LF = "\n".charCodeAt(0);
/**
* Thrown when a write operation is attempted on a full buffer.
*
* @example Usage
* ```ts
* import { BufWriter, BufferFullError, Writer } from "@std/io";
* import { assert, assertEquals } from "@std/assert";
*
* const writer: Writer = {
* write(p: Uint8Array): Promise<number> {
* throw new BufferFullError(p);
* }
* };
* const bufWriter = new BufWriter(writer);
* try {
* await bufWriter.write(new Uint8Array([1, 2, 3]));
* } catch (err) {
* assert(err instanceof BufferFullError);
* assertEquals(err.partial, new Uint8Array([3]));
* }
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class BufferFullError extends Error {
/**
* The partially read bytes
*
* @example Usage
* ```ts
* import { BufferFullError } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const err = new BufferFullError(new Uint8Array(2));
* assertEquals(err.partial, new Uint8Array(2));
* ```
*/
partial: Uint8Array;
/**
* Construct a new instance.
*
* @param partial The bytes partially read
*/
constructor(partial: Uint8Array) {
super("Buffer full");
this.name = this.constructor.name;
@ -23,11 +62,41 @@ export class BufferFullError extends Error {
}
/**
* Thrown when a read from a stream fails to read the
* requested number of bytes.
*
* @example Usage
* ```ts
* import { PartialReadError } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const err = new PartialReadError(new Uint8Array(2));
* assertEquals(err.name, "PartialReadError");
*
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class PartialReadError extends Error {
/**
* The partially read bytes
*
* @example Usage
* ```ts
* import { PartialReadError } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const err = new PartialReadError(new Uint8Array(2));
* assertEquals(err.partial, new Uint8Array(2));
* ```
*/
partial: Uint8Array;
/**
* Construct a {@linkcode PartialReadError}.
*
* @param partial The bytes partially read
*/
constructor(partial: Uint8Array) {
super("Encountered UnexpectedEof, data only partially read");
this.name = this.constructor.name;
@ -36,16 +105,34 @@ export class PartialReadError extends Error {
}
/**
* Result type returned by of BufReader.readLine().
* Result type returned by of {@linkcode BufReader.readLine}.
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export interface ReadLineResult {
/** The line read */
line: Uint8Array;
/** `true if the end of the line has not been reached, `false` otherwise. */
more: boolean;
}
/**
* Implements buffering for a {@linkcode Reader} object.
*
* @example Usage
* ```ts
* import { BufReader } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const encoder = new TextEncoder();
* const decoder = new TextDecoder();
*
* const reader = new BufReader(new Deno.Buffer(encoder.encode("hello world")));
* const buf = new Uint8Array(11);
* await reader.read(buf);
* assertEquals(decoder.decode(buf), "hello world");
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class BufReader implements Reader {
@ -55,11 +142,33 @@ export class BufReader implements Reader {
#w = 0; // buf write position.
#eof = false;
/** return new BufReader unless r is BufReader */
/**
* Returns a new {@linkcode BufReader} if `r` is not already one.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assert } from "@std/assert/assert";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = BufReader.create(reader);
* assert(bufReader instanceof BufReader);
* ```
*
* @param r The reader to read from.
* @param size The size of the buffer.
* @returns A new {@linkcode BufReader} if `r` is not already one.
*/
static create(r: Reader, size: number = DEFAULT_BUF_SIZE): BufReader {
return r instanceof BufReader ? r : new BufReader(r, size);
}
/**
* Constructs a new {@linkcode BufReader} for the given reader and buffer size.
*
* @param rd The reader to read from.
* @param size The size of the buffer.
*/
constructor(rd: Reader, size: number = DEFAULT_BUF_SIZE) {
if (size < MIN_BUF_SIZE) {
size = MIN_BUF_SIZE;
@ -67,11 +176,42 @@ export class BufReader implements Reader {
this.#reset(new Uint8Array(size), rd);
}
/** Returns the size of the underlying buffer in bytes. */
/**
* Returns the size of the underlying buffer in bytes.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
*
* assertEquals(bufReader.size(), 4096);
* ```
*
* @returns The size of the underlying buffer in bytes.
*/
size(): number {
return this.#buf.byteLength;
}
/**
* Returns the number of bytes that can be read from the current buffer.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* await bufReader.read(new Uint8Array(5));
* assertEquals(bufReader.buffered(), 6);
* ```
*
* @returns Number of bytes that can be read from the buffer
*/
buffered(): number {
return this.#w - this.#r;
}
@ -107,8 +247,23 @@ export class BufReader implements Reader {
);
};
/** Discards any buffered data, resets all state, and switches
* the buffered reader to read from r.
/**
* Discards any buffered data, resets all state, and switches
* the buffered reader to read from `r`.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* await bufReader.read(new Uint8Array(5));
* bufReader.reset(reader);
* assertEquals(bufReader.buffered(), 6);
* ```
*
* @param r The reader to read from.
*/
reset(r: Reader) {
this.#reset(this.#buf, r);
@ -122,11 +277,27 @@ export class BufReader implements Reader {
// 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).
* To read exactly len(p) bytes, use io.ReadFull(b, p).
/**
* Reads data into `p`.
*
* The bytes are taken from at most one `read()` on the underlying `Reader`,
* hence n may be less than `len(p)`.
* To read exactly `len(p)` bytes, use `io.ReadFull(b, p)`.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* const buf = new Uint8Array(5);
* await bufReader.read(buf);
* assertEquals(new TextDecoder().decode(buf), "hello");
* ```
*
* @param p The buffer to read data into.
* @returns The number of bytes read into `p`.
*/
async read(p: Uint8Array): Promise<number | null> {
let rr: number | null = p.byteLength;
@ -161,7 +332,8 @@ export class BufReader implements Reader {
return copied;
}
/** reads exactly `p.length` bytes into `p`.
/**
* Reads exactly `p.length` bytes into `p`.
*
* If successful, `p` is returned.
*
@ -174,6 +346,22 @@ export class BufReader implements Reader {
* buffer that has been successfully filled with data.
*
* Ported from https://golang.org/pkg/io/#ReadFull
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* const buf = new Uint8Array(5);
* await bufReader.readFull(buf);
* assertEquals(new TextDecoder().decode(buf), "hello");
* ```
*
* @param p The buffer to read data into.
* @returns The buffer `p` if the read is successful, `null` if the end of the
* underlying stream has been reached, and there are no more bytes available in the buffer.
*/
async readFull(p: Uint8Array): Promise<Uint8Array | null> {
let bytesRead = 0;
@ -191,7 +379,22 @@ export class BufReader implements Reader {
return p;
}
/** Returns the next byte [0, 255] or `null`. */
/**
* Returns the next byte ([0, 255]) or `null`.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* const byte = await bufReader.readByte();
* assertEquals(byte, 104);
* ```
*
* @returns The next byte ([0, 255]) or `null`.
*/
async readByte(): Promise<number | null> {
while (this.#r === this.#w) {
if (this.#eof) return null;
@ -203,14 +406,31 @@ export class BufReader implements Reader {
return c;
}
/** readString() reads until the first occurrence of delim in the input,
/**
* Reads until the first occurrence of delim in the input,
* returning a string containing the data up to and including the delimiter.
* If ReadString encounters an error before finding a delimiter,
* it returns the data read before the error and the error itself
* (often `null`).
* ReadString returns err !== null if and only if the returned data does not end
* in delim.
* For simple uses, a Scanner may be more convenient.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* const str = await bufReader.readString(" ");
* assertEquals(str, "hello ");
*
* const str2 = await bufReader.readString(" ");
* assertEquals(str2, "world");
* ```
*
* @param delim The delimiter to read until.
* @returns The string containing the data up to and including the delimiter.
*/
async readString(delim: string): Promise<string | null> {
if (delim.length !== 1) {
@ -221,8 +441,9 @@ export class BufReader implements Reader {
return new TextDecoder().decode(buffer);
}
/** `readLine()` is a low-level line-reading primitive. Most callers should
* use `readString('\n')` instead or use a Scanner.
/**
* A low-level line-reading primitive. Most callers should use
* `readString('\n')` instead.
*
* `readLine()` tries to return a single line, not including the end-of-line
* bytes. If the line was too long for the buffer then `more` is set and the
@ -231,7 +452,7 @@ export class BufReader implements Reader {
* of the line. The returned buffer is only valid until the next call to
* `readLine()`.
*
* The text returned from ReadLine does not include the line end ("\r\n" or
* The text returned from this method does not include the line end ("\r\n" or
* "\n").
*
* When the end of the underlying stream is reached, the final bytes in the
@ -239,9 +460,20 @@ export class BufReader implements Reader {
* without a final line end. When there are no more trailing bytes to read,
* `readLine()` returns `null`.
*
* Calling `unreadByte()` after `readLine()` will always unread the last byte
* read (possibly a character belonging to the line end) even if that byte is
* not part of the line returned by `readLine()`.
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello\nworld"));
* const bufReader = new BufReader(reader);
* const line1 = await bufReader.readLine();
* assertEquals(new TextDecoder().decode(line1!.line), "hello");
* const line2 = await bufReader.readLine();
* assertEquals(new TextDecoder().decode(line2!.line), "world");
* ```
*
* @returns The line read.
*/
async readLine(): Promise<ReadLineResult | null> {
let line: Uint8Array | null = null;
@ -295,7 +527,8 @@ export class BufReader implements Reader {
return { line, more: false };
}
/** `readSlice()` reads until the first occurrence of `delim` in the input,
/**
* Reads until the first occurrence of `delim` in the input,
* returning a slice pointing at the bytes in the buffer. The bytes stop
* being valid at the next read.
*
@ -310,6 +543,20 @@ export class BufReader implements Reader {
*
* Because the data returned from `readSlice()` will be overwritten by the
* next I/O operation, most clients should use `readString()` instead.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* const slice = await bufReader.readSlice(0x20);
* assertEquals(new TextDecoder().decode(slice!), "hello ");
* ```
*
* @param delim The delimiter to read until.
* @returns A slice pointing at the bytes in the buffer.
*/
async readSlice(delim: number): Promise<Uint8Array | null> {
let s = 0; // search start index
@ -361,7 +608,8 @@ export class BufReader implements Reader {
return slice;
}
/** `peek()` returns the next `n` bytes without advancing the reader. The
/**
* Returns the next `n` bytes without advancing the reader. The
* bytes stop being valid at the next read call.
*
* When the end of the underlying stream is reached, but there are unread
@ -371,6 +619,20 @@ export class BufReader implements Reader {
* If an error is encountered before `n` bytes are available, `peek()` throws
* an error with the `partial` property set to a slice of the buffer that
* contains the bytes that were available before the error occurred.
*
* @example Usage
* ```ts
* import { BufReader, Buffer } from "@std/io";
* import { assertEquals } from "@std/assert/equals";
*
* const reader = new Buffer(new TextEncoder().encode("hello world"));
* const bufReader = new BufReader(reader);
* const peeked = await bufReader.peek(5);
* assertEquals(new TextDecoder().decode(peeked!), "hello");
* ```
*
* @param n The number of bytes to peek.
* @returns The next `n` bytes without advancing the reader.
*/
async peek(n: number): Promise<Uint8Array | null> {
if (n < 0) {

View File

@ -6,57 +6,261 @@ import type { Writer, WriterSync } from "./types.ts";
const DEFAULT_BUF_SIZE = 4096;
abstract class AbstractBufBase {
/**
* AbstractBufBase is a base class which other classes can embed to
* implement the {@inkcode Reader} and {@linkcode Writer} interfaces.
* It provides basic implementations of those interfaces based on a buffer
* array.
*
* @example Usage
* ```ts no-assert
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { Reader } from "@std/io/types";
*
* class MyBufReader extends AbstractBufBase {
* constructor(buf: Uint8Array) {
* super(buf);
* }
* }
* ```
*
* @internal
*/
export abstract class AbstractBufBase {
/**
* The buffer
*
* @example Usage
* ```ts
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* class MyBuffer extends AbstractBufBase {}
*
* const buf = new Uint8Array(1024);
* const mb = new MyBuffer(buf);
*
* assertEquals(mb.buf, buf);
* ```
*/
buf: Uint8Array;
/**
* The used buffer bytes
*
* @example Usage
* ```ts
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* class MyBuffer extends AbstractBufBase {}
*
* const buf = new Uint8Array(1024);
* const mb = new MyBuffer(buf);
*
* assertEquals(mb.usedBufferBytes, 0);
* ```
*/
usedBufferBytes = 0;
/**
* The error
*
* @example Usage
* ```ts
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* class MyBuffer extends AbstractBufBase {}
*
* const buf = new Uint8Array(1024);
* const mb = new MyBuffer(buf);
*
* assertEquals(mb.err, null);
* ```
*/
err: Error | null = null;
/**
* Construct a {@linkcode AbstractBufBase} instance
*
* @param buf The buffer to use.
*/
constructor(buf: Uint8Array) {
this.buf = buf;
}
/** Size returns the size of the underlying buffer in bytes. */
/**
* Size returns the size of the underlying buffer in bytes.
*
* @example Usage
* ```ts
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* class MyBuffer extends AbstractBufBase {}
*
* const buf = new Uint8Array(1024);
* const mb = new MyBuffer(buf);
*
* assertEquals(mb.size(), 1024);
* ```
*
* @return the size of the buffer in bytes.
*/
size(): number {
return this.buf.byteLength;
}
/** Returns how many bytes are unused in the buffer. */
/**
* Returns how many bytes are unused in the buffer.
*
* @example Usage
* ```ts
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* class MyBuffer extends AbstractBufBase {}
*
* const buf = new Uint8Array(1024);
* const mb = new MyBuffer(buf);
*
* assertEquals(mb.available(), 1024);
* ```
*
* @return the number of bytes that are unused in the buffer.
*/
available(): number {
return this.buf.byteLength - this.usedBufferBytes;
}
/** buffered returns the number of bytes that have been written into the
/**
* buffered returns the number of bytes that have been written into the
* current buffer.
*
* @example Usage
* ```ts
* import { AbstractBufBase } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* class MyBuffer extends AbstractBufBase {}
*
* const buf = new Uint8Array(1024);
* const mb = new MyBuffer(buf);
*
* assertEquals(mb.buffered(), 0);
* ```
*
* @return the number of bytes that have been written into the current buffer.
*/
buffered(): number {
return this.usedBufferBytes;
}
}
/** BufWriter implements buffering for an deno.Writer object.
/**
* `BufWriter` implements buffering for an {@linkcode Writer} object.
* If an error occurs writing to a Writer, no more data will be
* accepted and all subsequent writes, and flush(), will return the error.
* After all data has been written, the client should call the
* flush() method to guarantee all data has been forwarded to
* the underlying deno.Writer.
*
* @example Usage
* ```ts
* import { BufWriter } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* const writer = {
* write(p: Uint8Array): Promise<number> {
* return Promise.resolve(p.length);
* }
* };
*
* const bufWriter = new BufWriter(writer);
* const data = new Uint8Array(1024);
*
* await bufWriter.write(data);
* await bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class BufWriter extends AbstractBufBase implements Writer {
#writer: Writer;
/** return new BufWriter unless writer is BufWriter */
/**
* return new BufWriter unless writer is BufWriter
*
* @example Usage
* ```ts
* import { BufWriter } from "@std/io/buf-writer";
* import { Writer } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: Writer = {
* write(p: Uint8Array): Promise<number> {
* return Promise.resolve(p.length);
* }
* };
*
* const bufWriter = BufWriter.create(writer);
* const data = new Uint8Array(1024);
*
* await bufWriter.write(data);
*
* assertEquals(bufWriter.buffered(), 1024);
* ```
*
* @param writer The writer to wrap.
* @param size The size of the buffer.
*
* @return a new {@linkcode BufWriter} instance.
*/
static create(writer: Writer, size: number = DEFAULT_BUF_SIZE): BufWriter {
return writer instanceof BufWriter ? writer : new BufWriter(writer, size);
}
/**
* Construct a new {@linkcode BufWriter}
*
* @param writer The writer to wrap.
* @param size The size of the buffer.
*/
constructor(writer: Writer, size: number = DEFAULT_BUF_SIZE) {
super(new Uint8Array(size <= 0 ? DEFAULT_BUF_SIZE : size));
this.#writer = writer;
}
/** Discards any unflushed buffered data, clears any error, and
/**
* Discards any unflushed buffered data, clears any error, and
* resets buffer to write its output to w.
*
* @example Usage
* ```ts
* import { BufWriter } from "@std/io/buf-writer";
* import { Writer } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: Writer = {
* write(p: Uint8Array): Promise<number> {
* return Promise.resolve(p.length);
* }
* };
*
* const bufWriter = new BufWriter(writer);
* const data = new Uint8Array(1024);
*
* await bufWriter.write(data);
*
* assertEquals(bufWriter.buffered(), 1024);
*
* bufWriter.reset(writer);
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*
* @param w The writer to write to.
*/
reset(w: Writer) {
this.err = null;
@ -64,7 +268,30 @@ export class BufWriter extends AbstractBufBase implements Writer {
this.#writer = w;
}
/** Flush writes any buffered data to the underlying io.Writer. */
/**
* Flush writes any buffered data to the underlying io.Writer.
*
* @example Usage
* ```ts
* import { BufWriter } from "@std/io/buf-writer";
* import { Writer } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: Writer = {
* write(p: Uint8Array): Promise<number> {
* return Promise.resolve(p.length);
* }
* };
*
* const bufWriter = new BufWriter(writer);
* const data = new Uint8Array(1024);
*
* await bufWriter.write(data);
* await bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*/
async flush() {
if (this.err !== null) throw this.err;
if (this.usedBufferBytes === 0) return;
@ -86,10 +313,32 @@ export class BufWriter extends AbstractBufBase implements Writer {
this.usedBufferBytes = 0;
}
/** Writes the contents of `data` into the buffer. If the contents won't fully
/**
* Writes the contents of `data` into the buffer. If the contents won't fully
* fit into the buffer, those bytes that are copied into the buffer will be flushed
* to the writer and the remaining bytes are then copied into the now empty buffer.
*
* @example Usage
* ```ts
* import { BufWriter } from "@std/io/buf-writer";
* import { Writer } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: Writer = {
* write(p: Uint8Array): Promise<number> {
* return Promise.resolve(p.length);
* }
* };
*
* const bufWriter = new BufWriter(writer);
* const data = new Uint8Array(1024);
*
* await bufWriter.write(data);
*
* assertEquals(bufWriter.buffered(), 1024);
* ```
*
* @param data The data to write to the buffer.
* @return the number of bytes written to the buffer.
*/
async write(data: Uint8Array): Promise<number> {
@ -126,19 +375,66 @@ export class BufWriter extends AbstractBufBase implements Writer {
}
}
/** BufWriterSync implements buffering for a deno.WriterSync object.
/**
* BufWriterSync implements buffering for a deno.WriterSync object.
* If an error occurs writing to a WriterSync, no more data will be
* accepted and all subsequent writes, and flush(), will return the error.
* After all data has been written, the client should call the
* flush() method to guarantee all data has been forwarded to
* the underlying deno.WriterSync.
*
* @example Usage
* ```ts
* import { BufWriterSync } from "@std/io/buf-writer";
* import { assertEquals } from "@std/assert/equals";
*
* const writer = {
* writeSync(p: Uint8Array): number {
* return p.length;
* }
* };
*
* const bufWriter = new BufWriterSync(writer);
* const data = new Uint8Array(1024);
*
* bufWriter.writeSync(data);
* bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class BufWriterSync extends AbstractBufBase implements WriterSync {
#writer: WriterSync;
/** return new BufWriterSync unless writer is BufWriterSync */
/**
* return new BufWriterSync unless writer is BufWriterSync
*
* @example Usage
* ```ts
* import { BufWriterSync } from "@std/io/buf-writer";
* import { WriterSync } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: WriterSync = {
* writeSync(p: Uint8Array): number {
* return p.length;
* }
* };
*
* const bufWriter = BufWriterSync.create(writer);
* const data = new Uint8Array(1024);
* bufWriter.writeSync(data);
* bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*
* @param writer The writer to wrap.
* @param size The size of the buffer.
* @returns a new {@linkcode BufWriterSync} instance.
*/
static create(
writer: WriterSync,
size: number = DEFAULT_BUF_SIZE,
@ -148,13 +444,43 @@ export class BufWriterSync extends AbstractBufBase implements WriterSync {
: new BufWriterSync(writer, size);
}
/**
* Construct a new {@linkcode BufWriterSync}
*
* @param writer The writer to wrap.
* @param size The size of the buffer.
*/
constructor(writer: WriterSync, size: number = DEFAULT_BUF_SIZE) {
super(new Uint8Array(size <= 0 ? DEFAULT_BUF_SIZE : size));
this.#writer = writer;
}
/** Discards any unflushed buffered data, clears any error, and
/**
* Discards any unflushed buffered data, clears any error, and
* resets buffer to write its output to w.
*
* @example Usage
* ```ts
* import { BufWriterSync } from "@std/io/buf-writer";
* import { WriterSync } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: WriterSync = {
* writeSync(p: Uint8Array): number {
* return p.length;
* }
* };
*
* const bufWriter = new BufWriterSync(writer);
* const data = new Uint8Array(1024);
*
* bufWriter.writeSync(data);
* bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*
* @param w The writer to write to.
*/
reset(w: WriterSync) {
this.err = null;
@ -162,7 +488,30 @@ export class BufWriterSync extends AbstractBufBase implements WriterSync {
this.#writer = w;
}
/** Flush writes any buffered data to the underlying io.WriterSync. */
/**
* Flush writes any buffered data to the underlying io.WriterSync.
*
* @example Usage
* ```ts
* import { BufWriterSync } from "@std/io/buf-writer";
* import { WriterSync } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: WriterSync = {
* writeSync(p: Uint8Array): number {
* return p.length;
* }
* };
*
* const bufWriter = new BufWriterSync(writer);
* const data = new Uint8Array(1024);
*
* bufWriter.writeSync(data);
* bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*/
flush() {
if (this.err !== null) throw this.err;
if (this.usedBufferBytes === 0) return;
@ -189,6 +538,28 @@ export class BufWriterSync extends AbstractBufBase implements WriterSync {
* buffer is the flushed to the writer and the remaining bytes are copied into
* the now empty buffer.
*
* @example Usage
* ```ts
* import { BufWriterSync } from "@std/io/buf-writer";
* import { WriterSync } from "@std/io/types";
* import { assertEquals } from "@std/assert/equals";
*
* const writer: WriterSync = {
* writeSync(p: Uint8Array): number {
* return p.length;
* }
* };
*
* const bufWriter = new BufWriterSync(writer);
* const data = new Uint8Array(1024);
*
* bufWriter.writeSync(data);
* bufWriter.flush();
*
* assertEquals(bufWriter.buffered(), 0);
* ```
*
* @param data The data to write to the buffer.
* @return the number of bytes written to the buffer.
*/
writeSync(data: Uint8Array): number {

View File

@ -11,7 +11,8 @@ import type { Reader, ReaderSync, Writer, WriterSync } from "./types.ts";
const MIN_READ = 32 * 1024;
const MAX_SIZE = 2 ** 32 - 2;
/** A variable-sized buffer of bytes with `read()` and `write()` methods.
/**
* A variable-sized buffer of bytes with `read()` and `write()` methods.
*
* Buffer is almost always used with some I/O like files and sockets. It allows
* one to buffer up a download from a socket. Buffer grows and shrinks as
@ -25,49 +26,145 @@ const MAX_SIZE = 2 ** 32 - 2;
* ArrayBuffer.
*
* Based on {@link https://golang.org/pkg/bytes/#Buffer | Go Buffer}.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, "));
* await buf.write(new TextEncoder().encode("world!"));
*
* const data = new Uint8Array(13);
* await buf.read(data);
*
* assertEquals(new TextDecoder().decode(data), "Hello, world!");
* ```
*/
export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
#buf: Uint8Array; // contents are the bytes buf[off : len(buf)]
#off = 0; // read at buf[off], write at buf[buf.byteLength]
/**
* Constructs a new instance with the specified {@linkcode ArrayBuffer} as its
* initial contents.
*
* @param ab The ArrayBuffer to use as the initial contents of the buffer.
*/
constructor(ab?: ArrayBufferLike | ArrayLike<number>) {
this.#buf = ab === undefined ? new Uint8Array(0) : new Uint8Array(ab);
}
/** Returns a slice holding the unread portion of the buffer.
/**
* Returns a slice holding the unread portion of the buffer.
*
* The slice is valid for use only until the next buffer modification (that
* is, only until the next call to a method like `read()`, `write()`,
* `reset()`, or `truncate()`). If `options.copy` is false the slice aliases the buffer content at
* least until the next buffer modification, so immediate changes to the
* slice will affect the result of future reads.
* @param [options={ copy: true }]
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, world!"));
*
* const slice = buf.bytes();
* assertEquals(new TextDecoder().decode(slice), "Hello, world!");
* ```
*
* @param options The options for the slice.
* @returns A slice holding the unread portion of the buffer.
*/
bytes(options = { copy: true }): Uint8Array {
if (options.copy === false) return this.#buf.subarray(this.#off);
return this.#buf.slice(this.#off);
}
/** Returns whether the unread portion of the buffer is empty. */
/**
* Returns whether the unread portion of the buffer is empty.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* assertEquals(buf.empty(), true);
* await buf.write(new TextEncoder().encode("Hello, world!"));
* assertEquals(buf.empty(), false);
* ```
*
* @returns `true` if the unread portion of the buffer is empty, `false`
* otherwise.
*/
empty(): boolean {
return this.#buf.byteLength <= this.#off;
}
/** A read only number of bytes of the unread portion of the buffer. */
/**
* A read only number of bytes of the unread portion of the buffer.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, world!"));
*
* assertEquals(buf.length, 13);
* ```
*
* @returns The number of bytes of the unread portion of the buffer.
*/
get length(): number {
return this.#buf.byteLength - this.#off;
}
/** The read only capacity of the buffer's underlying byte slice, that is,
* the total space allocated for the buffer's data. */
/**
* The read only capacity of the buffer's underlying byte slice, that is,
* the total space allocated for the buffer's data.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* assertEquals(buf.capacity, 0);
* await buf.write(new TextEncoder().encode("Hello, world!"));
* assertEquals(buf.capacity, 13);
* ```
*
* @returns The capacity of the buffer.
*/
get capacity(): number {
return this.#buf.buffer.byteLength;
}
/** Discards all but the first `n` unread bytes from the buffer but
/**
* Discards all but the first `n` unread bytes from the buffer but
* continues to use the same allocated storage. It throws if `n` is
* negative or greater than the length of the buffer. */
* negative or greater than the length of the buffer.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, world!"));
* buf.truncate(6);
* assertEquals(buf.length, 6);
* ```
*
* @param n The number of bytes to keep.
*/
truncate(n: number) {
if (n === 0) {
this.reset();
@ -79,6 +176,20 @@ export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
this.#reslice(this.#off + n);
}
/**
* Resets the contents
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, world!"));
* buf.reset();
* assertEquals(buf.length, 0);
* ```
*/
reset() {
this.#reslice(0);
this.#off = 0;
@ -100,9 +211,29 @@ export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
this.#buf = new Uint8Array(this.#buf.buffer, 0, len);
}
/** Reads the next `p.length` bytes from the buffer or until the buffer is
/**
* Reads the next `p.length` bytes from the buffer or until the buffer is
* drained. Returns the number of bytes read. If the buffer has no data to
* return, the return is EOF (`null`). */
* return, the return is EOF (`null`).
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, world!"));
*
* const data = new Uint8Array(5);
* const res = await buf.read(data);
*
* assertEquals(res, 5);
* assertEquals(new TextDecoder().decode(data), "Hello");
* ```
*
* @param p The buffer to read data into.
* @returns The number of bytes read.
*/
readSync(p: Uint8Array): number | null {
if (this.empty()) {
// Buffer is empty, reset to recover space.
@ -118,25 +249,85 @@ export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
return nread;
}
/** Reads the next `p.length` bytes from the buffer or until the buffer is
/**
* Reads the next `p.length` bytes from the buffer or until the buffer is
* drained. Resolves to the number of bytes read. If the buffer has no
* data to return, resolves to EOF (`null`).
*
* NOTE: This methods reads bytes synchronously; it's provided for
* compatibility with `Reader` interfaces.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* await buf.write(new TextEncoder().encode("Hello, world!"));
*
* const data = new Uint8Array(5);
* const res = await buf.read(data);
*
* assertEquals(res, 5);
* assertEquals(new TextDecoder().decode(data), "Hello");
* ```
*
* @param p The buffer to read data into.
* @returns The number of bytes read.
*/
read(p: Uint8Array): Promise<number | null> {
const rr = this.readSync(p);
return Promise.resolve(rr);
}
/**
* Writes the given data to the buffer.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* const data = new TextEncoder().encode("Hello, world!");
* buf.writeSync(data);
*
* const slice = buf.bytes();
* assertEquals(new TextDecoder().decode(slice), "Hello, world!");
* ```
*
* @param p The data to write to the buffer.
* @returns The number of bytes written.
*/
writeSync(p: Uint8Array): number {
const m = this.#grow(p.byteLength);
return copy(p, this.#buf, m);
}
/** NOTE: This methods writes bytes synchronously; it's provided for
* compatibility with `Writer` interface. */
/**
* Writes the given data to the buffer. Resolves to the number of bytes
* written.
*
* > [!NOTE]
* > This methods writes bytes synchronously; it's provided for compatibility
* > with the {@linkcode Writer} interface.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* const data = new TextEncoder().encode("Hello, world!");
* await buf.write(data);
*
* const slice = buf.bytes();
* assertEquals(new TextDecoder().decode(slice), "Hello, world!");
* ```
*
* @param p The data to write to the buffer.
* @returns The number of bytes written.
*/
write(p: Uint8Array): Promise<number> {
const n = this.writeSync(p);
return Promise.resolve(n);
@ -180,7 +371,20 @@ export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
* throw. If the buffer can't grow it will throw an error.
*
* Based on Go Lang's
* {@link https://golang.org/pkg/bytes/#Buffer.Grow | Buffer.Grow}. */
* {@link https://golang.org/pkg/bytes/#Buffer.Grow | Buffer.Grow}.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* buf.grow(10);
* assertEquals(buf.capacity, 10);
* ```
*
* @param n The number of bytes to grow the buffer by.
*/
grow(n: number) {
if (n < 0) {
throw Error("Buffer.grow: negative count");
@ -189,12 +393,30 @@ export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
this.#reslice(m);
}
/** Reads data from `r` until EOF (`null`) and appends it to the buffer,
/**
* Reads data from `r` until EOF (`null`) and appends it to the buffer,
* growing the buffer as needed. It resolves to the number of bytes read.
* If the buffer becomes too large, `.readFrom()` will reject with an error.
*
* Based on Go Lang's
* {@link https://golang.org/pkg/bytes/#Buffer.ReadFrom | Buffer.ReadFrom}. */
* {@link https://golang.org/pkg/bytes/#Buffer.ReadFrom | Buffer.ReadFrom}.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { StringReader } from "@std/io/string-reader";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* const r = new StringReader("Hello, world!");
* const n = await buf.readFrom(r);
*
* assertEquals(n, 13);
* ```
*
* @param r The reader to read from.
* @returns The number of bytes read.
*/
async readFrom(r: Reader): Promise<number> {
let n = 0;
const tmp = new Uint8Array(MIN_READ);
@ -224,7 +446,24 @@ export class Buffer implements Writer, WriterSync, Reader, ReaderSync {
* buffer becomes too large, `.readFromSync()` will throw an error.
*
* Based on Go Lang's
* {@link https://golang.org/pkg/bytes/#Buffer.ReadFrom | Buffer.ReadFrom}. */
* {@link https://golang.org/pkg/bytes/#Buffer.ReadFrom | Buffer.ReadFrom}.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { StringReader } from "@std/io/string-reader";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* const r = new StringReader("Hello, world!");
* const n = buf.readFromSync(r);
*
* assertEquals(n, 13);
* ```
*
* @param r The reader to read from.
* @returns The number of bytes read.
*/
readFromSync(r: ReaderSync): number {
let n = 0;
const tmp = new Uint8Array(MIN_READ);

View File

@ -10,8 +10,8 @@ import type { Reader, Writer } from "./types.ts";
* an error occurs. It resolves to the number of bytes copied or rejects with
* the first error encountered while copying.
*
* @example
* ```ts
* @example Usage
* ```ts no-eval
* import { copy } from "@std/io/copy";
*
* const source = await Deno.open("my_file.txt");

View File

@ -7,9 +7,22 @@ const DEFAULT_BUFFER_SIZE = 32 * 1024;
/**
* Copy N size at the most. If read size is lesser than N, then returns nread
*
* @example Usage
* ```ts
* import { copyN } from "@std/io/copy-n";
* import { assertEquals } from "@std/assert/equals";
*
* const source = await Deno.open("README.md");
*
* const res = await copyN(source, Deno.stdout, 10);
* assertEquals(res, 10);
* ```
*
* @param r Reader
* @param dest Writer
* @param size Read size
* @returns Number of bytes copied
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/

View File

@ -9,24 +9,21 @@ export type { Reader, ReaderSync };
/**
* Turns a {@linkcode Reader} into an async iterator.
*
* @example
* ```ts
* @example Usage
* ```ts no-assert
* import { iterateReader } from "@std/io/iterate-reader";
*
* using file = await Deno.open("/etc/passwd");
* using file = await Deno.open("README.md");
* for await (const chunk of iterateReader(file)) {
* console.log(chunk);
* }
* ```
*
* Second argument can be used to tune size of a buffer.
* Default size of the buffer is 32kB.
*
* @example
* ```ts
* @example Usage with buffer size
* ```ts no-assert
* import { iterateReader } from "@std/io/iterate-reader";
*
* using file = await Deno.open("/etc/passwd");
* using file = await Deno.open("README.md");
* const iter = iterateReader(file, {
* bufSize: 1024 * 1024
* });
@ -34,6 +31,11 @@ export type { Reader, ReaderSync };
* console.log(chunk);
* }
* ```
*
* @param reader The reader to read from
* @param options The options
* @param options.bufSize The size of the buffer to use
* @returns The async iterator of Uint8Array chunks
*/
export async function* iterateReader(
reader: Reader,
@ -56,27 +58,31 @@ export async function* iterateReader(
/**
* Turns a {@linkcode ReaderSync} into an iterator.
*
* @example Usage
* ```ts
* import { iterateReaderSync } from "@std/io/iterate-reader";
* import { assert } from "@std/assert/assert"
*
* using file = Deno.openSync("/etc/passwd");
* using file = Deno.openSync("README.md");
* for (const chunk of iterateReaderSync(file)) {
* console.log(chunk);
* assert(chunk instanceof Uint8Array);
* }
* ```
*
* Second argument can be used to tune size of a buffer.
* Default size of the buffer is 32kB.
*
* @example Usage with buffer size
* ```ts
* import { iterateReaderSync } from "@std/io/iterate-reader";
* using file = await Deno.open("/etc/passwd");
* import { assert } from "@std/assert/assert"
*
* using file = await Deno.open("README.md");
* const iter = iterateReaderSync(file, {
* bufSize: 1024 * 1024
* });
* for (const chunk of iter) {
* console.log(chunk);
* assert(chunk instanceof Uint8Array);
* }
* ```
*
@ -84,6 +90,10 @@ export async function* iterateReader(
* a view on that buffer on each iteration. It is therefore caller's
* responsibility to copy contents of the buffer if needed; otherwise the
* next iteration will overwrite contents of previously returned chunk.
*
* @param reader The reader to read from
* @param options The options
* @returns The iterator of Uint8Array chunks
*/
export function* iterateReaderSync(
reader: ReaderSync,

View File

@ -1,26 +1,97 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
/**
* A `LimitedReader` reads from `reader` but limits the amount of data returned to just `limit` bytes.
* Each call to `read` updates `limit` to reflect the new amount remaining.
* `read` returns `null` when `limit` <= `0` or
* when the underlying `reader` returns `null`.
*/
import type { Reader } from "./types.ts";
/**
* Reads from `reader` but limits the amount of data returned to just `limit` bytes.
* Each call to `read` updates `limit` to reflect the new amount remaining.
* `read` returns `null` when `limit` <= `0` or
* when the underlying `reader` returns `null`.
*
* @example Usage
* ```ts
* import { StringReader } from "@std/io/string-reader";
* import { LimitedReader } from "@std/io/limited-reader";
* import { readAll } from "@std/io/read-all";
* import { assertEquals } from "@std/assert/equals";
*
* const r = new StringReader("hello world");
* const lr = new LimitedReader(r, 5);
* const res = await readAll(lr);
*
* assertEquals(new TextDecoder().decode(res), "hello");
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class LimitedReader implements Reader {
/**
* The reader to read from
*
* @example Usage
* ```ts
* import { StringReader } from "@std/io/string-reader";
* import { LimitedReader } from "@std/io/limited-reader";
* import { assertEquals } from "@std/assert/equals";
*
* const r = new StringReader("hello world");
* const lr = new LimitedReader(r, 5);
*
* assertEquals(lr.reader, r);
* ```
*/
reader: Reader;
/**
* The number of bytes to limit the reader to
*
* @example Usage
* ```ts
* import { StringReader } from "@std/io/string-reader";
* import { LimitedReader } from "@std/io/limited-reader";
* import { assertEquals } from "@std/assert/equals";
*
* const r = new StringReader("hello world");
* const lr = new LimitedReader(r, 5);
*
* assertEquals(lr.limit, 5);
* ```
*/
limit: number;
/**
* Construct a new instance.
*
* @param reader The reader to read from.
* @param limit The number of bytes to limit the reader to.
*/
constructor(reader: Reader, limit: number) {
this.reader = reader;
this.limit = limit;
}
/**
* Reads data from the reader.
*
* @example Usage
* ```ts
* import { StringReader } from "@std/io/string-reader";
* import { LimitedReader } from "@std/io/limited-reader";
* import { assertEquals } from "@std/assert/equals";
*
* const r = new StringReader("hello world");
* const lr = new LimitedReader(r, 5);
*
* const data = new Uint8Array(5);
* const res = await lr.read(data);
*
* assertEquals(res, 5);
* assertEquals(new TextDecoder().decode(data), "hello");
* ```
*
* @param p The buffer to read data into.
* @returns The number of bytes read.
*/
async read(p: Uint8Array): Promise<number | null> {
if (this.limit <= 0) {
return null;

View File

@ -6,6 +6,13 @@
* `Reader` and `Writer` interfaces are deprecated in Deno, and so many of these
* utilities are also deprecated. Consider using web streams instead.
*
* ```ts no-assert
* import { toReadableStream, toWritableStream } from "@std/io";
*
* await toReadableStream(Deno.stdin)
* .pipeTo(toWritableStream(Deno.stdout));
* ```
*
* @module
*/

View File

@ -4,7 +4,23 @@
import type { Reader } from "./types.ts";
/**
* Reader utility for combining multiple readers
* Reader utility for combining multiple readers.
*
* @example Usage
* ```ts
* import { MultiReader } from "@std/io/multi-reader";
* import { StringReader } from "@std/io/string-reader";
* import { readAll } from "@std/io/read-all";
* import { assertEquals } from "@std/assert/equals";
*
* const r1 = new StringReader("hello");
* const r2 = new StringReader("world");
* const mr = new MultiReader([r1, r2]);
*
* const res = await readAll(mr);
*
* assertEquals(new TextDecoder().decode(res), "helloworld");
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
@ -12,10 +28,46 @@ export class MultiReader implements Reader {
readonly #readers: Reader[];
#currentIndex = 0;
/**
* Construct a new instance.
*
* @param readers The readers to combine.
*/
constructor(readers: Reader[]) {
this.#readers = [...readers];
}
/**
* Reads data from the readers.
*
* @example Usage
* ```ts
* import { MultiReader } from "@std/io/multi-reader";
* import { StringReader } from "@std/io/string-reader";
* import { readAll } from "@std/io/read-all";
* import { assertEquals } from "@std/assert/equals";
*
* const r1 = new StringReader("hello");
* const r2 = new StringReader("world");
* const mr = new MultiReader([r1, r2]);
*
* const data = new Uint8Array(5);
* const res = await mr.read(data);
*
* assertEquals(res, 5);
* assertEquals(new TextDecoder().decode(data), "hello");
*
* const res2 = await mr.read(data);
* assertEquals(res2, 0);
*
* const res3 = await mr.read(data);
* assertEquals(res3, 5);
* assertEquals(new TextDecoder().decode(data), "world");
* ```
*
* @param p The buffer to read data into.
* @returns The number of bytes read.
*/
async read(p: Uint8Array): Promise<number | null> {
const r = this.#readers[this.#currentIndex];
if (!r) return null;

View File

@ -9,8 +9,8 @@ import type { Reader, ReaderSync } from "./types.ts";
* Read {@linkcode Reader} `r` until EOF (`null`) and resolve to the content as
* {@linkcode Uint8Array}.
*
* @example
* ```ts
* @example Usage
* ```ts no-eval
* import { readAll } from "@std/io/read-all";
*
* // Example from stdin
@ -20,6 +20,9 @@ import type { Reader, ReaderSync } from "./types.ts";
* using file = await Deno.open("my_file.txt", {read: true});
* const myFileContent = await readAll(file);
* ```
*
* @param reader The reader to read from
* @returns The content as Uint8Array
*/
export async function readAll(reader: Reader): Promise<Uint8Array> {
const chunks: Uint8Array[] = [];
@ -41,8 +44,8 @@ export async function readAll(reader: Reader): Promise<Uint8Array> {
* Synchronously reads {@linkcode ReaderSync} `r` until EOF (`null`) and returns
* the content as {@linkcode Uint8Array}.
*
* @example
* ```ts
* @example Usage
* ```ts no-eval
* import { readAllSync } from "@std/io/read-all";
*
* // Example from stdin
@ -52,6 +55,9 @@ export async function readAll(reader: Reader): Promise<Uint8Array> {
* using file = Deno.openSync("my_file.txt", {read: true});
* const myFileContent = readAllSync(file);
* ```
*
* @param reader The reader to read from
* @returns The content as Uint8Array
*/
export function readAllSync(reader: ReaderSync): Uint8Array {
const chunks: Uint8Array[] = [];

View File

@ -26,7 +26,23 @@ function createLPS(pat: Uint8Array): Uint8Array {
}
/**
* Read delimited bytes from a Reader.
* Read delimited bytes from a {@linkcode Reader} through an
* {@linkcode AsyncIterableIterator} of {@linkcode Uint8Array}.
*
* @example Usage
* ```ts
* import { readDelim } from "@std/io/read-delim";
* import { assert } from "@std/assert/assert"
*
* const fileReader = await Deno.open("README.md");
* for await (const chunk of readDelim(fileReader, new TextEncoder().encode("\n"))) {
* assert(chunk instanceof Uint8Array);
* }
* ```
*
* @param reader The reader to read from
* @param delim The delimiter to read until
* @returns The {@linkcode AsyncIterableIterator} of {@linkcode Uint8Array}s.
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/

View File

@ -4,8 +4,21 @@ import type { BufReader } from "./buf_reader.ts";
import { readShort } from "./read_short.ts";
/**
* Read big endian 32bit integer from BufReader
* @param buf
* Read big endian 32bit integer from a {@linkcode BufReader}.
*
* @example Usage
* ```ts
* import { BufReader } from "@std/io/buf-reader";
* import { readInt } from "@std/io/read-int";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new BufReader(new Deno.Buffer(new Uint8Array([0x12, 0x34, 0x56, 0x78])));
* const int = await readInt(buf);
* assertEquals(int, 0x12345678);
* ```
*
* @param buf The buffer reader to read from
* @returns The 32bit integer
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/

View File

@ -6,21 +6,24 @@ import { BufReader } from "./buf_reader.ts";
import { concat } from "@std/bytes/concat";
/**
* Read strings line-by-line from a Reader.
* Read strings line-by-line from a {@linkcode Reader}.
*
* @example
* @example Usage
* ```ts
* import { readLines } from "@std/io/read-lines";
* import * as path from "@std/path";
* import { assert } from "@std/assert/assert"
*
* const filename = path.join(Deno.cwd(), "std/io/README.md");
* let fileReader = await Deno.open(filename);
* let fileReader = await Deno.open("README.md");
*
* for await (let line of readLines(fileReader)) {
* console.log(line);
* assert(typeof line === "string");
* }
* ```
*
* @param reader The reader to read from
* @param decoderOpts The options
* @returns The async iterator of strings
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export async function* readLines(

View File

@ -6,8 +6,23 @@ import { readInt } from "./read_int.ts";
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
/**
* Read big endian 64bit long from BufReader
* @param buf
* Read big endian 64bit long from a {@linkcode BufReader}.
*
* @example Usage
* ```ts
* import { BufReader } from "@std/io/buf-reader";
* import { readLong } from "@std/io/read-long";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new BufReader(new Deno.Buffer(new Uint8Array([0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0x9a])));
* const long = await readLong(buf);
* assertEquals(long, 0x123456789a);
* ```
*
* @param buf The BufReader to read from
* @returns The 64bit long
* @throws {Deno.errors.UnexpectedEof} If the reader returns unexpected EOF
* @throws {RangeError} If the long value is too big to be represented as a JavaScript number
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/

View File

@ -6,6 +6,8 @@ import type { Reader, ReaderSync } from "./types.ts";
const DEFAULT_BUFFER_SIZE = 32 * 1024;
/**
* The range of bytes to read from a file or other resource that is readable.
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export interface ByteRange {
@ -21,7 +23,8 @@ export interface ByteRange {
* seekable. The range start and end are inclusive of the bytes within that
* range.
*
* ```ts
* @example Usage
* ```ts no-eval
* import { assertEquals } from "@std/assert";
* import { readRange } from "@std/io/read-range";
*
@ -31,6 +34,10 @@ export interface ByteRange {
* assertEquals(bytes.length, 10);
* ```
*
* @param r The reader to read from
* @param range The range of bytes to read
* @returns The bytes read
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export async function readRange(
@ -67,7 +74,8 @@ export async function readRange(
* readable and seekable. The range start and end are inclusive of the bytes
* within that range.
*
* ```ts
* @example Usage
* ```ts no-eval
* import { assertEquals } from "@std/assert";
* import { readRangeSync } from "@std/io/read-range";
*
@ -77,6 +85,10 @@ export async function readRange(
* assertEquals(bytes.length, 10);
* ```
*
* @param r The reader to read from
* @param range The range of bytes to read
* @returns The bytes read
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export function readRangeSync(

View File

@ -3,8 +3,21 @@
import type { BufReader } from "./buf_reader.ts";
/**
* Read big endian 16bit short from BufReader
* @param buf
* Read big endian 16bit short from a {@linkcode BufReader}.
*
* @example Usage
* ```ts
* import { BufReader } from "@std/io/buf-reader";
* import { readShort } from "@std/io/read-short";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new BufReader(new Deno.Buffer(new Uint8Array([0x12, 0x34])));
* const short = await readShort(buf);
* assertEquals(short, 0x1234);
* ```
*
* @param buf The reader to read from
* @returns The 16bit short
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/

View File

@ -5,21 +5,25 @@ import type { Reader } from "./types.ts";
import { readDelim } from "./read_delim.ts";
/**
* Read Reader chunk by chunk, splitting based on delimiter.
* Read {@linkcode Reader} chunk by chunk, splitting based on delimiter.
*
* @example
* @example Usage
* ```ts
* import { readStringDelim } from "@std/io/read-string-delim";
* import * as path from "@std/path";
* import { assert } from "@std/assert/assert"
*
* const filename = path.join(Deno.cwd(), "std/io/README.md");
* let fileReader = await Deno.open(filename);
* let fileReader = await Deno.open("README.md");
*
* for await (let line of readStringDelim(fileReader, "\n")) {
* console.log(line);
* assert(typeof line === "string");
* }
* ```
*
* @param reader The reader to read from
* @param delim The delimiter to split the reader by
* @param decoderOpts The options
* @returns The async iterator of strings
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export async function* readStringDelim(

View File

@ -8,17 +8,19 @@ import type { Reader } from "./types.ts";
/**
* Create a {@linkcode Reader} from a {@linkcode ReadableStreamDefaultReader}.
*
* @example
* ```ts
* @example Usage
* ```ts no-assert
* import { copy } from "@std/io/copy";
* import { readerFromStreamReader } from "@std/io/reader-from-stream-reader";
*
* const res = await fetch("https://deno.land");
* using file = await Deno.open("./deno.land.html", { create: true, write: true });
*
* const reader = readerFromStreamReader(res.body!.getReader());
* await copy(reader, file);
* await copy(reader, Deno.stdout);
* ```
*
* @param streamReader The stream reader to read from
* @returns The reader
*/
export function readerFromStreamReader(
streamReader: ReadableStreamDefaultReader<Uint8Array>,

View File

@ -2,9 +2,20 @@
// This module is browser compatible.
/**
* Slice number into 64bit big endian byte array
* Slice number into 64bit big endian byte array.
*
* @example Usage
* ```ts
* import { sliceLongToBytes } from "@std/io/slice-long-to-bytes";
* import { assertEquals } from "@std/assert/equals";
*
* const dest = sliceLongToBytes(0x123456789a);
* assertEquals(dest, [0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0x9a]);
* ```
*
* @param d The number to be sliced
* @param dest The sliced array
* @param dest The array to store the sliced bytes
* @returns The sliced bytes
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/

View File

@ -6,35 +6,29 @@ import { Buffer } from "./buffer.ts";
/**
* Reader utility for strings.
*
* @example
* @example Usage
* ```ts
* import { StringReader } from "@std/io/string-reader";
* import { assertEquals } from "@std/assert/equals";
*
* const data = new Uint8Array(6);
* const r = new StringReader("abcdef");
* const res0 = await r.read(data);
* const res1 = await r.read(new Uint8Array(6));
*
* // Number of bytes read
* console.log(res0); // 6
* console.log(res1); // null, no byte left to read. EOL
*
* // text
*
* console.log(new TextDecoder().decode(data)); // abcdef
* ```
*
* **Output:**
*
* ```text
* 6
* null
* abcdef
* assertEquals(res0, 6);
* assertEquals(res1, null);
* assertEquals(new TextDecoder().decode(data), "abcdef");
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
*/
export class StringReader extends Buffer {
/**
* Construct a new instance.
*
* @param s The string to read.
*/
constructor(s: string) {
super(new TextEncoder().encode(s).buffer);
}

View File

@ -8,7 +8,7 @@ const decoder = new TextDecoder();
/**
* Writer utility for buffering string chunks.
*
* @example
* @example Usage
* ```ts
* import {
* copyN,
@ -16,23 +16,16 @@ const decoder = new TextDecoder();
* StringWriter,
* } from "@std/io";
* import { copy } from "@std/io/copy";
* import { assertEquals } from "@std/assert/equals";
*
* const w = new StringWriter("base");
* const r = new StringReader("0123456789");
* await copyN(r, w, 4); // copy 4 bytes
*
* // Number of bytes read
* console.log(w.toString()); //base0123
* assertEquals(w.toString(), "base0123");
*
* await copy(r, w); // copy all
* console.log(w.toString()); // base0123456789
* ```
*
* **Output:**
*
* ```text
* base0123
* base0123456789
* assertEquals(w.toString(), "base0123456789");
* ```
*
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
@ -43,6 +36,11 @@ export class StringWriter implements Writer, WriterSync {
#cache: string | undefined;
#base: string;
/**
* Construct a new instance.
*
* @param base The base string to write to the buffer.
*/
constructor(base = "") {
const c = new TextEncoder().encode(base);
this.#chunks.push(c);
@ -50,10 +48,42 @@ export class StringWriter implements Writer, WriterSync {
this.#base = base;
}
/**
* Writes the bytes to the buffer asynchronously.
*
* @example Usage
* ```ts
* import { StringWriter } from "@std/io/string-writer";
* import { assertEquals } from "@std/assert/equals";
*
* const w = new StringWriter("base");
* await w.write(new TextEncoder().encode("0123"));
* assertEquals(w.toString(), "base0123");
* ```
*
* @param p The bytes to write to the buffer.
* @returns The number of bytes written to the buffer in total.
*/
write(p: Uint8Array): Promise<number> {
return Promise.resolve(this.writeSync(p));
}
/**
* Writes the bytes to the buffer synchronously.
*
* @example Usage
* ```ts
* import { StringWriter } from "@std/io/string-writer";
* import { assertEquals } from "@std/assert/equals";
*
* const w = new StringWriter("base");
* w.writeSync(new TextEncoder().encode("0123"));
* assertEquals(w.toString(), "base0123");
* ```
*
* @param p The bytes to write to the buffer.
* @returns The number of bytes written to the buffer in total.
*/
writeSync(p: Uint8Array): number {
this.#chunks.push(new Uint8Array(p));
this.#byteLength += p.byteLength;
@ -61,6 +91,21 @@ export class StringWriter implements Writer, WriterSync {
return p.byteLength;
}
/**
* Returns the string written to the buffer.
*
* @example Usage
* ```ts
* import { StringWriter } from "@std/io/string-writer";
* import { assertEquals } from "@std/assert/equals";
*
* const w = new StringWriter("base");
* await w.write(new TextEncoder().encode("0123"));
* assertEquals(w.toString(), "base0123");
* ```
*
* @returns the string written to the buffer.
*/
toString(): string {
if (this.#cache) {
return this.#cache;

View File

@ -14,11 +14,14 @@ export interface ToReadableStreamOptions {
*/
autoClose?: boolean;
/** The size of chunks to allocate to read, the default is ~16KiB, which is
* the maximum size that Deno operations can currently support. */
/**
* The size of chunks to allocate to read.
*
* @default {16640}
*/
chunkSize?: number;
/** The queuing strategy to create the `ReadableStream` with. */
/** The queuing strategy to create the {@linkcode ReadableStream} with. */
strategy?: QueuingStrategy<Uint8Array>;
}
@ -30,13 +33,17 @@ export interface ToReadableStreamOptions {
* will be read. When `null` is returned from the reader, the stream will be
* closed along with the reader (if it is also a `Closer`).
*
* @example
* ```ts
* @example Usage
* ```ts no-assert
* import { toReadableStream } from "@std/io/to-readable-stream";
*
* const file = await Deno.open("./file.txt", { read: true });
* const file = await Deno.open("./README.md", { read: true });
* const fileStream = toReadableStream(file);
* ```
*
* @param reader The reader to read from
* @param options The options
* @returns The readable stream
*/
export function toReadableStream(
reader: Reader | (Reader & Closer),

View File

@ -19,15 +19,18 @@ export interface toWritableStreamOptions {
/**
* Create a {@linkcode WritableStream} from a {@linkcode Writer}.
*
* @example
* ```ts
* @example Usage
* ```ts no-assert
* import { toWritableStream } from "@std/io/to-writable-stream";
*
* const file = await Deno.open("./file.txt", { create: true, write: true });
* await ReadableStream.from("Hello World")
* await ReadableStream.from(["Hello World"])
* .pipeThrough(new TextEncoderStream())
* .pipeTo(toWritableStream(file));
* .pipeTo(toWritableStream(Deno.stdout));
* ```
*
* @param writer The writer to write to
* @param options The options
* @returns The writable stream
*/
export function toWritableStream(
writer: Writer,

View File

@ -6,19 +6,25 @@ import type { Writer, WriterSync } from "./types.ts";
/**
* Write all the content of the array buffer (`arr`) to the writer (`w`).
*
* @example
* ```ts
* @example Writing to stdout
* ```ts no-assert
* import { writeAll } from "@std/io/write-all";
* // Example writing to stdout
* let contentBytes = new TextEncoder().encode("Hello World");
* await writeAll(Deno.stdout, contentBytes);
*
* // Example writing to file
* contentBytes = new TextEncoder().encode("Hello World");
* using file = await Deno.open('test.file', {write: true});
* const contentBytes = new TextEncoder().encode("Hello World");
* await writeAll(Deno.stdout, contentBytes);
* ```
*
* @example Writing to file
* ```ts no-eval no-assert
* import { writeAll } from "@std/io/write-all";
*
* const contentBytes = new TextEncoder().encode("Hello World");
* using file = await Deno.open('test.file', { write: true });
* await writeAll(file, contentBytes);
* ```
*
* @param writer The writer to write to
* @param data The data to write
*/
export async function writeAll(writer: Writer, data: Uint8Array) {
let nwritten = 0;
@ -31,19 +37,25 @@ export async function writeAll(writer: Writer, data: Uint8Array) {
* Synchronously write all the content of the array buffer (`arr`) to the
* writer (`w`).
*
* @example
* ```ts
* @example "riting to stdout
* ```ts no-assert
* import { writeAllSync } from "@std/io/write-all";
*
* // Example writing to stdout
* let contentBytes = new TextEncoder().encode("Hello World");
* const contentBytes = new TextEncoder().encode("Hello World");
* writeAllSync(Deno.stdout, contentBytes);
* ```
*
* // Example writing to file
* contentBytes = new TextEncoder().encode("Hello World");
* using file = Deno.openSync('test.file', {write: true});
* @example Writing to file
* ```ts no-eval no-assert
* import { writeAllSync } from "@std/io/write-all";
*
* const contentBytes = new TextEncoder().encode("Hello World");
* using file = Deno.openSync("test.file", { write: true });
* writeAllSync(file, contentBytes);
* ```
*
* @param writer The writer to write to
* @param data The data to write
*/
export function writeAllSync(writer: WriterSync, data: Uint8Array) {
let nwritten = 0;