@mieweb/wikigdrive
Version:
Google Drive to MarkDown synchronization
489 lines (488 loc) • 19 kB
JavaScript
// Copyright 2018-2025 the Deno authors. MIT license.
// This module is browser compatible.
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Buffer_instances, _Buffer_buf, _Buffer_off, _Buffer_tryGrowByReslice, _Buffer_reslice, _Buffer_grow;
import { copy } from "../../bytes/1.0.6/copy.js";
// MIN_READ is the minimum ArrayBuffer size passed to a read call by
// buffer.ReadFrom. As long as the Buffer has at least MIN_READ bytes beyond
// what is required to hold the contents of r, readFrom() will not grow the
// underlying buffer.
const MIN_READ = 32 * 1024;
const MAX_SIZE = 2 ** 32 - 2;
/**
* 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
* necessary.
*
* Buffer is NOT the same thing as Node's Buffer. Node's Buffer was created in
* 2009 before JavaScript had the concept of ArrayBuffers. It's simply a
* non-standard ArrayBuffer.
*
* ArrayBuffer is a fixed memory allocation. Buffer is implemented on top of
* 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 {
/**
* 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) {
_Buffer_instances.add(this);
_Buffer_buf.set(this, void 0); // contents are the bytes buf[off : len(buf)]
_Buffer_off.set(this, 0); // read at buf[off], write at buf[buf.byteLength]
if (ab === undefined) {
__classPrivateFieldSet(this, _Buffer_buf, new Uint8Array(0), "f");
}
else if (ab instanceof SharedArrayBuffer) {
// Note: This is necessary to avoid type error
__classPrivateFieldSet(this, _Buffer_buf, new Uint8Array(ab), "f");
}
else {
__classPrivateFieldSet(this, _Buffer_buf, new Uint8Array(ab), "f");
}
}
/**
* 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.
*
* @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 }) {
if (options.copy === false)
return __classPrivateFieldGet(this, _Buffer_buf, "f").subarray(__classPrivateFieldGet(this, _Buffer_off, "f"));
return __classPrivateFieldGet(this, _Buffer_buf, "f").slice(__classPrivateFieldGet(this, _Buffer_off, "f"));
}
/**
* 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() {
return __classPrivateFieldGet(this, _Buffer_buf, "f").byteLength <= __classPrivateFieldGet(this, _Buffer_off, "f");
}
/**
* 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() {
return __classPrivateFieldGet(this, _Buffer_buf, "f").byteLength - __classPrivateFieldGet(this, _Buffer_off, "f");
}
/**
* 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() {
return __classPrivateFieldGet(this, _Buffer_buf, "f").buffer.byteLength;
}
/**
* 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.
*
* @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) {
if (n === 0) {
this.reset();
return;
}
if (n < 0 || n > this.length) {
throw new Error("Buffer truncation out of range");
}
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, __classPrivateFieldGet(this, _Buffer_off, "f") + 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() {
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, 0);
__classPrivateFieldSet(this, _Buffer_off, 0, "f");
}
/**
* 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`).
*
* @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) {
if (this.empty()) {
// Buffer is empty, reset to recover space.
this.reset();
if (p.byteLength === 0) {
// this edge case is tested in 'bufferReadEmptyAtEOF' test
return 0;
}
return null;
}
const nread = copy(__classPrivateFieldGet(this, _Buffer_buf, "f").subarray(__classPrivateFieldGet(this, _Buffer_off, "f")), p);
__classPrivateFieldSet(this, _Buffer_off, __classPrivateFieldGet(this, _Buffer_off, "f") + nread, "f");
return nread;
}
/**
* 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) {
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) {
const m = __classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_grow).call(this, p.byteLength);
return copy(p, __classPrivateFieldGet(this, _Buffer_buf, "f"), m);
}
/**
* 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) {
const n = this.writeSync(p);
return Promise.resolve(n);
}
/** Grows the buffer's capacity, if necessary, to guarantee space for
* another `n` bytes. After `.grow(n)`, at least `n` bytes can be written to
* the buffer without another allocation. If `n` is negative, `.grow()` will
* 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}.
*
* @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) {
if (n < 0) {
throw new Error("Buffer growth cannot be negative");
}
const m = __classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_grow).call(this, n);
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, m);
}
/**
* 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}.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* const r = new Buffer(new TextEncoder().encode("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) {
let n = 0;
const tmp = new Uint8Array(MIN_READ);
while (true) {
const shouldGrow = this.capacity - this.length < MIN_READ;
// read into tmp buffer if there's not enough room
// otherwise read directly into the internal buffer
const buf = shouldGrow
? tmp
: new Uint8Array(__classPrivateFieldGet(this, _Buffer_buf, "f").buffer, this.length);
const nread = await r.read(buf);
if (nread === null) {
return n;
}
// write will grow if needed
if (shouldGrow)
this.writeSync(buf.subarray(0, nread));
else
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, this.length + nread);
n += nread;
}
}
/** Reads data from `r` until EOF (`null`) and appends it to the buffer,
* growing the buffer as needed. It returns the number of bytes read. If the
* buffer becomes too large, `.readFromSync()` will throw an error.
*
* Based on Go Lang's
* {@link https://golang.org/pkg/bytes/#Buffer.ReadFrom | Buffer.ReadFrom}.
*
* @example Usage
* ```ts
* import { Buffer } from "@std/io/buffer";
* import { assertEquals } from "@std/assert/equals";
*
* const buf = new Buffer();
* const r = new Buffer(new TextEncoder().encode("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) {
let n = 0;
const tmp = new Uint8Array(MIN_READ);
while (true) {
const shouldGrow = this.capacity - this.length < MIN_READ;
// read into tmp buffer if there's not enough room
// otherwise read directly into the internal buffer
const buf = shouldGrow
? tmp
: new Uint8Array(__classPrivateFieldGet(this, _Buffer_buf, "f").buffer, this.length);
const nread = r.readSync(buf);
if (nread === null) {
return n;
}
// write will grow if needed
if (shouldGrow)
this.writeSync(buf.subarray(0, nread));
else
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, this.length + nread);
n += nread;
}
}
}
_Buffer_buf = new WeakMap(), _Buffer_off = new WeakMap(), _Buffer_instances = new WeakSet(), _Buffer_tryGrowByReslice = function _Buffer_tryGrowByReslice(n) {
const l = __classPrivateFieldGet(this, _Buffer_buf, "f").byteLength;
if (n <= this.capacity - l) {
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, l + n);
return l;
}
return -1;
}, _Buffer_reslice = function _Buffer_reslice(len) {
if (len > __classPrivateFieldGet(this, _Buffer_buf, "f").buffer.byteLength) {
throw new RangeError("Length is greater than buffer capacity");
}
__classPrivateFieldSet(this, _Buffer_buf, new Uint8Array(__classPrivateFieldGet(this, _Buffer_buf, "f").buffer, 0, len), "f");
}, _Buffer_grow = function _Buffer_grow(n) {
const m = this.length;
// If buffer is empty, reset to recover space.
if (m === 0 && __classPrivateFieldGet(this, _Buffer_off, "f") !== 0) {
this.reset();
}
// Fast: Try to grow by means of a reslice.
const i = __classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_tryGrowByReslice).call(this, n);
if (i >= 0) {
return i;
}
const c = this.capacity;
if (n <= Math.floor(c / 2) - m) {
// We can slide things down instead of allocating a new
// ArrayBuffer. We only need m+n <= c to slide, but
// we instead let capacity get twice as large so we
// don't spend all our time copying.
copy(__classPrivateFieldGet(this, _Buffer_buf, "f").subarray(__classPrivateFieldGet(this, _Buffer_off, "f")), __classPrivateFieldGet(this, _Buffer_buf, "f"));
}
else if (c + n > MAX_SIZE) {
throw new Error(`The buffer cannot be grown beyond the maximum size of "${MAX_SIZE}"`);
}
else {
// Not enough space anywhere, we need to allocate.
const buf = new Uint8Array(Math.min(2 * c + n, MAX_SIZE));
copy(__classPrivateFieldGet(this, _Buffer_buf, "f").subarray(__classPrivateFieldGet(this, _Buffer_off, "f")), buf);
__classPrivateFieldSet(this, _Buffer_buf, buf, "f");
}
// Restore this.#off and len(this.#buf).
__classPrivateFieldSet(this, _Buffer_off, 0, "f");
__classPrivateFieldGet(this, _Buffer_instances, "m", _Buffer_reslice).call(this, Math.min(m + n, MAX_SIZE));
return m;
};