@ckb-lumos/codec
Version:
Make your own molecule binding in JavaScript(TypeScript)
133 lines (112 loc) • 3.34 kB
text/typescript
import { BI, BIish } from "@ckb-lumos/bi";
import { createFixedBytesCodec, FixedBytesCodec } from "../base";
import { CodecBaseParseError } from "../error";
export { BI, BIish };
function assertNumberRange(
value: BIish,
min: BIish,
max: BIish,
typeName: string
): void {
value = BI.from(value);
if (value.lt(min) || value.gt(max)) {
throw new CodecBaseParseError(
`Value must be between ${min.toString()} and ${max.toString()}, but got ${value.toString()}`,
typeName
);
}
}
function createUintNumberCodec(
byteLength: number,
littleEndian = false
): FixedBytesCodec<number, BIish> {
const codec = createUintBICodec(byteLength, littleEndian);
return {
__isFixedCodec__: true,
byteLength,
pack: (packable) => codec.pack(packable),
unpack: (unpackable) => codec.unpack(unpackable).toNumber(),
};
}
const createUintBICodec = (byteLength: number, littleEndian = false) => {
const max = BI.from(1)
.shl(byteLength * 8)
.sub(1);
return createFixedBytesCodec<BI, BIish>({
byteLength,
pack(biIsh) {
let endianType: "LE" | "BE" | "" = littleEndian ? "LE" : "BE";
if (byteLength <= 1) {
endianType = "";
}
const typeName = `Uint${byteLength * 8}${endianType}`;
if (typeof biIsh === "number" && !Number.isSafeInteger(biIsh)) {
throw new CodecBaseParseError(
`${biIsh} is not a safe integer`,
typeName
);
}
let num = BI.from(biIsh);
assertNumberRange(num, 0, max, typeName);
const result = new DataView(new ArrayBuffer(byteLength));
for (let i = 0; i < byteLength; i++) {
if (littleEndian) {
result.setUint8(i, num.and(0xff).toNumber());
} else {
result.setUint8(byteLength - i - 1, num.and(0xff).toNumber());
}
num = num.shr(8);
}
return new Uint8Array(result.buffer);
},
unpack: (buf) => {
const view = new DataView(Uint8Array.from(buf).buffer);
let result = BI.from(0);
for (let i = 0; i < byteLength; i++) {
if (littleEndian) {
result = result.or(BI.from(view.getUint8(i)).shl(i * 8));
} else {
result = result.shl(8).or(view.getUint8(i));
}
}
return result;
},
});
};
export const Uint8 = createUintNumberCodec(1);
export const Uint16LE = createUintNumberCodec(2, true);
export const Uint16BE = createUintNumberCodec(2);
/**
* @alias Uint16LE
*/
export const Uint16 = Uint16LE;
export const Uint32LE = createUintNumberCodec(4, true);
export const Uint32BE = createUintNumberCodec(4);
/**
* @alias Uint32LE
*/
export const Uint32 = Uint32LE;
export const Uint64LE = createUintBICodec(8, true);
export const Uint64BE = createUintBICodec(8);
/**
* @alias Uint64LE
*/
export const Uint64 = Uint64LE;
export const Uint128LE = createUintBICodec(16, true);
export const Uint128BE = createUintBICodec(16);
/**
* @alias Uint128LE
*/
export const Uint128 = Uint128LE;
export const Uint256LE = createUintBICodec(32, true);
export const Uint256BE = createUintBICodec(32);
/**
* @alias Uint256LE
*/
export const Uint256 = Uint256LE;
export const Uint512LE = createUintBICodec(64, true);
export const Uint512BE = createUintBICodec(64);
/**
* @alias Uint512LE
*/
export const Uint512 = Uint512LE;