{% if support_buffer %}
type SinkOrBuf = Sink | Buffer | ArrayBuffer | Uint8Array;
{% else %}
type SinkOrBuf = Sink | ArrayBuffer | Uint8Array;
{% endif %}
export class Sink {
public view: DataView;
public position: number;
private constructor(input: ArrayBuffer) {
this.view = new DataView(input);
this.position = 0;
}
public reserve(extra: number): void {
if (this.position + extra <= this.view.buffer.byteLength) {
return;
}
const newBuffer = new ArrayBuffer(
(this.view.buffer.byteLength + extra) * 2
);
new Uint8Array(newBuffer).set(new Uint8Array(this.view.buffer));
this.view = new DataView(newBuffer);
}
public static create(input?: SinkOrBuf): Sink {
if (input == undefined) {
return new Sink(new ArrayBuffer(0));
}
if (input instanceof Sink) {
return input;
}
{% if support_buffer %}
if (input instanceof Buffer) {
return new Sink(
input.buffer.slice(
input.byteOffset,
input.byteOffset + input.byteLength
)
);
}
{%- endif %}
if (input instanceof ArrayBuffer) {
return new Sink(input);
}
if (input instanceof Uint8Array) {
return new Sink(input.buffer);
}
throw new Error(
{%- if support_buffer %}
`'input' was of incorrect type. Expected 'Sink | Buffer | ArrayBuffer | Uint8Array'`
{%- else %}
`'input' was of incorrect type. Expected 'Sink | ArrayBuffer | Uint8Array'`
{%- endif %}
);
}
public getUint8Array(): Uint8Array {
return new Uint8Array(this.view.buffer.slice(0, this.position));
}
{% if support_buffer %}
public getBuffer(): Buffer {
return Buffer.from(this.view.buffer, 0, this.position);
}
{%- endif %}
}
const BIG_32 = BigInt(32);
const BIG_64 = BigInt(64);
const BIG_32Fs = BigInt('4294967295');
const BIG_64Fs = BigInt('18446744073709551615');
const textEncoder: TextEncoder = new TextEncoder();
const textDecoder: TextDecoder = new TextDecoder();
function readU8(sink: Sink): number {
const value = sink.view.getUint8(sink.position);
sink.position += 1;
return value;
}
function writeU8(value: number, sink: Sink): Sink {
sink.reserve(1);
sink.view.setUint8(sink.position, value);
sink.position += 1;
return sink;
}
function readI8(sink: Sink): number {
const value = sink.view.getInt8(sink.position);
sink.position += 1;
return value;
}
function writeI8(value: number, sink: Sink): Sink {
sink.reserve(1);
sink.view.setInt8(sink.position, value);
sink.position += 1;
return sink;
}
function readU16(sink: Sink): number {
const value = sink.view.getUint16(sink.position, true);
sink.position += 2;
return value;
}
function writeU16(value: number, sink: Sink): Sink {
sink.reserve(2);
sink.view.setUint16(sink.position, value, true);
sink.position += 2;
return sink;
}
function readI16(sink: Sink): number {
const value = sink.view.getInt16(sink.position, true);
sink.position += 2;
return value;
}
function writeI16(value: number, sink: Sink): Sink {
sink.reserve(2);
sink.view.setInt16(sink.position, value, true);
sink.position += 2;
return sink;
}
function readU32(sink: Sink): number {
const value = sink.view.getUint32(sink.position, true);
sink.position += 4;
return value;
}
function writeU32(value: number, sink: Sink): Sink {
sink.reserve(4);
sink.view.setUint32(sink.position, value, true);
sink.position += 4;
return sink;
}
function readI32(sink: Sink): number {
const value = sink.view.getInt32(sink.position, true);
sink.position += 4;
return value;
}
function writeI32(value: number, sink: Sink): Sink {
sink.reserve(4);
sink.view.setInt32(sink.position, value, true);
sink.position += 4;
return sink;
}
function readF32(sink: Sink): number {
const value = sink.view.getFloat32(sink.position, true);
sink.position += 4;
return value;
}
function writeF32(value: number, sink: Sink): Sink {
sink.reserve(4);
sink.view.setFloat32(sink.position, value, true);
sink.position += 4;
return sink;
}
function readF64(sink: Sink): number {
const value = sink.view.getFloat64(sink.position, true);
sink.position += 8;
return value;
}
function writeF64(value: number, sink: Sink): Sink {
sink.reserve(8);
sink.view.setFloat64(sink.position, value, true);
sink.position += 8;
return sink;
}
function readU64(sink: Sink): bigint {
const high = readU32(sink);
const low = readU32(sink);
return (BigInt(low) << BIG_32) | BigInt(high);
}
function writeU64(value: bigint, sink: Sink): Sink {
const low = value & BIG_32Fs;
const high = value >> BIG_32;
writeU32(Number(low), sink);
writeU32(Number(high), sink);
return sink;
}
function readI64(sink: Sink): bigint {
const high = readI32(sink);
const low = readI32(sink);
return (BigInt(low) << BIG_32) | BigInt(high);
}
function writeI64(value: bigint, sink: Sink): Sink {
const low = value & BIG_32Fs;
const high = value >> BIG_32;
writeI32(Number(low), sink);
writeI32(Number(high), sink);
return sink;
}
function readUSize(sink: Sink): bigint {
return readU64(sink);
}
function writeUSize(value: bigint, sink: Sink): Sink {
writeU64(value, sink);
return sink;
}
function readISize(sink: Sink): bigint {
return readI64(sink);
}
function writeISize(value: bigint, sink: Sink): Sink {
writeI64(value, sink);
return sink;
}
function readU128(sink: Sink): bigint {
const high = readU64(sink);
const low = readU64(sink);
return (low << BIG_64) | high;
}
function writeU128(value: bigint, sink: Sink): Sink {
const low = value & BIG_64Fs;
const high = value >> BIG_64;
writeU64(low, sink);
writeU64(high, sink);
return sink;
}
function readI128(sink: Sink): bigint {
const high = readI64(sink);
const low = readI64(sink);
return (low << BIG_64) | high;
}
function writeI128(value: bigint, sink: Sink): Sink {
const low = value & BIG_64Fs;
const high = value >> BIG_64;
writeI64(low, sink);
writeI64(high, sink);
return sink;
}
function readBool(sink: Sink): boolean {
return readU8(sink) == 1;
}
function writeBool(value: boolean, sink: Sink): Sink {
writeU8(value ? 1 : 0, sink);
return sink;
}
function writeBytes(value: Uint8Array, sink: Sink): Sink {
sink.reserve(value.length + 1);
new Uint8Array(sink.view.buffer, sink.position).set(value);
sink.position += value.length;
return sink;
}
function readBytes(sink: Sink, length: number): Uint8Array {
const bytes = sink.view.buffer.slice(sink.position, sink.position + length);
sink.position += length;
return new Uint8Array(bytes);
}
function writeString(value: string, sink: Sink): Sink {
const bytes = textEncoder.encode(value);
writeU64(BigInt(bytes.length), sink);
writeBytes(bytes, sink);
return sink;
}
function readString(sink: Sink): string {
const length = readU64(sink);
const bytes = readBytes(sink, Number(length));
return textDecoder.decode(bytes);
}
function writeOption<T>(
writeFunc: (value: T, sink: Sink) => Sink
): (value: T | undefined, sink: Sink) => Sink {
return (value: T | undefined, sink: Sink) => {
writeBool(value != undefined, sink);
if (value != undefined) {
writeFunc(value, sink);
}
return sink;
};
}
function readOption<T>(
readFunc: (sink: Sink) => T
): (sink: Sink) => T | undefined {
return (sink: Sink) => {
const some = readBool(sink);
if (!some) {
return undefined;
}
return readFunc(sink);
};
}
function writeSeq<T>(
writeFunc: (value: T, sink: Sink) => Sink
): (value: Array<T>, sink: Sink) => Sink {
return (value: Array<T>, sink: Sink) => {
writeU64(BigInt(value.length), sink);
for (const each of value) {
writeFunc(each, sink);
}
return sink;
};
}
function readSeq<T>(readFunc: (sink: Sink) => T): (sink: Sink) => Array<T> {
return (sink: Sink) => {
const length = readU64(sink);
const output = new Array();
for (var i = 0; i < length; i++) {
output.push(readFunc(sink));
}
return output;
};
}
type TypedArray = ArrayLike<any> & {
BYTES_PER_ELEMENT: number;
readonly length: number;
readonly buffer: ArrayBuffer;
readonly byteLength: number;
readonly byteOffset: number;
};
type TypedArrayConstructor<T> = {
new (buffer: ArrayBuffer, offset?: number, length?: number): T;
BYTES_PER_ELEMENT: number;
};
function writeTypedArray<T extends TypedArray>(value: T, sink: Sink): Sink {
writeU64(BigInt(value.length), sink);
writeBytes(
new Uint8Array(value.buffer.slice(value.byteOffset, value.byteLength)),
sink
);
return sink;
}
function readTypedArray<T extends TypedArray>(
array_type: TypedArrayConstructor<T>
): (sink: Sink) => T {
return (sink: Sink) => {
const length = readU64(sink);
const bytes = readBytes(sink, Number(length) * array_type.BYTES_PER_ELEMENT);
return new array_type(bytes.buffer, 0, Number(length));
};
}
function writeMap<TK, TV>(
writeKeyFunc: (value: TK, sink: Sink) => Sink,
writeValueFunc: (value: TV, sink: Sink) => Sink
): (value: Map<TK, TV>, sink: Sink) => Sink {
return (value: Map<TK, TV>, sink: Sink) => {
writeU64(BigInt(value.size), sink);
value.forEach((v, k) => {
writeKeyFunc(k, sink);
writeValueFunc(v, sink);
});
return sink;
};
}
function readMap<TK, TV>(
readKeyFunc: (sink: Sink) => TK,
readValueFunc: (sink: Sink) => TV
): (sink: Sink) => Map<TK, TV> {
return (sink: Sink) => {
const length = readU64(sink);
const output = new Map();
for (var i = 0; i < length; i++) {
output.set(readKeyFunc(sink), readValueFunc(sink));
}
return output;
};
}
function writeTuple<T extends any[]>(
...writeFns: Array<(value: any, sink: Sink) => Sink>
): (value: T, sink: Sink) => Sink {
return (value: T, sink: Sink) => {
for (let i = 0; i < writeFns.length; i++) {
writeFns[i](value[i], sink);
}
return sink;
};
}
function readTuple<T extends any[]>(
...readFns: Array<(sink: Sink) => any>
): (sink: Sink) => T {
return (sink: Sink) => {
const out = new Array();
for (const readFn of readFns) {
out.push(readFn(sink));
}
return out as T;
};
}