{% 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( 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( readFunc: (sink: Sink) => T ): (sink: Sink) => T | undefined { return (sink: Sink) => { const some = readBool(sink); if (!some) { return undefined; } return readFunc(sink); }; } function writeSeq( writeFunc: (value: T, sink: Sink) => Sink ): (value: Array, sink: Sink) => Sink { return (value: Array, sink: Sink) => { writeU64(BigInt(value.length), sink); for (const each of value) { writeFunc(each, sink); } return sink; }; } function readSeq(readFunc: (sink: Sink) => T): (sink: Sink) => Array { 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 & { BYTES_PER_ELEMENT: number; readonly length: number; readonly buffer: ArrayBuffer; readonly byteLength: number; readonly byteOffset: number; }; type TypedArrayConstructor = { new (buffer: ArrayBuffer, offset?: number, length?: number): T; BYTES_PER_ELEMENT: number; }; function writeTypedArray(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( array_type: TypedArrayConstructor ): (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( writeKeyFunc: (value: TK, sink: Sink) => Sink, writeValueFunc: (value: TV, sink: Sink) => Sink ): (value: Map, sink: Sink) => Sink { return (value: Map, sink: Sink) => { writeU64(BigInt(value.size), sink); value.forEach((v, k) => { writeKeyFunc(k, sink); writeValueFunc(v, sink); }); return sink; }; } function readMap( readKeyFunc: (sink: Sink) => TK, readValueFunc: (sink: Sink) => TV ): (sink: Sink) => Map { 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( ...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( ...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; }; }