@chickenjdk/byteutils
Version:
Some utilitys for working with binary data
213 lines (212 loc) • 12.4 kB
JavaScript
"use strict";
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 _writableStream_stream, _chunkingWritableStream_instances, _chunkingWritableStream_chunkSize, _chunkingWritableStream_stream, _chunkingWritableStream_buffer, _chunkingWritableStream_used, _chunkingWritableStream_flushFull;
Object.defineProperty(exports, "__esModule", { value: true });
exports.chunkingWritableStreamLE = exports.chunkingWritableStream = exports.writableStreamLE = exports.writableStream = void 0;
const common_1 = require("../common");
const writableBuffer_1 = require("../writableBuffer");
class writableStream extends writableBuffer_1.writableBufferBase {
/**
* Write binary encoded data to a stream.
* Writes each write to the stream immeditly, no matter the size of the data.
* For this reason, for high speed/bandwidth, it is recommended to use `chunkingWritableStream` to prevent memory issues with large writes and spamming the stream.
* This is accomplished by writing data with predictably sized chunks, regardless of how small or large the writes are.
* @param stream The stream to write to.
*/
constructor(stream) {
super();
_writableStream_stream.set(this, void 0);
__classPrivateFieldSet(this, _writableStream_stream, stream, "f");
}
get stream() {
return __classPrivateFieldGet(this, _writableStream_stream, "f");
}
writeUint8Array(value) {
return new Promise((resolve, reject) => {
__classPrivateFieldGet(this, _writableStream_stream, "f").write(value, (err) => {
if (err) {
reject(err);
}
else {
resolve();
}
});
});
}
writeUint8ArrayBackwards(value) {
return this.writeUint8Array(value.slice(0).reverse());
}
writeArray(value) {
return this.writeUint8Array(Uint8Array.from(value));
}
writeArrayBackwards(value) {
// writeUint8ArrayBackwards clones the input to prevent its mutation but we already clone it via Uint8Array.from so we can just reverse it directly
return this.writeUint8Array(Uint8Array.from(value).reverse());
}
push(value) {
return new Promise((resolve, reject) => {
__classPrivateFieldGet(this, _writableStream_stream, "f").write(Uint8Array.of(value), (err) => {
if (err) {
reject(err);
}
else {
resolve();
}
});
});
}
}
exports.writableStream = writableStream;
_writableStream_stream = new WeakMap();
exports.writableStreamLE = (0, common_1.addDefaultEndianness)(writableStream, true);
class chunkingWritableStream extends writableBuffer_1.writableBufferBase {
/**
* The stream we are writing to.
* @returns TThe stream we are writing to.
*/
get stream() {
return __classPrivateFieldGet(this, _chunkingWritableStream_stream, "f");
}
/**
* The size of the chunks to write to the stream.
* If you need to change it, please use the `setChunkSize` method.
* @returns The size of the chunks to write to the stream.
* @default 2000
*/
get chunkSize() {
return __classPrivateFieldGet(this, _chunkingWritableStream_chunkSize, "f");
}
/**
* Change the chunk size of the stream.
* This is async because it may need to flush the current buffer if the new chunk size is smaller than the current used size.
* @param value The new chunk size to set.
*/
async setChunkSize(value) {
__classPrivateFieldSet(this, _chunkingWritableStream_chunkSize, value, "f");
if (__classPrivateFieldGet(this, _chunkingWritableStream_used, "f") < value) {
// If the new chunk size is larger, we can just copy the old buffer to the new one
const oldBuffer = __classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f");
__classPrivateFieldSet(this, _chunkingWritableStream_buffer, new Uint8Array(value), "f");
__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").set(oldBuffer.subarray(0, __classPrivateFieldGet(this, _chunkingWritableStream_used, "f")), 0);
}
else if (__classPrivateFieldGet(this, _chunkingWritableStream_used, "f") > value) {
// Not enough space in the buffer, so we need to flush it
// This will do one last write in the old chunk size, but who cares?
await this.flush();
__classPrivateFieldSet(this, _chunkingWritableStream_buffer, new Uint8Array(__classPrivateFieldGet(this, _chunkingWritableStream_chunkSize, "f")), "f");
}
}
/**
* Write to the stream in predictable sized chunks.
* This is useful for high speed/bandwidth writes to a stream, as it prevents memory issues with large writes and spamming the stream.
* It accomplishes this by writing data with predictably sized chunks, regardless of how small or large the writes are.
* If you need the data written immediately, you can use the `flush` method to write the current buffer to the stream.
* If you need each write to be written immediately, use `writableStream` instead.
* @param stream The stream to write to.
* @param chunkSize The size of the chunks to write to the stream.
*/
constructor(stream, chunkSize = 2000) {
super();
_chunkingWritableStream_instances.add(this);
_chunkingWritableStream_chunkSize.set(this, void 0);
_chunkingWritableStream_stream.set(this, void 0);
// Always get the buffer's length to allow safely changing chunkSIze
_chunkingWritableStream_buffer.set(this, void 0);
_chunkingWritableStream_used.set(this, 0);
__classPrivateFieldSet(this, _chunkingWritableStream_stream, stream, "f");
__classPrivateFieldSet(this, _chunkingWritableStream_chunkSize, chunkSize, "f");
__classPrivateFieldSet(this, _chunkingWritableStream_buffer, new Uint8Array(chunkSize), "f");
}
/**
* Flush the buffer to the stream.
* If the buffer is empty, it resolves immediately.
* If the buffer is not empty, it writes the used section of the buffer to the stream and resets the buffer.
* This is useful for ensuring that all data is sent to the stream before closing it or performing other operations.
* @returns A promise that resolves when the buffer is flushed.
*/
flush() {
if (__classPrivateFieldGet(this, _chunkingWritableStream_used, "f") === 0) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
__classPrivateFieldGet(this, _chunkingWritableStream_stream, "f").write(__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").subarray(0, __classPrivateFieldGet(this, _chunkingWritableStream_used, "f")), (err) => {
__classPrivateFieldSet(this, _chunkingWritableStream_used, 0, "f");
__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").fill(0); // Reset the buffer to zeroes
if (err) {
reject(err);
}
else {
resolve();
}
});
});
}
async push(value) {
var _a, _b;
if (__classPrivateFieldGet(this, _chunkingWritableStream_used, "f") === __classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").length) {
await __classPrivateFieldGet(this, _chunkingWritableStream_instances, "m", _chunkingWritableStream_flushFull).call(this);
}
__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f")[__classPrivateFieldSet(this, _chunkingWritableStream_used, (_b = __classPrivateFieldGet(this, _chunkingWritableStream_used, "f"), _a = _b++, _b), "f"), _a] = value;
}
async writeUint8Array(value) {
let bytesLeft = value.length;
let index = 0;
while (bytesLeft > 0) {
if (__classPrivateFieldGet(this, _chunkingWritableStream_used, "f") === __classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").length) {
await __classPrivateFieldGet(this, _chunkingWritableStream_instances, "m", _chunkingWritableStream_flushFull).call(this);
}
const bytesToWrite = Math.min(bytesLeft, __classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").length - __classPrivateFieldGet(this, _chunkingWritableStream_used, "f"));
__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").set(value.subarray(index, index + bytesToWrite), __classPrivateFieldGet(this, _chunkingWritableStream_used, "f"));
__classPrivateFieldSet(this, _chunkingWritableStream_used, __classPrivateFieldGet(this, _chunkingWritableStream_used, "f") + bytesToWrite, "f");
index += bytesToWrite;
bytesLeft -= bytesToWrite;
}
}
writeUint8ArrayBackwards(value) {
// Don't mutate the origional value
return this.writeUint8Array(value.slice(0).reverse());
}
async writeArray(value) {
let bytesLeft = value.length;
let index = 0;
while (bytesLeft > 0) {
if (__classPrivateFieldGet(this, _chunkingWritableStream_used, "f") === __classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").length) {
await __classPrivateFieldGet(this, _chunkingWritableStream_instances, "m", _chunkingWritableStream_flushFull).call(this);
}
const bytesToWrite = Math.min(bytesLeft, __classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").length - __classPrivateFieldGet(this, _chunkingWritableStream_used, "f"));
__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").set(value.slice(index, index + bytesToWrite), __classPrivateFieldGet(this, _chunkingWritableStream_used, "f"));
__classPrivateFieldSet(this, _chunkingWritableStream_used, __classPrivateFieldGet(this, _chunkingWritableStream_used, "f") + bytesToWrite, "f");
index += bytesToWrite;
bytesLeft -= bytesToWrite;
}
}
writeArrayBackwards(value) {
return this.writeArray(value.slice(0).reverse());
}
}
exports.chunkingWritableStream = chunkingWritableStream;
_chunkingWritableStream_chunkSize = new WeakMap(), _chunkingWritableStream_stream = new WeakMap(), _chunkingWritableStream_buffer = new WeakMap(), _chunkingWritableStream_used = new WeakMap(), _chunkingWritableStream_instances = new WeakSet(), _chunkingWritableStream_flushFull = function _chunkingWritableStream_flushFull() {
return new Promise((resolve, reject) => {
__classPrivateFieldGet(this, _chunkingWritableStream_stream, "f").write(__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f"), (err) => {
__classPrivateFieldSet(this, _chunkingWritableStream_used, 0, "f");
__classPrivateFieldGet(this, _chunkingWritableStream_buffer, "f").fill(0);
if (err) {
reject(err);
}
else {
resolve();
}
});
});
};
exports.chunkingWritableStreamLE = (0, common_1.addDefaultEndianness)(chunkingWritableStream, true);