/* eslint-disable @typescript-eslint/no-explicit-any */ import { assertBufferLength, isObjectLike } from "./utils"; import { bytify } from "./bytes"; export interface Codec< Packed, Unpacked, Packable = Unpacked, Unpackable = Packed > { pack: (packable: Packable) => Packed; unpack: (unpackable: Unpackable) => Unpacked; } export type AnyCodec = Codec; export type PackResult = T extends Codec< infer Packed, any, any, any > ? Packed : never; export type PackParam = T extends Codec< any, any, infer Packable, any > ? Packable : never; export type UnpackResult = T extends Codec< any, infer Unpacked, any, any > ? Unpacked : never; export type UnpackParam = T extends Codec< any, any, any, infer Unpackable > ? Unpackable : never; export type Uint8ArrayCodec = Codec< Uint8Array, Unpacked, Packable >; export type BytesLike = ArrayLike | ArrayBuffer | string; export type BytesCodec = Codec< Uint8Array, Unpacked, Packable, BytesLike >; /** * Create a codec to deal with bytes-like data. * @param codec */ export function createBytesCodec( codec: Uint8ArrayCodec ): BytesCodec { return { pack: (unpacked) => codec.pack(unpacked), unpack: (bytesLike) => codec.unpack(bytify(bytesLike)), }; } export type Fixed = { readonly __isFixedCodec__: true; readonly byteLength: number; }; export type FixedBytesCodec = BytesCodec< Unpacked, Packable > & Fixed; export function isFixedCodec( codec: BytesCodec ): codec is FixedBytesCodec { return isObjectLike(codec) && !!codec.__isFixedCodec__; } export function createFixedBytesCodec( codec: Uint8ArrayCodec & { byteLength: number } ): FixedBytesCodec { const byteLength = codec.byteLength; return { __isFixedCodec__: true, byteLength, ...createBytesCodec({ pack: (u) => { const packed = codec.pack(u); assertBufferLength(packed, byteLength); return packed; }, unpack: (buf) => { assertBufferLength(buf, byteLength); return codec.unpack(buf); }, }), }; }