mirror of
https://github.com/swc-project/swc.git
synced 2024-12-22 05:01:42 +03:00
328 lines
9.2 KiB
TypeScript
328 lines
9.2 KiB
TypeScript
|
// Loaded from https://deno.land/std@0.101.0/io/util.ts
|
||
|
|
||
|
|
||
|
import { Buffer } from "./buffer.ts";
|
||
|
import { copy as copyBytes } from "../bytes/mod.ts";
|
||
|
import { assert } from "../testing/asserts.ts";
|
||
|
|
||
|
const DEFAULT_BUFFER_SIZE = 32 * 1024;
|
||
|
|
||
|
/** Read Reader `r` until EOF (`null`) and resolve to the content as
|
||
|
* Uint8Array`.
|
||
|
*
|
||
|
* ```ts
|
||
|
*
|
||
|
* // Example from stdin
|
||
|
* const stdinContent = await readAll(Deno.stdin);
|
||
|
*
|
||
|
* // Example from file
|
||
|
* const file = await Deno.open("my_file.txt", {read: true});
|
||
|
* const myFileContent = await readAll(file);
|
||
|
* Deno.close(file.rid);
|
||
|
*
|
||
|
* // Example from buffer
|
||
|
* const myData = new Uint8Array(100);
|
||
|
* // ... fill myData array with data
|
||
|
* const reader = new Buffer(myData.buffer);
|
||
|
* const bufferContent = await readAll(reader);
|
||
|
* ```
|
||
|
*/
|
||
|
export async function readAll(r: Deno.Reader): Promise<Uint8Array> {
|
||
|
const buf = new Buffer();
|
||
|
await buf.readFrom(r);
|
||
|
return buf.bytes();
|
||
|
}
|
||
|
|
||
|
/** Synchronously reads Reader `r` until EOF (`null`) and returns the content
|
||
|
* as `Uint8Array`.
|
||
|
*
|
||
|
* ```ts
|
||
|
* // Example from stdin
|
||
|
* const stdinContent = readAllSync(Deno.stdin);
|
||
|
*
|
||
|
* // Example from file
|
||
|
* const file = Deno.openSync("my_file.txt", {read: true});
|
||
|
* const myFileContent = readAllSync(file);
|
||
|
* Deno.close(file.rid);
|
||
|
*
|
||
|
* // Example from buffer
|
||
|
* const myData = new Uint8Array(100);
|
||
|
* // ... fill myData array with data
|
||
|
* const reader = new Buffer(myData.buffer);
|
||
|
* const bufferContent = readAllSync(reader);
|
||
|
* ```
|
||
|
*/
|
||
|
export function readAllSync(r: Deno.ReaderSync): Uint8Array {
|
||
|
const buf = new Buffer();
|
||
|
buf.readFromSync(r);
|
||
|
return buf.bytes();
|
||
|
}
|
||
|
|
||
|
export interface ByteRange {
|
||
|
/** The 0 based index of the start byte for a range. */
|
||
|
start: number;
|
||
|
|
||
|
/** The 0 based index of the end byte for a range, which is inclusive. */
|
||
|
end: number;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read a range of bytes from a file or other resource that is readable and
|
||
|
* seekable. The range start and end are inclusive of the bytes within that
|
||
|
* range.
|
||
|
*
|
||
|
* ```ts
|
||
|
* // Read the first 10 bytes of a file
|
||
|
* const file = await Deno.open("example.txt", { read: true });
|
||
|
* const bytes = await readRange(file, { start: 0, end: 9 });
|
||
|
* assert(bytes.length, 10);
|
||
|
* ```
|
||
|
*/
|
||
|
export async function readRange(
|
||
|
r: Deno.Reader & Deno.Seeker,
|
||
|
range: ByteRange,
|
||
|
): Promise<Uint8Array> {
|
||
|
// byte ranges are inclusive, so we have to add one to the end
|
||
|
let length = range.end - range.start + 1;
|
||
|
assert(length > 0, "Invalid byte range was passed.");
|
||
|
await r.seek(range.start, Deno.SeekMode.Start);
|
||
|
const result = new Uint8Array(length);
|
||
|
let off = 0;
|
||
|
while (length) {
|
||
|
const p = new Uint8Array(Math.min(length, DEFAULT_BUFFER_SIZE));
|
||
|
const nread = await r.read(p);
|
||
|
assert(nread !== null, "Unexpected EOF reach while reading a range.");
|
||
|
assert(nread > 0, "Unexpected read of 0 bytes while reading a range.");
|
||
|
copyBytes(p, result, off);
|
||
|
off += nread;
|
||
|
length -= nread;
|
||
|
assert(length >= 0, "Unexpected length remaining after reading range.");
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read a range of bytes synchronously from a file or other resource that is
|
||
|
* readable and seekable. The range start and end are inclusive of the bytes
|
||
|
* within that range.
|
||
|
*
|
||
|
* ```ts
|
||
|
* // Read the first 10 bytes of a file
|
||
|
* const file = Deno.openSync("example.txt", { read: true });
|
||
|
* const bytes = readRangeSync(file, { start: 0, end: 9 });
|
||
|
* assert(bytes.length, 10);
|
||
|
* ```
|
||
|
*/
|
||
|
export function readRangeSync(
|
||
|
r: Deno.ReaderSync & Deno.SeekerSync,
|
||
|
range: ByteRange,
|
||
|
): Uint8Array {
|
||
|
// byte ranges are inclusive, so we have to add one to the end
|
||
|
let length = range.end - range.start + 1;
|
||
|
assert(length > 0, "Invalid byte range was passed.");
|
||
|
r.seekSync(range.start, Deno.SeekMode.Start);
|
||
|
const result = new Uint8Array(length);
|
||
|
let off = 0;
|
||
|
while (length) {
|
||
|
const p = new Uint8Array(Math.min(length, DEFAULT_BUFFER_SIZE));
|
||
|
const nread = r.readSync(p);
|
||
|
assert(nread !== null, "Unexpected EOF reach while reading a range.");
|
||
|
assert(nread > 0, "Unexpected read of 0 bytes while reading a range.");
|
||
|
copyBytes(p, result, off);
|
||
|
off += nread;
|
||
|
length -= nread;
|
||
|
assert(length >= 0, "Unexpected length remaining after reading range.");
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** Write all the content of the array buffer (`arr`) to the writer (`w`).
|
||
|
*
|
||
|
* ```ts
|
||
|
* // Example writing to stdout
|
||
|
* const contentBytes = new TextEncoder().encode("Hello World");
|
||
|
* await writeAll(Deno.stdout, contentBytes);
|
||
|
*
|
||
|
* // Example writing to file
|
||
|
* const contentBytes = new TextEncoder().encode("Hello World");
|
||
|
* const file = await Deno.open('test.file', {write: true});
|
||
|
* await writeAll(file, contentBytes);
|
||
|
* Deno.close(file.rid);
|
||
|
*
|
||
|
* // Example writing to buffer
|
||
|
* const contentBytes = new TextEncoder().encode("Hello World");
|
||
|
* const writer = new Buffer();
|
||
|
* await writeAll(writer, contentBytes);
|
||
|
* console.log(writer.bytes().length); // 11
|
||
|
* ```
|
||
|
*/
|
||
|
export async function writeAll(w: Deno.Writer, arr: Uint8Array) {
|
||
|
let nwritten = 0;
|
||
|
while (nwritten < arr.length) {
|
||
|
nwritten += await w.write(arr.subarray(nwritten));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Synchronously write all the content of the array buffer (`arr`) to the
|
||
|
* writer (`w`).
|
||
|
*
|
||
|
* ```ts
|
||
|
* // Example writing to stdout
|
||
|
* const contentBytes = new TextEncoder().encode("Hello World");
|
||
|
* writeAllSync(Deno.stdout, contentBytes);
|
||
|
*
|
||
|
* // Example writing to file
|
||
|
* const contentBytes = new TextEncoder().encode("Hello World");
|
||
|
* const file = Deno.openSync('test.file', {write: true});
|
||
|
* writeAllSync(file, contentBytes);
|
||
|
* Deno.close(file.rid);
|
||
|
*
|
||
|
* // Example writing to buffer
|
||
|
* const contentBytes = new TextEncoder().encode("Hello World");
|
||
|
* const writer = new Buffer();
|
||
|
* writeAllSync(writer, contentBytes);
|
||
|
* console.log(writer.bytes().length); // 11
|
||
|
* ```
|
||
|
*/
|
||
|
export function writeAllSync(w: Deno.WriterSync, arr: Uint8Array): void {
|
||
|
let nwritten = 0;
|
||
|
while (nwritten < arr.length) {
|
||
|
nwritten += w.writeSync(arr.subarray(nwritten));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Turns a Reader, `r`, into an async iterator.
|
||
|
*
|
||
|
* ```ts
|
||
|
* let f = await Deno.open("/etc/passwd");
|
||
|
* for await (const chunk of iter(f)) {
|
||
|
* console.log(chunk);
|
||
|
* }
|
||
|
* f.close();
|
||
|
* ```
|
||
|
*
|
||
|
* Second argument can be used to tune size of a buffer.
|
||
|
* Default size of the buffer is 32kB.
|
||
|
*
|
||
|
* ```ts
|
||
|
* let f = await Deno.open("/etc/passwd");
|
||
|
* const iter = iter(f, {
|
||
|
* bufSize: 1024 * 1024
|
||
|
* });
|
||
|
* for await (const chunk of iter) {
|
||
|
* console.log(chunk);
|
||
|
* }
|
||
|
* f.close();
|
||
|
* ```
|
||
|
*
|
||
|
* Iterator uses an internal buffer of fixed size for efficiency; it returns
|
||
|
* 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.
|
||
|
*/
|
||
|
export async function* iter(
|
||
|
r: Deno.Reader,
|
||
|
options?: {
|
||
|
bufSize?: number;
|
||
|
},
|
||
|
): AsyncIterableIterator<Uint8Array> {
|
||
|
const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
|
||
|
const b = new Uint8Array(bufSize);
|
||
|
while (true) {
|
||
|
const result = await r.read(b);
|
||
|
if (result === null) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
yield b.subarray(0, result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Turns a ReaderSync, `r`, into an iterator.
|
||
|
*
|
||
|
* ```ts
|
||
|
* let f = Deno.openSync("/etc/passwd");
|
||
|
* for (const chunk of iterSync(f)) {
|
||
|
* console.log(chunk);
|
||
|
* }
|
||
|
* f.close();
|
||
|
* ```
|
||
|
*
|
||
|
* Second argument can be used to tune size of a buffer.
|
||
|
* Default size of the buffer is 32kB.
|
||
|
*
|
||
|
* ```ts
|
||
|
* let f = await Deno.open("/etc/passwd");
|
||
|
* const iter = iterSync(f, {
|
||
|
* bufSize: 1024 * 1024
|
||
|
* });
|
||
|
* for (const chunk of iter) {
|
||
|
* console.log(chunk);
|
||
|
* }
|
||
|
* f.close();
|
||
|
* ```
|
||
|
*
|
||
|
* Iterator uses an internal buffer of fixed size for efficiency; it returns
|
||
|
* 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.
|
||
|
*/
|
||
|
export function* iterSync(
|
||
|
r: Deno.ReaderSync,
|
||
|
options?: {
|
||
|
bufSize?: number;
|
||
|
},
|
||
|
): IterableIterator<Uint8Array> {
|
||
|
const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
|
||
|
const b = new Uint8Array(bufSize);
|
||
|
while (true) {
|
||
|
const result = r.readSync(b);
|
||
|
if (result === null) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
yield b.subarray(0, result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Copies from `src` to `dst` until either EOF (`null`) is read from `src` or
|
||
|
* an error occurs. It resolves to the number of bytes copied or rejects with
|
||
|
* the first error encountered while copying.
|
||
|
*
|
||
|
* ```ts
|
||
|
* const source = await Deno.open("my_file.txt");
|
||
|
* const bytesCopied1 = await copy(source, Deno.stdout);
|
||
|
* const destination = await Deno.create("my_file_2.txt");
|
||
|
* const bytesCopied2 = await copy(source, destination);
|
||
|
* ```
|
||
|
*
|
||
|
* @param src The source to copy from
|
||
|
* @param dst The destination to copy to
|
||
|
* @param options Can be used to tune size of the buffer. Default size is 32kB
|
||
|
*/
|
||
|
export async function copy(
|
||
|
src: Deno.Reader,
|
||
|
dst: Deno.Writer,
|
||
|
options?: {
|
||
|
bufSize?: number;
|
||
|
},
|
||
|
): Promise<number> {
|
||
|
let n = 0;
|
||
|
const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE;
|
||
|
const b = new Uint8Array(bufSize);
|
||
|
let gotEOF = false;
|
||
|
while (gotEOF === false) {
|
||
|
const result = await src.read(b);
|
||
|
if (result === null) {
|
||
|
gotEOF = true;
|
||
|
} else {
|
||
|
let nwritten = 0;
|
||
|
while (nwritten < result) {
|
||
|
nwritten += await dst.write(b.subarray(nwritten, result));
|
||
|
}
|
||
|
n += nwritten;
|
||
|
}
|
||
|
}
|
||
|
return n;
|
||
|
}
|