@yubing744/rooch-sdk
Version:
177 lines (140 loc) • 5.22 kB
text/typescript
/**
* Copyright (c) Facebook, Inc. and its affiliates
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
import { Serializer } from './serializer'
import * as util from "@kayahr/text-encoding";
export abstract class BinarySerializer implements Serializer {
private static readonly BIG_32: bigint = BigInt(32);
private static readonly BIG_64: bigint = BigInt(64);
private static readonly BIG_32Fs: bigint = BigInt("4294967295");
private static readonly BIG_64Fs: bigint = BigInt("18446744073709551615");
private static readonly textEncoder = typeof window === "undefined"
? new util.TextEncoder()
: new TextEncoder();
private buffer: ArrayBuffer;
private offset: number;
constructor() {
this.buffer = new ArrayBuffer(64);
this.offset = 0;
}
private ensureBufferWillHandleSize(bytes: number) {
while (this.buffer.byteLength < this.offset + bytes) {
const newBuffer = new ArrayBuffer(this.buffer.byteLength * 2);
new Uint8Array(newBuffer).set(new Uint8Array(this.buffer));
this.buffer = newBuffer;
}
}
protected serialize(values: Uint8Array) {
this.ensureBufferWillHandleSize(values.length);
new Uint8Array(this.buffer, this.offset).set(values);
this.offset += values.length;
}
abstract serializeLen(value: number): void;
abstract serializeVariantIndex(value: number): void;
abstract sortMapEntries(offsets: number[]): void;
public serializeStr(value: string): void {
this.serializeBytes(BinarySerializer.textEncoder.encode(value));
}
public serializeBytes(value: Uint8Array): void {
this.serializeLen(value.length);
this.serialize(value);
}
public serializeBool(value: boolean): void {
const byteValue = value ? 1 : 0;
this.serialize(new Uint8Array([byteValue]));
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/explicit-module-boundary-types
public serializeUnit(_value: null): void {
return;
}
private serializeWithFunction(
fn: (byteOffset: number, value: number, littleEndian: boolean) => void,
bytesLength: number,
value: number,
) {
this.ensureBufferWillHandleSize(bytesLength);
const dv = new DataView(this.buffer, this.offset);
fn.apply(dv, [0, value, true]);
this.offset += bytesLength;
}
public serializeU8(value: number): void {
this.serialize(new Uint8Array([value]));
}
public serializeU16(value: number): void {
this.serializeWithFunction(DataView.prototype.setUint16, 2, value);
}
public serializeU32(value: number): void {
this.serializeWithFunction(DataView.prototype.setUint32, 4, value);
}
public serializeU64(value: BigInt | number): void {
const low = BigInt(value.toString()) & BinarySerializer.BIG_32Fs;
const high = BigInt(value.toString()) >> BinarySerializer.BIG_32;
// write little endian number
this.serializeU32(Number(low));
this.serializeU32(Number(high));
}
public serializeU128(value: BigInt | number): void {
const low = BigInt(value.toString()) & BinarySerializer.BIG_64Fs;
const high = BigInt(value.toString()) >> BinarySerializer.BIG_64;
// write little endian number
this.serializeU64(low);
this.serializeU64(high);
}
public serializeI8(value: number): void {
const bytes = 1;
this.ensureBufferWillHandleSize(bytes);
new DataView(this.buffer, this.offset).setInt8(0, value);
this.offset += bytes;
}
public serializeI16(value: number): void {
const bytes = 2;
this.ensureBufferWillHandleSize(bytes);
new DataView(this.buffer, this.offset).setInt16(0, value, true);
this.offset += bytes;
}
public serializeI32(value: number): void {
const bytes = 4;
this.ensureBufferWillHandleSize(bytes);
new DataView(this.buffer, this.offset).setInt32(0, value, true);
this.offset += bytes;
}
public serializeI64(value: bigint | number): void {
const low = BigInt(value) & BinarySerializer.BIG_32Fs;
const high = BigInt(value) >> BinarySerializer.BIG_32;
// write little endian number
this.serializeI32(Number(low));
this.serializeI32(Number(high));
}
public serializeI128(value: bigint | number): void {
const low = BigInt(value) & BinarySerializer.BIG_64Fs;
const high = BigInt(value) >> BinarySerializer.BIG_64;
// write little endian number
this.serializeI64(low);
this.serializeI64(high);
}
public serializeOptionTag(value: boolean): void {
this.serializeBool(value);
}
public getBufferOffset(): number {
return this.offset;
}
public getBytes(): Uint8Array {
return new Uint8Array(this.buffer).slice(0, this.offset);
}
public serializeChar(_value: string): void {
throw new Error("Method serializeChar not implemented.");
}
public serializeF32(value: number): void {
const bytes = 4;
this.ensureBufferWillHandleSize(bytes);
new DataView(this.buffer, this.offset).setFloat32(0, value, true);
this.offset += bytes;
}
public serializeF64(value: number): void {
const bytes = 8;
this.ensureBufferWillHandleSize(bytes);
new DataView(this.buffer, this.offset).setFloat64(0, value, true);
this.offset += bytes;
}
}