UNPKG

@ickb/utils

Version:

General utilities built on top of CCC

83 lines 3.05 kB
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