import { type Coder as BaseCoder } from '@scure/base'; import type { TArg, TRet } from '@scure/base'; export type { TArg, TRet } from '@scure/base'; /** * Define complex binary structures using composable primitives. * Main ideas: * - Encode / decode can be chained, same as in `scure-base` * - A complex structure can be created from an array and struct of primitive types * - Strings / bytes are arrays with specific optimizations: we can just read bytes directly * without creating plain array first and reading each byte separately. * - Types are inferred from definition * @module * @example * Define a struct with numbers, strings, bytes, and nested arrays. * ```ts * import * as P from 'micro-packed'; * const s = P.struct({ * field1: P.U32BE, // 32-bit unsigned big-endian integer * field2: P.string(P.U8), // String with U8 length prefix * field3: P.bytes(32), // 32 bytes * field4: P.array(P.U16BE, P.struct({ // Array of structs with U16BE length * subField1: P.U64BE, // 64-bit unsigned big-endian integer * subField2: P.string(10) // 10-byte string * })) * }); * ``` */ /** * Shortcut to zero-length (empty) byte array. * Keep public Bytes typing, not TRet, so variables inferred from this * constant can later accept caller-owned Bytes backed by any ArrayBufferLike. */ export declare const EMPTY: Bytes; /** * Shortcut to one-element (element is 0) byte array. * Keep the same public Bytes typing rationale as EMPTY. */ export declare const NULL: Bytes; /** Checks if two Uint8Arrays are equal. Not constant-time. */ declare function equalBytes(a: TArg, b: TArg): boolean; declare const findBytes: (needle: TArg, data: TArg, pos?: number) => number | undefined; /** Checks if the given value is a Uint8Array. */ declare function isBytes(a: unknown): a is Bytes; /** * Concatenates multiple Uint8Arrays. * Engines limit functions to 65K+ arguments. * @param arrays Array of Uint8Array elements * @returns Concatenated Uint8Array */ declare function concatBytes(...arrays: TArg): TRet; /** * Checks if the provided value is object-like for option/schema bags. * This intentionally matches noble-curves and noble-hashes by using the * `[object Object]` tag instead of rejecting class/proxy/env objects by prototype; * stricter checks caused compatibility reports in proxied environments. * Array, Uint8Array and others are not plain objects. * @param obj - The value to be checked. */ declare function isPlainObject(obj: any): boolean; /** * Miscellaneous helpers reused by the coder internals and tests. * @example * Reuse a couple of byte helpers without pulling in the full namespace. * ```ts * import { utils } from 'micro-packed'; * const left = Uint8Array.of(1); * const right = Uint8Array.of(2); * utils.equalBytes(utils.concatBytes(left, right), Uint8Array.of(1, 2)); * ``` */ export declare const utils: TRet<{ equalBytes: typeof equalBytes; isBytes: typeof isBytes; isCoder: typeof isCoder; checkBounds: typeof checkBounds; concatBytes: typeof concatBytes; createView: (arr: TArg) => DataView; isPlainObject: typeof isPlainObject; }>; /** Byte-array alias used throughout the public API. */ export type Bytes = Uint8Array; /** Optional value helper used by conditional coders. */ export type Option = T | undefined; /** Coder encodes and decodes between two types. */ export interface Coder { /** * Encodes (converts) a decoded value into its serialized representation. * @param from - Value to encode. * @returns Encoded representation. */ encode(from: F): T; /** * Decodes (converts) a serialized value back into its decoded representation. * @param to - Encoded representation to decode. * @returns Decoded value. */ decode(to: T): F; } /** BytesCoder converts value between a type and a byte array. */ export interface BytesCoder extends Coder { /** Fixed-size hint in bytes, when known. */ size?: number; /** * Encodes a value into a byte array. * @param data - Value to encode. * @returns Encoded bytes. */ encode: (data: T) => Bytes; /** * Decodes a byte array into a value. * @param data - Bytes to decode. * @param opts - Reader options used while decoding. See {@link ReaderOpts}. * @returns Decoded value. */ decode: (data: Bytes, opts?: ReaderOpts) => T; } /** BytesCoderStream converts value between a type and a byte array, using streams. */ export interface BytesCoderStream { /** Fixed-size hint in bytes, when known. */ size?: number; /** * Encodes a value into a Writer stream. * @param w - Writer stream. * @param value - Value to encode. */ encodeStream: (w: Writer, value: T) => void; /** * Decodes a value from a Reader stream. * @param r - Reader stream. * @returns Decoded value. */ decodeStream: (r: Reader) => T; } /** Full coder interface with both stream and byte-array helpers. */ export type CoderType = BytesCoderStream & BytesCoder; /** CoderType with a known fixed byte size. */ export type Sized = CoderType & { size: number; }; /** Extract the decoded value type from a coder. */ export type UnwrapCoder = T extends CoderType ? U : T; /** * Validation function. Should return value after validation. * Can be used to narrow types */ export type Validate = (elm: T) => T; /** Length descriptor accepted by variable-size coders. */ export type Length = CoderType | CoderType | number | Bytes | string | null; type ArrLike = Array | ReadonlyArray; /** Typed arrays supported by the utility helper types. */ export type TypedArray = Uint8Array | Int8Array | Uint8ClampedArray | Uint16Array | Int16Array | Uint32Array | Int32Array; /** Writable version of a type, where readonly properties are made writable. */ export type Writable = T extends {} ? T extends TypedArray ? T : { -readonly [P in keyof T]: Writable; } : T; /** Union of object value types. */ export type Values = T[keyof T]; /** Key helper that removes fields whose values are exactly `undefined`. */ export type NonUndefinedKey = T[K] extends undefined ? never : K; /** Key helper that keeps only nullable fields. */ export type NullableKey = T[K] extends NonNullable ? never : K; /** Key helper for optional-but-present struct fields. */ export type OptKey = NullableKey & NonUndefinedKey; /** Key helper for required struct fields. */ export type ReqKey = T[K] extends NonNullable ? K : never; /** Object containing only optional keys from a struct shape. */ export type OptKeys = Pick; }[keyof T]>; /** Object containing only required keys from a struct shape. */ export type ReqKeys = Pick; }[keyof T]>; /** Input object type accepted by `struct()`. */ export type StructInput> = { [P in keyof ReqKeys]: T[P]; } & { [P in keyof OptKeys]?: T[P]; }; /** Record of field names to coder instances for `struct()`. */ export type StructRecord> = { [P in keyof T]: CoderType; }; /** Generic decoded object bag used internally by nested coders. */ export type StructOut = Record; /** Padding function that takes an index and returns a padding value. */ export type PadFn = (i: number) => number; /** Path related utils (internal) */ type Path = { obj: StructOut; field?: string; }; type PathStack = Path[]; export type _PathObjFn = (cb: (field: string, fieldFn: Function) => void) => void; type PathUtils = { pushObj: (stack: PathStack, obj: StructOut, objFn: _PathObjFn) => void; path: (stack: PathStack) => string; err: (name: string, stack: PathStack, msg: string | Error) => Error; resolve: (stack: PathStack, path: string) => StructOut | undefined; }; declare const Path: PathUtils; /** Options for the Reader class. */ export type ReaderOpts = { /** Allow decoding to finish with unread trailing bytes. */ allowUnreadBytes?: boolean; /** Allow the same byte range to be read more than once through pointers. */ allowMultipleReads?: boolean; }; /** Reader interface passed into stream decoders. */ export type Reader = { /** Current position in the buffer. */ readonly pos: number; /** Number of bytes left in the buffer. */ readonly leftBytes: number; /** Total number of bytes in the buffer. */ readonly totalBytes: number; /** * Checks if the end of the buffer has been reached. * @returns `true` when the reader consumed the whole buffer. */ isEnd(): boolean; /** * Creates an error with the given message. Adds information about current field path. * If Error object provided, saves original stack trace. * @param msg - The error message or an Error object. * @returns The created Error object. */ err(msg: string | Error): Error; /** * Reads a specified number of bytes from the buffer. * * WARNING: Uint8Array is subarray of original buffer. Do not modify. * @param n - The number of bytes to read. * @param peek - If `true`, the bytes are read without advancing the position. * @returns The read bytes as a Uint8Array. */ bytes(n: number, peek?: boolean): Uint8Array; /** * Reads a single byte from the buffer. * @param peek - If `true`, the byte is read without advancing the position. * @returns The read byte as a number. */ byte(peek?: boolean): number; /** * Reads a specified number of bits from the buffer. * @param bits - The number of bits to read. * @returns The read bits as a number. */ bits(bits: number): number; /** * Finds the first occurrence of a needle in the buffer. * @param needle - The needle to search for. * @param pos - The starting position for the search. * @returns The position of the first occurrence of the needle, or `undefined` if not found. */ find(needle: Bytes, pos?: number): number | undefined; /** * Creates a new Reader instance at the specified offset. * Complex and unsafe API: currently only used in eth ABI parsing of pointers. * Required to break pointer boundaries inside arrays for complex structure. * Please use only if absolutely necessary! * @param n - The offset to create the new Reader at. * @returns A new Reader instance at the specified offset. */ offsetReader(n: number): Reader; }; /** Writer interface passed into stream encoders. */ export type Writer = { /** * Creates an error with the given message. Adds information about current field path. * If Error object provided, saves original stack trace. * @param msg - The error message or an Error object. * @returns The created Error object. */ err(msg: string | Error): Error; /** * Writes a byte array to the buffer. * @param b - The byte array to write. */ bytes(b: Bytes): void; /** * Writes a single byte to the buffer. * @param b - The byte to write. */ byte(b: number): void; /** * Writes a specified number of bits to the buffer. * @param value - The value to write. * @param bits - The number of bits to write. */ bits(value: number, bits: number): void; }; /** * Internal structure. Reader class for reading from a byte array. * `stack` is internal: for debugger and logging * @class Reader */ declare class _Reader implements Reader { pos: number; readonly data: Bytes; readonly opts: ReaderOpts; readonly stack: PathStack; private parent; private parentOffset; private bitBuf; private bitPos; private bs; private view; constructor(data: Bytes, opts?: ReaderOpts, stack?: PathStack, parent?: _Reader | undefined, parentOffset?: number); /** Internal method for pointers. */ _enablePointers(): void; private markBytesBS; private markBytes; pushObj(obj: StructOut, objFn: _PathObjFn): void; readView(n: number, fn: (view: DataView, pos: number) => number): number; absBytes(n: number): Uint8Array; finish(): void; err(msg: string | Error): Error; offsetReader(n: number): _Reader; bytes(n: number, peek?: boolean): Uint8Array; byte(peek?: boolean): number; get leftBytes(): number; get totalBytes(): number; isEnd(): boolean; progress(): number; bits(bits: number): number; find(needle: Bytes, pos?: number): number | undefined; } /** * Internal structure. Writer class for writing to a byte array. * The `stack` argument of constructor is internal, for debugging and logs. * @class Writer */ declare class _Writer implements Writer { pos: number; readonly stack: PathStack; private buffers; private cleanBuffers; ptrs: { pos: number; ptr: CoderType; buffer: Bytes; }[]; private bitBuf; private bitPos; private viewBuf; private view; private finished; constructor(stack?: PathStack); pushObj(obj: StructOut, objFn: _PathObjFn): void; writeView(len: number, fn: (view: DataView) => void): void; err(msg: string | Error): Error; bytes(b: Bytes): void; byte(b: number): void; finish(clean?: boolean): Bytes; bits(value: number, bits: number): void; } /** Internal function for checking bit bounds of bigint in signed/unsinged form */ declare function checkBounds(value: bigint, bits: bigint, signed: boolean): void; /** * Validates a value before encoding and after decoding using a provided function. * @param inner - The inner CoderType. * @param fn - The validation function. * @returns CoderType which check value with validation function. * @throws On wrong inner coder or validator argument types. {@link TypeError} * @example * Reject values outside the accepted range during both encode and decode. * ```ts * import * as P from 'micro-packed'; * const val = (n: number) => { * if (n > 10) throw new Error(`${n} > 10`); * return n; * }; * * // Checks that values are <= 10 during encoding and decoding. * const RangedInt = P.validate(P.U32LE, val); * ``` */ export declare function validate(inner: CoderType, fn: Validate): CoderType; /** * Wraps a stream encoder into a generic encoder and optionally validation function * @param inner - Stream coder with optional validation hook. * @returns The wrapped CoderType. * @throws On wrong wrapped stream-coder shapes. {@link TypeError} * @example * Start from stream methods, then add validation if needed. * ```ts * import * as P from 'micro-packed'; * const U8 = P.wrap({ * encodeStream: (w, value) => w.byte(value), * decodeStream: (r) => r.byte(), * }); * const checkedU8 = P.wrap({ * encodeStream: (w, value) => w.byte(value), * decodeStream: (r) => r.byte(), * validate: (n: number) => { * if (n > 10) throw new Error(`${n} > 10`); * return n; * } * }); * ``` */ export declare const wrap: (inner: { size?: number; encodeStream: (w: Writer, value: T) => void; decodeStream: (r: Reader) => T; validate?: Validate; }) => CoderType; /** * Checks if the given value is a CoderType. * @param elm - The value to check. * @returns True if the value is a CoderType, false otherwise. * @example * Guard unknown values before calling encode/decode helpers on them. * ```ts * import { isCoder, U8 } from 'micro-packed'; * isCoder(U8); * ``` */ export declare function isCoder(elm: any): elm is CoderType; /** * Base coder for working with dictionaries (records, objects, key-value map) * Dictionary is dynamic type like: `[key: string, value: any][]` * @returns base coder that encodes/decodes between arrays of key-value tuples and dictionaries. * @example * Convert between tuple entries and a plain object record. * ```ts * import * as P from 'micro-packed'; * const dict: P.CoderType> = P.apply( * P.array(P.U16BE, P.tuple([P.cstring, P.U32LE] as const)), * P.coders.dict() * ); * ``` */ declare function dict(): BaseCoder<[string, T][], Record>; type Enum = { [k: string]: number | string; } & { [k: number]: string; }; type EnumKeys = keyof T; /** * Base coder for working with TypeScript enums. * @param e - TypeScript enum. * @returns base coder that encodes/decodes between numbers and enum keys. * @example * Map enum numbers to their string keys and back. * ```ts * import * as P from 'micro-packed'; * enum Color { Red, Green, Blue } * const colorCoder = P.coders.tsEnum(Color); * colorCoder.encode(Color.Red); // 'Red' * colorCoder.decode('Green'); // 1 * ``` */ declare function tsEnum(e: T): BaseCoder>; /** * Base coder for working with decimal numbers. * @param precision - Number of decimal places. * @param round - Round fraction part if bigger than precision (throws error by default) * @returns base coder that encodes/decodes between bigints and decimal strings. * @example * Convert bigint amounts into fixed-precision decimal strings. * ```ts * import * as P from 'micro-packed'; * const decimal8 = P.coders.decimal(8); * decimal8.encode(630880845n); // '6.30880845' * decimal8.decode('6.30880845'); // 630880845n * ``` */ declare function decimal(precision: number, round?: boolean): Coder; type BaseInput = F extends BaseCoder ? T : never; type BaseOutput = F extends BaseCoder ? T : never; /** * Combines multiple coders into a single coder, allowing conditional * encoding/decoding based on input. * Acts as a parser combinator, splitting complex conditional coders into smaller parts. * * `encode = [Ae, Be]; decode = [Ad, Bd]` * -> * `match([{encode: Ae, decode: Ad}, {encode: Be; decode: Bd}])` * * @param lst - Array of coders to match. * @returns Combined coder for conditional encoding/decoding. */ declare function match[], I = { [K in keyof L]: NonNullable>; }[number], O = { [K in keyof L]: NonNullable>; }[number]>(lst: L): BaseCoder; /** * Collection of reusable base coders and helpers. * @example * Build a reusable decimal-string adapter. * ```ts * import { coders } from 'micro-packed'; * const decimal2 = coders.decimal(2); * decimal2.encode(123n); // '1.23' * ``` */ export declare const coders: { dict: typeof dict; numberBigint: BaseCoder; tsEnum: typeof tsEnum; decimal: typeof decimal; match: typeof match; reverse: (coder: Coder) => Coder; }; /** * CoderType for parsing individual bits. * NOTE: Structure should parse whole amount of bytes before it can start parsing byte-level elements. * @param len - Number of bits to parse. * @returns CoderType representing the parsed bits. * @throws On invalid bit-length configuration or bit values. {@link Error} * @throws On wrong argument types forwarded into wrapped numeric validators. {@link TypeError} * @example * Pack several bit fields into a single byte. * ```ts * import * as P from 'micro-packed'; * const s = P.struct({ magic: P.bits(1), version: P.bits(1), tag: P.bits(4), len: P.bits(2) }); * ``` */ export declare const bits: (len: number) => CoderType; /** * CoderType for working with bigint values. * Unsized bigint values should be wrapped in a container (e.g., bytes or string). * * `0n = Uint8Array.of()` * * `1n = new Uint8Array([1n])` * * Please open issue, if you need different behavior for zero. * * @param size - Size of the bigint in bytes. * @param le - Whether to use little-endian byte order. * @param signed - Whether the bigint is signed. * @param sized - Whether the bigint should have a fixed size. * @returns CoderType representing the bigint value. * @throws On invalid bigint coder configuration or out-of-bounds bigint values. {@link Error} * @throws On wrong builder argument or wrapped numeric value types. {@link TypeError} * @example * Define a 512-bit unsigned big-endian integer coder. * ```ts * import * as P from 'micro-packed'; * // Define a CoderType for a 512-bit unsigned big-endian integer. * const U512BE = P.bigint(64, false, false, true); * ``` */ export declare const bigint: (size: number, le?: boolean, signed?: boolean, sized?: boolean) => CoderType; /** Unsigned 256-bit little-endian integer CoderType. */ export declare const U256LE: CoderType; /** Unsigned 256-bit big-endian integer CoderType. */ export declare const U256BE: CoderType; /** Signed 256-bit little-endian integer CoderType. */ export declare const I256LE: CoderType; /** Signed 256-bit big-endian integer CoderType. */ export declare const I256BE: CoderType; /** Unsigned 128-bit little-endian integer CoderType. */ export declare const U128LE: CoderType; /** Unsigned 128-bit big-endian integer CoderType. */ export declare const U128BE: CoderType; /** Signed 128-bit little-endian integer CoderType. */ export declare const I128LE: CoderType; /** Signed 128-bit big-endian integer CoderType. */ export declare const I128BE: CoderType; /** Unsigned 64-bit little-endian integer CoderType. */ export declare const U64LE: CoderType; /** Unsigned 64-bit big-endian integer CoderType. */ export declare const U64BE: CoderType; /** Signed 64-bit little-endian integer CoderType. */ export declare const I64LE: CoderType; /** Signed 64-bit big-endian integer CoderType. */ export declare const I64BE: CoderType; /** * CoderType for working with number values (up to 6 bytes/48 bits). * Unsized int values should be wrapped in a container (e.g., bytes or string). * * `0 = Uint8Array.of()` * * `1 = new Uint8Array([1n])` * * Please open issue, if you need different behavior for zero. * * @param size - Size of the number in bytes. * @param le - Whether to use little-endian byte order. * @param signed - Whether the number is signed. * @param sized - Whether the number should have a fixed size. * @returns CoderType representing the number value. * @throws On invalid number-coder configuration or out-of-bounds values. {@link Error} * @throws On wrong builder argument or wrapped numeric value types. {@link TypeError} * @example * Create a coder for JavaScript numbers up to 48 bits wide. * ```ts * import * as P from 'micro-packed'; * const int24 = P.int(3, false); // Define a coder for a 24-bit unsigned big-endian integer * ``` */ export declare const int: (size: number, le?: boolean, signed?: boolean, sized?: boolean) => CoderType; /** Unsigned 32-bit little-endian integer CoderType. */ export declare const U32LE: CoderType; /** Unsigned 32-bit big-endian integer CoderType. */ export declare const U32BE: CoderType; /** Signed 32-bit little-endian integer CoderType. */ export declare const I32LE: CoderType; /** Signed 32-bit big-endian integer CoderType. */ export declare const I32BE: CoderType; /** Unsigned 16-bit little-endian integer CoderType. */ export declare const U16LE: CoderType; /** Unsigned 16-bit big-endian integer CoderType. */ export declare const U16BE: CoderType; /** Signed 16-bit little-endian integer CoderType. */ export declare const I16LE: CoderType; /** Signed 16-bit big-endian integer CoderType. */ export declare const I16BE: CoderType; /** Unsigned 8-bit integer CoderType. */ export declare const U8: CoderType; /** Signed 8-bit integer CoderType. */ export declare const I8: CoderType; /** 32-bit big-endian floating point CoderType ("binary32", IEEE 754-2008). */ export declare const F32BE: CoderType; /** 32-bit little-endian floating point CoderType ("binary32", IEEE 754-2008). */ export declare const F32LE: CoderType; /** 64-bit big-endian floating point type ("binary64", IEEE 754-2008). */ export declare const F64BE: CoderType; /** 64-bit little-endian floating point type ("binary64", IEEE 754-2008). */ export declare const F64LE: CoderType; /** Boolean CoderType. */ export declare const bool: CoderType; /** * Bytes CoderType with a specified length and endianness. * The bytes can have: * - Dynamic size (prefixed with a length CoderType like U16BE) * - Fixed size (specified by a number) * - Unknown size (null, will parse until end of buffer) * - Zero-terminated (terminator can be any Uint8Array) * @param len - Length mode: CoderType for dynamic size, number for fixed size, * Uint8Array for terminator mode, or null to parse until end of buffer. * @param le - Whether to use little-endian byte order. * @returns CoderType representing the bytes. * @throws If the byte layout or terminator handling is invalid. {@link Error} * @throws On wrong byte-coder argument or value types. {@link TypeError} * @example * Use fixed-size, length-prefixed, or trailing byte arrays. * ```ts * import * as P from 'micro-packed'; * const dynamicBytes = P.bytes(P.U16BE, false); * const fixedBytes = P.bytes(32, false); // Fixed size bytes * const unknownBytes = P.bytes(null, false); // Unknown size bytes, will parse until end of buffer * const zeroTerminatedBytes = P.bytes(Uint8Array.of(0), false); // Zero-terminated bytes * ``` */ declare const createBytes: (len: Length, le?: boolean) => CoderType; export { createBytes as bytes, createHex as hex }; /** * Prefix-encoded value using a length prefix and an inner CoderType. * The prefix can have: * - Dynamic size (prefixed with a length CoderType like U16BE) * - Fixed size (specified by a number) * - Unknown size (null, will parse until end of buffer) * - Zero-terminated (terminator can be any Uint8Array) * @param len - Length mode: CoderType for dynamic size, number for fixed size, * Uint8Array for terminator mode, or null to parse until end of buffer. * @param inner - CoderType for the actual value to be prefix-encoded. * @returns CoderType representing the prefix-encoded value. * @throws If the prefix configuration or wrapped coding step is invalid. {@link Error} * @throws On wrong prefix-coder argument types. {@link TypeError} * @example * Prefix a payload with either a dynamic or fixed byte count. * ```ts * import * as P from 'micro-packed'; * // Dynamic size prefix: prefixed with P.U16BE byte length. * const dynamicPrefix = P.prefix(P.U16BE, P.bytes(null)); * // Fixed size prefix: always 10 bytes. * const fixedPrefix = P.prefix(10, P.bytes(null)); * ``` */ export declare function prefix(len: Length, inner: CoderType): CoderType; /** * String CoderType with a specified length and endianness. * The string can be: * - Dynamic size (prefixed with a length CoderType like U16BE) * - Fixed size (specified by a number) * - Unknown size (null, will parse until end of buffer) * - Zero-terminated (terminator can be any Uint8Array) * @param len - Length mode: CoderType for dynamic size, number for fixed size, * Uint8Array for terminator mode, or null to parse until end of buffer. * @param le - Whether to use little-endian byte order. * Note: UTF-8 has no endian variant; `le` reverses the encoded byte sequence * via the underlying byte coder. * @returns CoderType representing the string. * @throws If the underlying byte layout is invalid. {@link Error} * @throws On wrong string-coder argument or value types. {@link TypeError} * @example * Use fixed-size, length-prefixed, or trailing UTF-8 strings. * ```ts * import * as P from 'micro-packed'; * // Dynamic string prefixed with P.U16BE string length. * const dynamicString = P.string(P.U16BE, false); * const fixedString = P.string(10, false); * // Unknown size string, parsed until end of buffer. * const unknownString = P.string(null, false); * const nullTerminatedString = P.cstring; // NUL-terminated string * const _cstring = P.string(Uint8Array.of(0)); // Same thing * ``` */ export declare const string: (len: Length, le?: boolean) => CoderType; /** NUL-terminated string CoderType. */ export declare const cstring: CoderType; type HexOpts = { isLE?: boolean; with0x?: boolean; }; /** * Hexadecimal string CoderType with a specified length, endianness, and optional 0x prefix. * @param len - Length mode: CoderType for dynamic size, number for fixed size, * Uint8Array for terminator mode, or null to parse until end of buffer. * @param options - Hex-specific endianness and prefix options. See {@link HexOpts}. * Use `isLE` to decode bytes as little-endian before converting to hex, and * `with0x` to add and require a `0x` prefix. * @returns CoderType representing the hexadecimal string. * @throws If the underlying byte layout or `0x` prefix handling is invalid. {@link Error} * @throws On wrong hex-coder argument or value types. {@link TypeError} * @example * Encode bytes as hex, optionally little-endian and with a `0x` prefix. * ```ts * import * as P from 'micro-packed'; * // Hex string with 0x prefix and U16BE length. * const dynamicHex = P.hex(P.U16BE, {isLE: false, with0x: true}); * // Fixed-length 32-byte hex string without 0x prefix. * const fixedHex = P.hex(32, {isLE: false, with0x: false}); * ``` */ declare const createHex: (len: Length, options?: HexOpts) => CoderType; /** * Applies a base coder to a CoderType. * @param inner - The inner CoderType. * @param base - The base coder to apply. * @returns CoderType representing the transformed value. * @throws On wrong inner-coder or base-coder argument types. {@link TypeError} * @example * Reuse a base coder on top of a binary bytes coder. * ```ts * import * as P from 'micro-packed'; * import { hex as baseHex } from '@scure/base'; * const hexCoder = P.apply(P.bytes(32), baseHex); // will decode bytes into a hex string * ``` */ export declare function apply(inner: CoderType, base: BaseCoder): CoderType; /** * Lazy CoderType that is evaluated at runtime. * @param fn - A function that returns the CoderType. * @returns CoderType representing the lazy value. * @throws On wrong lazy-factory argument types. {@link TypeError} * @example * Define a recursive tree without referencing the coder before it exists. * ```ts * import * as P from 'micro-packed'; * type Tree = { name: string; children: Tree[] }; * const tree = P.struct({ * name: P.cstring, * children: P.array( * P.U16BE, * P.lazy((): P.CoderType => tree) * ), * }); * ``` */ export declare function lazy(fn: () => CoderType): CoderType; /** * Flag CoderType that encodes/decodes a boolean value based on the presence of a marker. * @param flagValue - Marker value. * @param xor - Whether to invert the flag behavior. * @returns CoderType representing the flag value. * @throws On wrong flag argument or value types. {@link TypeError} * @throws If the marker is empty. {@link Error} * @example * Toggle a boolean based on whether a marker is present. * ```ts * import * as P from 'micro-packed'; * // Encodes true as u8a([0x01, 0x02]), false as u8a([]). * const flag = P.flag(new Uint8Array([0x01, 0x02])); * // Encodes true as u8a([]), false as u8a([0x01, 0x02]). * const flagXor = P.flag(new Uint8Array([0x01, 0x02]), true); * const s = P.struct({ f: P.flag(new Uint8Array([0x0, 0x1])), f2: P.flagged('f', P.U32BE) }); * ``` */ export declare const flag: (flagValue: TArg, xor?: boolean) => CoderType; /** * Conditional CoderType that encodes/decodes a value only if a flag is present. * @param path - Path to the flag value or a CoderType for the flag. * @param inner - Inner CoderType for the value. * @param def - Optional default value to use if the flag is not present. * @returns CoderType representing the conditional value. * @throws On wrong flag-path or inner-coder argument types. {@link TypeError} * @example * Decode a field only when a sibling flag is present. * ```ts * import * as P from 'micro-packed'; * const s = P.struct({ * f: P.flag(new Uint8Array([0x0, 0x1])), * f2: P.flagged('f', P.U32BE) * }); * ``` * * @example * Supply a default when the sibling flag is missing. * ```ts * import * as P from 'micro-packed'; * const s2 = P.struct({ * f: P.flag(new Uint8Array([0x0, 0x1])), * f2: P.flagged('f', P.U32BE, 123) * }); * ``` */ export declare function flagged(path: string | CoderType, inner: CoderType, def?: T): CoderType>; /** * Optional CoderType that encodes/decodes a value based on a flag. * @param flag - CoderType for the flag value. * @param inner - Inner CoderType for the value. * @param def - Optional default value to use if the flag is not present. * @returns CoderType representing the optional value. * @throws On wrong flag-coder or inner-coder argument types. {@link TypeError} * @example * Decode a value only when a marker flag is present. * ```ts * import * as P from 'micro-packed'; * const optional = P.optional(P.flag(new Uint8Array([0x0, 0x1])), P.U32BE); * ``` * * @example * Provide a fallback value when the marker flag is absent. * ```ts * import * as P from 'micro-packed'; * const optionalWithDefault = P.optional(P.flag(new Uint8Array([0x0, 0x1])), P.U32BE, 123); * ``` */ export declare function optional(flag: CoderType, inner: CoderType, def?: T): CoderType>; /** * Magic value CoderType that encodes/decodes a constant value. * This can be used to check for a specific magic value or byte sequence * at the beginning of a data structure. * @param inner - Inner CoderType for the value. * @param constant - Constant value. * @param check - Whether to check the decoded value against the constant. * @returns CoderType representing the magic value. * @throws On wrong magic-coder argument types. {@link TypeError} * @example * Require a specific encoded value at this position in the stream. * ```ts * import * as P from 'micro-packed'; * const magicU8 = P.magic(P.U8, 0x42); * ``` */ export declare function magic(inner: CoderType, constant: T, check?: boolean): CoderType; /** * Magic bytes CoderType that encodes/decodes a constant byte array or string. * @param constant - Constant byte array or string. * @returns CoderType representing the magic bytes. * @throws If the constant check fails or the wrapped coder rejects the bytes. {@link Error} * @throws On wrong magic-bytes argument types. {@link TypeError} * Note: Uint8Array constants are retained by reference; do not mutate them * after constructing the coder. * @example * Match a fixed byte or string marker without producing a value. * ```ts * import * as P from 'micro-packed'; * const magicBytes = P.magicBytes('MAGIC'); * ``` */ export declare const magicBytes: (constant: TArg) => CoderType; /** * Creates a CoderType for a constant value. The function enforces this value during encoding, * ensuring it matches the provided constant. During decoding, it always returns the constant value. * The actual value is not written to or read from any byte stream; it's used only for validation. * * @param c - Constant value. * @returns CoderType representing the constant value. * @throws On wrong constant values passed during encoding. {@link TypeError} * Note: object constants are compared and returned by reference. * @example * Hide an always-constant field behind a regular coder. * ```ts * import * as P from 'micro-packed'; * const constantU8 = P.constant(123); * ``` */ export declare function constant(c: T): CoderType; /** * Structure of composable primitives (C/Rust struct) * @param fields - Object mapping field names to CoderTypes. * @returns CoderType representing the structure. * @throws If the structure definition or encoded struct value is invalid. {@link Error} * @throws On wrong structure argument types. {@link TypeError} * Note: the fields object is retained by reference; mutating it after * construction can change encoding * while leaving fixed-size metadata unchanged. * @example * Combine named fields into a single structured coder. * ```ts * import * as P from 'micro-packed'; * const myStruct = P.struct({ * id: P.U32BE, * name: P.string(P.U8), * nested: P.struct({ * flag: P.bool, * value: P.I16LE * }) * }); * ``` */ export declare function struct>(fields: StructRecord): CoderType>; /** * Tuple (unnamed structure) of CoderTypes. Same as struct but with unnamed fields. * @param fields - Array of CoderTypes. * @returns CoderType representing the tuple. * @throws If the tuple definition or encoded tuple value is invalid. {@link Error} * @throws On wrong tuple argument types. {@link TypeError} * Note: unbounded coders such as `array(null, ...)` should be last or length-prefixed; otherwise * they can consume bytes intended for later fields. * Note: the fields array is retained by reference; mutating it after construction can change encoding * while leaving fixed-size metadata unchanged. * @example * Combine several coders into an ordered fixed-length tuple. * ```ts * import * as P from 'micro-packed'; * const myTuple = P.tuple([P.U8, P.U16LE, P.string(P.U8)]); * ``` */ export declare function tuple>, O = Writable<{ [K in keyof T]: UnwrapCoder; }>>(fields: T): CoderType; /** * Array of items (inner type) with a specified length. * @param len - Length mode: CoderType for dynamic size, number for fixed size, * Uint8Array for terminator mode, or null to parse until end of buffer. * @param inner - CoderType for encoding/decoding each array item. * @returns CoderType representing the array. * @throws If the array definition or encoded array elements are invalid. {@link Error} * @throws On wrong array-coder argument types. {@link TypeError} * Note: Uint8Array terminators are retained by reference; do not mutate them * after constructing the coder. * @example * Build dynamic, fixed-size, and trailing arrays from one item coder. * ```ts * import * as P from 'micro-packed'; * const child = P.U8; * // Dynamic array prefixed with P.U16BE array length. * const a1 = P.array(P.U16BE, child); * const a2 = P.array(4, child); // Fixed size array * // Unknown size array, parsed until end of buffer. * const a3 = P.array(null, child); * // Zero-terminated array; terminator can be any buffer. * const a4 = P.array(Uint8Array.of(0), child); * ``` */ export declare function array(len: Length, inner: CoderType): CoderType; /** * Mapping between encoded values and string representations. * @param inner - CoderType for encoded values. * @param variants - Object mapping string representations to encoded values. * @returns CoderType representing the mapping. * @throws If mapping variants are invalid or raw variant values are duplicate. {@link Error} * @throws On wrong mapping argument types. {@link TypeError} * Note: variants are copied into lookup maps at construction; mutating the * original object later does not update the coder. * Note: construction does not run the inner coder. Path-dependent coders need * encode/decode stack context that does not exist at construction, so selected * variant values are validated by the inner coder only when encoded or decoded. * @example * Map encoded numbers to a small set of string labels. * ```ts * import * as P from 'micro-packed'; * const numberMap = P.map(P.U8, { * 'one': 1, * 'two': 2, * 'three': 3 * }); * * const byteMap = P.map(P.hex(2), { * 'ab': '6162', * 'cd': '6364' * }); * ``` */ export declare function map(inner: CoderType, variants: Record): CoderType; /** * Tagged union of CoderTypes, where the tag value determines which CoderType to use. * The decoded value will have the structure `\{ TAG: number, data: ... \}`. * @param tag - CoderType for the tag value. * @param variants - Object mapping tag values to CoderTypes. * @returns CoderType representing the tagged union. * @throws On wrong tag-coder or variant-map argument types. {@link TypeError} * Note: variants are copied into a lookup map at construction; mutating the * original object later does not update the coder. * Note: construction does not run the tag coder. Path-dependent tag coders need * encode/decode stack context that does not exist at construction, so callers * are responsible for providing tag keys that the tag coder can encode/decode. * @example * Switch between payload coders based on a leading tag byte. * ```ts * import * as P from 'micro-packed'; * const taggedUnion = P.tag(P.U8, { * 0x01: P.array(P.U16LE, P.U8), * 0x02: P.string(P.U8), * 0x03: P.U32BE * }); * * const encoded = taggedUnion.encode({ TAG: 0x01, data: [1, 2] }); * const decoded = taggedUnion.decode(encoded); * ``` */ export declare function tag; }; }>, TagValue extends string | number, Variants extends Record>>(tag: CoderType, variants: Variants): CoderType; /** * Mapping between encoded values, string representations, and CoderTypes using a tag CoderType. * @param tagCoder - CoderType for the tag value. * @param variants - Object mapping string representations to [tag value, CoderType] pairs. * @returns CoderType representing the mapping. * @throws If the mapped-tag table is invalid, raw tag values are duplicate, * or the selected variant is invalid. {@link Error} * @throws On wrong tag-coder or variant-map argument types. {@link TypeError} * Note: construction does not run the tag coder. Path-dependent tag coders need * encode/decode stack context that does not exist at construction, so callers * are responsible for providing tag values that the tag coder can encode/decode. * Note: variant pairs are copied at construction; mutating the original variants * object or pair arrays later does not update the coder. * @example * Use string tags in TypeScript while encoding them as compact numeric tags. * ```ts * import * as P from 'micro-packed'; * type Value = * | { TAG: 'uint'; data: number } * | { TAG: 'array'; data: Value[] }; * const value: P.CoderType = P.mappedTag(P.U8, { * uint: [0, P.U8], * array: [1, P.array(P.U8, P.lazy(() => value))], * }); * value.encode({ TAG: 'array', data: [{ TAG: 'uint', data: 5 }] }); * ``` */ export declare function mappedTag; }; }>, TagValue extends string | number, Variants extends Record]>>(tagCoder: CoderType, variants: Variants): CoderType; /** * Bitset of boolean values with optional padding. * @param names - An array of string names for the bitset values. * @param pad - Whether to pad the bitset to a multiple of 8 bits. * @param strict - Whether to reject duplicate names and non-zero padding bits. * @returns CoderType representing the bitset. * @typeParam Names - Bit names preserved in the returned record. * @throws If the bitset definition or encoded bitset values are invalid. {@link Error} * @throws On wrong bitset argument types. {@link TypeError} * Note: bits follow `names` order and are written most-significant-bit first * within each byte; non-byte-aligned `pad=false` bitsets must be composed with * more bit-level coders. * Note: strict mode is opt-in for legacy compatibility with callers that used * repeated reserved names or accept non-zero padding bits. * Note: the names array is retained by reference; mutating it after construction * changes encoding and decoding. * @example * Pack several named booleans into a compact bitset. * ```ts * import * as P from 'micro-packed'; * const myBitset = P.bitset(['flag1', 'flag2', 'flag3', 'flag4'], true); * ``` */ export declare function bitset(names: Names, pad?: boolean, strict?: boolean): CoderType>; /** * Padding function which always returns zero. * @param i - Zero-based padding byte index. * @returns Always returns `0`. * @example * Use the default zero padding helper with padLeft/padRight. * ```ts * import { U16BE, ZeroPad, padLeft } from 'micro-packed'; * padLeft(4, U16BE, ZeroPad); * ``` */ export declare const ZeroPad: PadFn; declare function padLength(blockSize: number, len: number): number; /** * Pads a CoderType with a specified block size and padding function on the left side. * @param blockSize - Block size for padding (positive safe integer). * @param inner - Inner CoderType to pad. * @param padFn - Padding function to use. If not provided, zero padding is used. * @returns CoderType representing the padded value. * Note: decode skips the computed left-padding bytes without validating values; * `padFn` affects encoding only. * @throws If the padding configuration or wrapped coder is invalid. {@link Error} * @throws On wrong padding argument types. {@link TypeError} * @example * Left-pad a value to the next block boundary. * ```ts * import * as P from 'micro-packed'; * const paddedU32BE = P.padLeft(4, P.U32BE); * * const paddedBytes = P.padLeft(16, P.bytes(8), (i) => i + 1); * ``` */ export declare function padLeft(blockSize: number, inner: CoderType, padFn: Option): CoderType; /** * Pads a CoderType with a specified block size and padding function on the right side. * @param blockSize - Block size for padding (positive safe integer). * @param inner - Inner CoderType to pad. * @param padFn - Padding function to use. If not provided, zero padding is used. * @returns CoderType representing the padded value. * Note: decode skips the computed right-padding bytes without validating values; * `padFn` affects encoding only. * @throws If the padding configuration or wrapped coder is invalid. {@link Error} * @throws On wrong padding argument types. {@link TypeError} * @example * Right-pad a value to the next block boundary. * ```ts * import * as P from 'micro-packed'; * const paddedU16BE = P.padRight(2, P.U16BE); * * const paddedBytes = P.padRight(8, P.bytes(null), (i) => i + 1); * ``` */ export declare function padRight(blockSize: number, inner: CoderType, padFn: Option): CoderType; /** * Pointer to a value using a pointer CoderType and an inner CoderType. * Pointers are scoped, and the next pointer in the dereference chain is offset by the previous one. * By default (if no 'allowMultipleReads' in ReaderOpts is set) is safe, since * same region of memory cannot be read multiple times. * @param ptr - CoderType for the pointer value. * @param inner - CoderType for encoding/decoding the pointed value. * @param sized - Whether the in-place pointer slot should report a fixed size. * @returns CoderType representing the pointer to the value. * @throws If the pointer configuration or pointed value decoding is invalid. {@link Error} * @throws On wrong pointer-coder argument types. {@link TypeError} * @example * Jump to a pointed value and decode it with another coder. * ```ts * import * as P from 'micro-packed'; * const pointerToU8 = P.pointer(P.U16BE, P.U8); // Pointer to a single U8 value * ``` */ export declare function pointer(ptr: CoderType, inner: CoderType, sized?: boolean): CoderType; export declare const _TEST: { _bitset: { BITS: number; FULL_MASK: number; len: (len: number) => number; create: (len: number) => Uint32Array; clean: (bs: Uint32Array) => Uint32Array; debug: (bs: Uint32Array) => string[]; checkLen: (bs: Uint32Array, len: number) => void; chunkLen: (bsLen: number, pos: number, len: number) => void; set: (bs: Uint32Array, chunk: number, value: number, allowRewrite?: boolean) => boolean; pos: (pos: number, i: number) => { chunk: number; mask: number; }; indices: (bs: Uint32Array, len: number, invert?: boolean) => number[]; range: (arr: number[]) => { pos: number; length: number; }[]; rangeDebug: (bs: Uint32Array, len: number, invert?: boolean) => string; setRange: (bs: Uint32Array, bsLen: number, pos: number, len: number, allowRewrite?: boolean) => boolean; }; _padLength: typeof padLength; _findBytes: typeof findBytes; _Reader: typeof _Reader; _Writer: typeof _Writer; Path: { /** * Internal method for handling stack of paths (debug, errors, dynamic fields via path) * This callback shape forces stack cleanup by construction: * `.pop()` always happens after the wrapped function. * Also, this makes impossible: * - pushing field when stack is empty * - pushing field inside of field (real bug) * NOTE: we don't want to do '.pop' on error! */ pushObj: (stack: PathStack, obj: StructOut, objFn: _PathObjFn) => void; path: (stack: PathStack) => string; err(name: string, stack: PathStack, msg: string | Error): Error; resolve: (stack: PathStack, path: string) => StructOut | undefined; }; }; //# sourceMappingURL=index.d.ts.map