{"id":15650624,"url":"https://github.com/paulmillr/micro-packed","last_synced_at":"2025-04-05T01:09:31.540Z","repository":{"id":45009844,"uuid":"504962313","full_name":"paulmillr/micro-packed","owner":"paulmillr","description":"Define complex binary structures using composable primitives","archived":false,"fork":false,"pushed_at":"2025-03-25T10:19:43.000Z","size":917,"stargazers_count":42,"open_issues_count":1,"forks_count":8,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-29T00:09:26.511Z","etag":null,"topics":["binary","bytes","enum","packed","protobuf","struct","structure","tuple"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulmillr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"paulmillr"}},"created_at":"2022-06-18T22:22:05.000Z","updated_at":"2025-03-25T10:19:47.000Z","dependencies_parsed_at":"2024-06-18T18:40:33.381Z","dependency_job_id":"6b0a9b88-39bd-4ab7-9b45-dbed3337a1d0","html_url":"https://github.com/paulmillr/micro-packed","commit_stats":{"total_commits":73,"total_committers":2,"mean_commits":36.5,"dds":"0.013698630136986356","last_synced_commit":"0c5230e20f61ad7f112ffb4ee406ee92c13f248c"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-packed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-packed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-packed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-packed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulmillr","download_url":"https://codeload.github.com/paulmillr/micro-packed/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271532,"owners_count":20911587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary","bytes","enum","packed","protobuf","struct","structure","tuple"],"created_at":"2024-10-03T12:35:17.365Z","updated_at":"2025-04-05T01:09:31.513Z","avatar_url":"https://github.com/paulmillr.png","language":"TypeScript","readme":"# micro-packed\n\n\u003e Less painful binary encoding / decoding\n\nDefine complex binary structures using composable primitives. Comes with a friendly [debugger](#debugger).\n\nUsed in:\n\n- [btc-signer](https://github.com/paulmillr/scure-btc-signer) for parsing of Bitcoin Script\n- [eth-signer](https://github.com/paulmillr/micro-eth-signer) for RLP and SSZ decoding. RLP pointers are protected against DoS\n- [sol-signer](https://github.com/paulmillr/micro-sol-signer) for parsing of keys, messages and other things\n- [micro-ordinals](https://github.com/paulmillr/micro-ordinals) for Bitcoin ordinal parsing\n- [key-producer](https://github.com/paulmillr/micro-key-producer) for lightweight implementations of PGP, SSH and OTP\n\n## Usage\n\n\u003e `npm install micro-packed`\n\n\u003e `jsr add jsr:@paulmillr/micro-packed`\n\n```ts\nimport * as P from 'micro-packed';\nconst s = P.struct({\n  field1: P.U32BE, // 32-bit unsigned big-endian integer\n  field2: P.string(P.U8), // String with U8 length prefix\n  field3: P.bytes(32), // 32 bytes\n  field4: P.array(\n    P.U16BE,\n    P.struct({\n      // Array of structs with U16BE length\n      subField1: P.U64BE, // 64-bit unsigned big-endian integer\n      subField2: P.string(10), // 10-byte string\n    })\n  ),\n});\n```\n\nTable of contents:\n\n- [Basics](#basics)\n- Primitive types: [P.bytes](#pbytes), [P.string](#pstring), [P.hex](#phex), [P.constant](#pconstant), [P.pointer](#ppointer)\n- Complex types: [P.array](#parray), [P.struct](#pstruct), [P.tuple](#ptuple), [P.map](#pmap), [P.tag](#ptag), [P.mappedTag](#pmappedtag)\n- Padding, prefix, magic: [P.padLeft](#ppadleft), [P.padRight](#ppadright), [P.prefix](#pprefix), [P.magic](#pmagic), [P.magicBytes](#pmagicbytes)\n- Flags: [P.flag](#pflag), [P.flagged](#pflagged), [P.optional](#poptional)\n- Wrappers: [P.apply](#papply), [P.wrap](#pwrap), [P.lazy](#plazy)\n- Bit fiddling: [P.bits](#pbits), [P.bitset](#pbitset)\n- [utils](#utils): [P.validate](#pvalidate), [coders.decimal](#codersdecimal)\n- [Debugger](#debugger)\n\n### Basics\n\nThere are 3 main interfaces:\n\n- `Coder\u003cF, T\u003e` - a converter between types F and T\n- `BytesCoder\u003cT\u003e` - a Coder from type T to Bytes\n- `BytesCoderStream\u003cT\u003e` - streaming BytesCoder with Reader and Writer streams\n\nCoder and BytesCoder use `encode` / `decode` methods\n\nBytesCoderStream use `encodeStream` and `decodeStream`\n\n#### Flexible size\n\nMany primitives accept length / size / len as their argument.\nIt represents their size. There are four different types of size:\n\n- CoderType: Dynamic size (prefixed with a length CoderType like U16BE)\n- number: Fixed size (specified by a number)\n- terminator: Uint8Array (will parse until these bytes are matched)\n- null: (null, will parse until end of buffer)\n\n## Primitive types\n\n### P.bytes\n\nBytes CoderType with a specified length and endianness.\n\n| Param | Description                                                     |\n| ----- | --------------------------------------------------------------- |\n| len   | Length CoderType, number, Uint8Array (for terminator), or null. |\n| le    | Whether to use little-endian byte order.                        |\n\n```js\n// Dynamic size bytes (prefixed with P.U16BE number of bytes length)\nconst dynamicBytes = P.bytes(P.U16BE, false);\nconst fixedBytes = P.bytes(32, false); // Fixed size bytes\nconst unknownBytes = P.bytes(null, false); // Unknown size bytes, will parse until end of buffer\nconst zeroTerminatedBytes = P.bytes(new Uint8Array([0]), false); // Zero-terminated bytes\n```\n\nFollowing shortcuts are also available:\n\n- `P.EMPTY`: Shortcut to zero-length (empty) byte array\n- `P.NULL`: Shortcut to one-element (element is 0) byte array\n\n### P.string\n\nString CoderType with a specified length and endianness.\n\n| Param | Description                                        |\n| ----- | -------------------------------------------------- |\n| len   | CoderType, number, Uint8Array (terminator) or null |\n| le    | Whether to use little-endian byte order.           |\n\n```js\nconst dynamicString = P.string(P.U16BE, false); // Dynamic size string (prefixed with P.U16BE number of string length)\nconst fixedString = P.string(10, false); // Fixed size string\nconst unknownString = P.string(null, false); // Unknown size string, will parse until end of buffer\nconst nullTerminatedString = P.cstring; // NUL-terminated string\nconst _cstring = P.string(new Uint8Array([0])); // Same thing\n```\n\n### P.hex\n\nHexadecimal string CoderType with a specified length, endianness, and optional 0x prefix.\n\n**Returns**: CoderType representing the hexadecimal string.\n\n| Param  | Description                                                                                                                 |\n| ------ | --------------------------------------------------------------------------------------------------------------------------- |\n| len    | Length CoderType (dynamic size), number (fixed size), Uint8Array (for terminator), or null (will parse until end of buffer) |\n| isLE   | Whether to use little-endian byte order.                                                                                    |\n| with0x | Whether to include the 0x prefix.                                                                                           |\n\n```js\nconst dynamicHex = P.hex(P.U16BE, { isLE: false, with0x: true }); // Hex string with 0x prefix and U16BE length\nconst fixedHex = P.hex(32, { isLE: false, with0x: false }); // Fixed-length 32-byte hex string without 0x prefix\n```\n\n### P.constant\n\nCreates a CoderType for a constant value. The function enforces this value during encoding,\nensuring it matches the provided constant. During decoding, it always returns the constant value.\nThe actual value is not written to or read from any byte stream; it's used only for validation.\n\n**Returns**: CoderType representing the constant value.\n\n| Param | Description     |\n| ----- | --------------- |\n| c     | Constant value. |\n\n```js\n// Always return 123 on decode, throws on encoding anything other than 123\nconst constantU8 = P.constant(123);\n```\n\n### P.pointer\n\nPointer to a value using a pointer CoderType and an inner CoderType.\nPointers are scoped, and the next pointer in the dereference chain is offset by the previous one.\nBy default (if no 'allowMultipleReads' in ReaderOpts is set) is safe, since\nsame region of memory cannot be read multiple times.\n\n**Returns**: CoderType representing the pointer to the value.\n\n| Param | Description                                        |\n| ----- | -------------------------------------------------- |\n| ptr   | CoderType for the pointer value.                   |\n| inner | CoderType for encoding/decoding the pointed value. |\n| sized | Whether the pointer should have a fixed size.      |\n\n```js\nconst pointerToU8 = P.pointer(P.U16BE, P.U8); // Pointer to a single U8 value\n```\n\n## Complex types\n\n### P.array\n\nArray of items (inner type) with a specified length.\n\n| Param | Description                                                                                                             |\n| ----- | ----------------------------------------------------------------------------------------------------------------------- |\n| len   | Length CoderType (dynamic size), number (fixed size), Uint8Array (terminator), or null (will parse until end of buffer) |\n| inner | CoderType for encoding/decoding each array item.                                                                        |\n\n```js\nconst a1 = P.array(P.U16BE, child); // Dynamic size array (prefixed with P.U16BE number of array length)\nconst a2 = P.array(4, child); // Fixed size array\nconst a3 = P.array(null, child); // Unknown size array, will parse until end of buffer\nconst a4 = P.array(new Uint8Array([0]), child); // zero-terminated array (NOTE: terminator can be any buffer)\n```\n\n### P.struct\n\nStructure of composable primitives (C/Rust struct)\n\n**Returns**: CoderType representing the structure.\n\n| Param  | Description                               |\n| ------ | ----------------------------------------- |\n| fields | Object mapping field names to CoderTypes. |\n\n```js\n// Define a structure with a 32-bit big-endian unsigned integer, a string, and a nested structure\nconst myStruct = P.struct({\n  id: P.U32BE,\n  name: P.string(P.U8),\n  nested: P.struct({\n    flag: P.bool,\n    value: P.I16LE,\n  }),\n});\n```\n\n### P.tuple\n\nTuple (unnamed structure) of CoderTypes. Same as struct but with unnamed fields.\n\n| Param  | Description          |\n| ------ | -------------------- |\n| fields | Array of CoderTypes. |\n\n```js\nconst myTuple = P.tuple([P.U8, P.U16LE, P.string(P.U8)]);\n```\n\n### P.map\n\nMapping between encoded values and string representations.\n\n**Returns**: CoderType representing the mapping.\n\n| Param    | Description                                              |\n| -------- | -------------------------------------------------------- |\n| inner    | CoderType for encoded values.                            |\n| variants | Object mapping string representations to encoded values. |\n\n```ts\n// Map between numbers and strings\nconst numberMap = P.map(P.U8, {\n  one: 1,\n  two: 2,\n  three: 3,\n});\n\n// Map between byte arrays and strings\nconst byteMap = P.map(P.bytes(2, false), {\n  ab: Uint8Array.from([0x61, 0x62]),\n  cd: Uint8Array.from([0x63, 0x64]),\n});\n```\n\n### P.tag\n\nTagged union of CoderTypes, where the tag value determines which CoderType to use.\nThe decoded value will have the structure `{ TAG: number, data: ... }`.\n\n| Param    | Description                              |\n| -------- | ---------------------------------------- |\n| tag      | CoderType for the tag value.             |\n| variants | Object mapping tag values to CoderTypes. |\n\n```js\n// Tagged union of array, string, and number\n// Depending on the value of the first byte, it will be decoded as an array, string, or number.\nconst taggedUnion = P.tag(P.U8, {\n  0x01: P.array(P.U16LE, P.U8),\n  0x02: P.string(P.U8),\n  0x03: P.U32BE,\n});\n\nconst encoded = taggedUnion.encode({ TAG: 0x01, data: 'hello' }); // Encodes the string 'hello' with tag 0x01\nconst decoded = taggedUnion.decode(encoded); // Decodes the encoded value back to { TAG: 0x01, data: 'hello' }\n```\n\n### P.mappedTag\n\nMapping between encoded values, string representations, and CoderTypes using a tag CoderType.\n\n| Param    | Description                                                            |\n| -------- | ---------------------------------------------------------------------- |\n| tagCoder | CoderType for the tag value.                                           |\n| variants | Object mapping string representations to [tag value, CoderType] pairs. |\n\n```js\nconst cborValue: P.CoderType\u003cCborValue\u003e = P.mappedTag(P.bits(3), {\n  uint: [0, cborUint], // An unsigned integer in the range 0..264-1 inclusive.\n  negint: [1, cborNegint], // A negative integer in the range -264..-1 inclusive\n  bytes: [2, P.lazy(() =\u003e cborLength(P.bytes, cborValue))], // A byte string.\n  string: [3, P.lazy(() =\u003e cborLength(P.string, cborValue))], // A text string (utf8)\n  array: [4, cborArrLength(P.lazy(() =\u003e cborValue))], // An array of data items\n  map: [5, P.lazy(() =\u003e cborArrLength(P.tuple([cborValue, cborValue])))], // A map of pairs of data items\n  tag: [6, P.tuple([cborUint, P.lazy(() =\u003e cborValue)] as const)], // A tagged data item (\"tag\") whose tag number\n  simple: [7, cborSimple], // Floating-point numbers and simple values, as well as the \"break\" stop code\n});\n```\n\n## Padding, prefix, magic\n\n### P.padLeft\n\nPads a CoderType with a specified block size and padding function on the left side.\n\n**Returns**: CoderType representing the padded value.\n\n| Param     | Description                                                     |\n| --------- | --------------------------------------------------------------- |\n| blockSize | Block size for padding (positive safe integer).                 |\n| inner     | Inner CoderType to pad.                                         |\n| padFn     | Padding function to use. If not provided, zero padding is used. |\n\n```js\n// Pad a U32BE with a block size of 4 and zero padding\nconst paddedU32BE = P.padLeft(4, P.U32BE);\n\n// Pad a string with a block size of 16 and custom padding\nconst paddedString = P.padLeft(16, P.string(P.U8), (i) =\u003e i + 1);\n```\n\n### P.padRight\n\nPads a CoderType with a specified block size and padding function on the right side.\n\n**Returns**: CoderType representing the padded value.\n\n| Param     | Description                                                     |\n| --------- | --------------------------------------------------------------- |\n| blockSize | Block size for padding (positive safe integer).                 |\n| inner     | Inner CoderType to pad.                                         |\n| padFn     | Padding function to use. If not provided, zero padding is used. |\n\n```js\n// Pad a U16BE with a block size of 2 and zero padding\nconst paddedU16BE = P.padRight(2, P.U16BE);\n\n// Pad a bytes with a block size of 8 and custom padding\nconst paddedBytes = P.padRight(8, P.bytes(null), (i) =\u003e i + 1);\n```\n\n### P.ZeroPad\n\nShortcut to zero-bytes padding\n\n### P.prefix\n\nPrefix-encoded value using a length prefix and an inner CoderType.\n\n**Returns**: CoderType representing the prefix-encoded value.\n\n| Param | Description                                                     |\n| ----- | --------------------------------------------------------------- |\n| len   | Length CoderType, number, Uint8Array (for terminator), or null. |\n| inner | CoderType for the actual value to be prefix-encoded.            |\n\n```js\nconst dynamicPrefix = P.prefix(P.U16BE, P.bytes(null)); // Dynamic size prefix (prefixed with P.U16BE number of bytes length)\nconst fixedPrefix = P.prefix(10, P.bytes(null)); // Fixed size prefix (always 10 bytes)\n```\n\n### P.magic\n\nMagic value CoderType that encodes/decodes a constant value.\nThis can be used to check for a specific magic value or sequence of bytes at the beginning of a data structure.\n\n**Returns**: CoderType representing the magic value.\n\n| Param    | Description                                              |\n| -------- | -------------------------------------------------------- |\n| inner    | Inner CoderType for the value.                           |\n| constant | Constant value.                                          |\n| check    | Whether to check the decoded value against the constant. |\n\n```js\n// Always encodes constant as bytes using inner CoderType, throws if encoded value is not present\nconst magicU8 = P.magic(P.U8, 0x42);\n```\n\n### P.magicBytes\n\nMagic bytes CoderType that encodes/decodes a constant byte array or string.\n\n**Returns**: CoderType representing the magic bytes.\n\n| Param    | Description                    |\n| -------- | ------------------------------ |\n| constant | Constant byte array or string. |\n\n```js\n// Always encodes undefined into byte representation of string 'MAGIC'\nconst magicBytes = P.magicBytes('MAGIC');\n```\n\n## Flags\n\n### P.flag\n\nFlag CoderType that encodes/decodes a boolean value based on the presence of a marker.\n\n**Returns**: CoderType representing the flag value.\n\n| Param     | Description                          |\n| --------- | ------------------------------------ |\n| flagValue | Marker value.                        |\n| xor       | Whether to invert the flag behavior. |\n\n```js\nconst flag = P.flag(new Uint8Array([0x01, 0x02])); // Encodes true as u8a([0x01, 0x02]), false as u8a([])\nconst flagXor = P.flag(new Uint8Array([0x01, 0x02]), true); // Encodes true as u8a([]), false as u8a([0x01, 0x02])\n// Conditional encoding with flagged\nconst s = P.struct({ f: P.flag(new Uint8Array([0x0, 0x1])), f2: P.flagged('f', P.U32BE) });\n```\n\n### P.flagged\n\nConditional CoderType that encodes/decodes a value only if a flag is present.\n\n**Returns**: CoderType representing the conditional value.\n\n| Param | Description                                               |\n| ----- | --------------------------------------------------------- |\n| path  | Path to the flag value or a CoderType for the flag.       |\n| inner | Inner CoderType for the value.                            |\n| def   | Optional default value to use if the flag is not present. |\n\n### P.optional\n\nOptional CoderType that encodes/decodes a value based on a flag.\n\n**Returns**: CoderType representing the optional value.\n\n| Param | Description                                               |\n| ----- | --------------------------------------------------------- |\n| flag  | CoderType for the flag value.                             |\n| inner | Inner CoderType for the value.                            |\n| def   | Optional default value to use if the flag is not present. |\n\n```js\n// Will decode into P.U32BE only if flag present\nconst optional = P.optional(P.flag(new Uint8Array([0x0, 0x1])), P.U32BE);\n```\n\n```js\n// If no flag present, will decode into default value\nconst optionalWithDefault = P.optional(P.flag(new Uint8Array([0x0, 0x1])), P.U32BE, 123);\n```\n\n```js\nconst s = P.struct({\n  f: P.flag(new Uint8Array([0x0, 0x1])),\n  f2: P.flagged('f', P.U32BE),\n});\n```\n\n```js\nconst s2 = P.struct({\n  f: P.flag(new Uint8Array([0x0, 0x1])),\n  f2: P.flagged('f', P.U32BE, 123),\n});\n```\n\n## Wrappers\n\n### P.apply\n\nApplies a base coder to a CoderType.\n\n**Returns**: CoderType representing the transformed value.\n\n| Param | Description              |\n| ----- | ------------------------ |\n| inner | The inner CoderType.     |\n| b     | The base coder to apply. |\n\n```js\nimport { hex } from '@scure/base';\nconst hex = P.apply(P.bytes(32), hex); // will decode bytes into a hex string\n```\n\n### P.wrap\n\nWraps a stream encoder into a generic encoder and optionally validation function\n\n| Param | Description                                    |\n| ----- | ---------------------------------------------- |\n| inner | BytesCoderStream \u0026 { validate?: Validate\u003cT\u003e }. |\n\n```js\nconst U8 = P.wrap({\n  encodeStream: (w: Writer, value: number) =\u003e w.byte(value),\n  decodeStream: (r: Reader): number =\u003e r.byte()\n});\n\nconst checkedU8 = P.wrap({\n  encodeStream: (w: Writer, value: number) =\u003e w.byte(value),\n  decodeStream: (r: Reader): number =\u003e r.byte()\n  validate: (n: number) =\u003e {\n   if (n \u003e 10) throw new Error(`${n} \u003e 10`);\n   return n;\n  }\n});\n```\n\n### P.lazy\n\nLazy CoderType that is evaluated at runtime.\n\n**Returns**: CoderType representing the lazy value.\n\n| Param | Description                            |\n| ----- | -------------------------------------- |\n| fn    | A function that returns the CoderType. |\n\n```js\ntype Tree = { name: string; children: Tree[] };\nconst tree = P.struct({\n  name: P.cstring,\n  children: P.array(\n    P.U16BE,\n    P.lazy((): P.CoderType\u003cTree\u003e =\u003e tree)\n  ),\n});\n```\n\n## Bit fiddling\n\nBit fiddling is implementing using primitive called Bitset: a small structure to store position of ranges that have been read.\nCan be more efficient when internal trees are utilized at the cost of complexity.\nNeeds `O(N/8)` memory for parsing.\nPurpose: if there are pointers in parsed structure,\nthey can cause read of two distinct ranges:\n[0-32, 64-128], which means 'pos' is not enough to handle them\n\n### P.bits\n\nCoderType for parsing individual bits.\nNOTE: Structure should parse whole amount of bytes before it can start parsing byte-level elements.\n\n**Returns**: CoderType representing the parsed bits.\n\n| Param | Description              |\n| ----- | ------------------------ |\n| len   | Number of bits to parse. |\n\n```js\nconst s = P.struct({ magic: P.bits(1), version: P.bits(1), tag: P.bits(4), len: P.bits(2) });\n```\n\n### P.bitset\n\nBitset of boolean values with optional padding.\n\n**Returns**: CoderType representing the bitset.\n\n| Param | Description                                        |\n| ----- | -------------------------------------------------- |\n| names | An array of string names for the bitset values.    |\n| pad   | Whether to pad the bitset to a multiple of 8 bits. |\n\n```js\nconst myBitset = P.bitset(['flag1', 'flag2', 'flag3', 'flag4'], true);\n```\n\n## utils\n\n#### P.validate\n\nValidates a value before encoding and after decoding using a provided function.\n\n**Returns**: CoderType which check value with validation function.\n\n| Param | Description              |\n| ----- | ------------------------ |\n| inner | The inner CoderType.     |\n| fn    | The validation function. |\n\n```js\nconst val = (n: number) =\u003e {\n  if (n \u003e 10) throw new Error(`${n} \u003e 10`);\n  return n;\n};\n\nconst RangedInt = P.validate(P.U32LE, val); // Will check if value is \u003c= 10 during encoding and decoding\n```\n\n#### coders.dict\n\nBase coder for working with dictionaries (records, objects, key-value map)\nDictionary is dynamic type like: `[key: string, value: any][]`\n\n**Returns**: base coder that encodes/decodes between arrays of key-value tuples and dictionaries.\n\n```js\nconst dict: P.CoderType\u003cRecord\u003cstring, number\u003e\u003e = P.apply(\n P.array(P.U16BE, P.tuple([P.cstring, P.U32LE] as const)),\n P.coders.dict()\n);\n```\n\n#### coders.decimal\n\nBase coder for working with decimal numbers.\n\n**Returns**: base coder that encodes/decodes between bigints and decimal strings.\n\n| Param     | Default            | Description                                                            |\n| --------- | ------------------ | ---------------------------------------------------------------------- |\n| precision |                    | Number of decimal places.                                              |\n| round     | \u003ccode\u003efalse\u003c/code\u003e | Round fraction part if bigger than precision (throws error by default) |\n\n```js\nconst decimal8 = P.coders.decimal(8);\ndecimal8.encode(630880845n); // '6.30880845'\ndecimal8.decode('6.30880845'); // 630880845n\n```\n\n#### coders.match\n\nCombines multiple coders into a single coder, allowing conditional encoding/decoding based on input.\nActs as a parser combinator, splitting complex conditional coders into smaller parts.\n\n`encode = [Ae, Be]; decode = [Ad, Bd]`\n-\u003e\n`match([{encode: Ae, decode: Ad}, {encode: Be; decode: Bd}])`\n\n**Returns**: Combined coder for conditional encoding/decoding.\n\n| Param | Description               |\n| ----- | ------------------------- |\n| lst   | Array of coders to match. |\n\n#### coders.reverse\n\nReverses direction of coder\n\n## Debugger\n\nThere is a second optional module for debugging into console.\n\n```ts\nimport * as P from 'micro-packed';\nimport * as PD from 'micro-packed/debugger';\n\nconst debugInt = PD.debug(P.U32LE); // Will print info to console\n// PD.decode(\u003ccoder\u003e, data);\n// PD.diff(\u003ccoder\u003e, actual, expected);\n```\n\n![Decode](./test/screens/decode.png)\n\n![Diff](./test/screens/diff.png)\n\n## License\n\nMIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.\n","funding_links":["https://github.com/sponsors/paulmillr"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fmicro-packed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulmillr%2Fmicro-packed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fmicro-packed/lists"}