@ickb/utils
Version:
General utilities built on top of CCC
83 lines • 3.05 kB
JavaScript
import { mol, ccc } from "@ckb-ccc/core";
export const CheckedInt32LE = mol.Codec.from({
byteLength: 4,
encode: (numLike) => {
const num = Number(numLike);
if (num < -2147483648 || num > 2147483647) {
throw Error("NumLike out of int32 bounds");
}
const encoded = new Uint8Array(4);
new DataView(encoded.buffer).setInt32(0, num, true);
return encoded;
},
decode: (bytesLike) => {
const bytes = ccc.bytesFrom(bytesLike);
return new DataView(bytes.buffer).getInt32(0, true);
},
});
export function union(codecLayout, fields) {
const keys = Object.keys(codecLayout);
const values = Object.values(codecLayout);
let byteLength = values[0]?.byteLength;
for (const { byteLength: l } of values.slice(1)) {
if (l === undefined || l !== byteLength) {
byteLength = undefined;
break;
}
}
if (byteLength !== undefined) {
byteLength += 4;
}
return mol.Codec.from({
byteLength,
encode({ type, value }) {
const typeStr = type.toString();
const codec = codecLayout[typeStr];
if (!codec) {
throw new Error(`union: invalid type, expected ${keys.toString()}, but got ${typeStr}`);
}
const fieldId = fields ? (fields[typeStr] ?? -1) : keys.indexOf(typeStr);
if (fieldId < 0) {
throw new Error(`union: invalid field id ${fieldId} of ${typeStr}`);
}
const header = uint32To(fieldId);
try {
const body = codec.encode(value);
return ccc.bytesConcat(header, body);
}
catch (e) {
throw new Error(`union.(${typeStr})(${e?.toString()})`);
}
},
decode(buffer) {
const value = ccc.bytesFrom(buffer);
const fieldIndex = uint32From(value.slice(0, 4));
const keys = Object.keys(codecLayout);
const field = (() => {
if (!fields) {
return keys[fieldIndex];
}
const entry = Object.entries(fields).find(([, id]) => id === fieldIndex);
return entry?.[0];
})();
if (!field) {
if (!fields) {
throw new Error(`union: unknown union field index ${fieldIndex}, only ${keys.toString()} are allowed`);
}
const fieldKeys = Object.keys(fields);
throw new Error(`union: unknown union field index ${fieldIndex}, only ${fieldKeys.toString()} and ${keys.toString()} are allowed`);
}
return {
type: field,
value: codecLayout[field].decode(value.slice(4)),
};
},
});
}
function uint32To(numLike) {
return ccc.numToBytes(numLike, 4);
}
function uint32From(bytesLike) {
return Number(ccc.numFromBytes(bytesLike));
}
//# sourceMappingURL=codec.js.map