IntersectMBO / IntersectMBO/evolution-sdk

[Tangent] Eliminate duplicate WithLength decoder family in CBOR.ts

Open
#159 1 comment 0 reactions 0 assignees View on GitHub
exploration
Dominant language
TypeScript
Stars
22
Forks
30
Avg merge
5h 29m
Merged PRs (30d)
12

Description

## What was discovered
CBOR.ts has two complete decoder implementations side-by-side: an offset-based family (\`decodeItemAt\`, \`decodeBytesAt\`, \`decodeArrayAt\`, …) and a slice-based family (\`decodeItemWithLengthSync\`, \`decodeBytesWithLengthSync\`, \`decodeArrayWithLengthSync\`, …). The slice-based family calls \`data.slice(offset)\` at every recursion, allocating a new \`Uint8Array\` for each nested item.

## Surfaced during
CBOR module review while preparing the \`bounded_bytes\` / \`BoundedBytes\` fix (PR for Conway CDDL compliance). Found during full read of CBOR.ts decoder section (~lines 1600–1900).

## Why it's worth exploring
For deeply nested PlutusData (constr with 5 levels, many fields), the slice-based path allocates hundreds of \`Uint8Array\` copies. The offset-based family is strictly better — it threads an integer offset through the call chain with zero allocation overhead. The two families are functionally equivalent. Deleting the \`WithLength\` family and routing its callers to the offset-based one removes ~200 lines and eliminates the O(n²) allocation pattern.

## What would be needed
1. Identify all callers of the \`WithLength\` family inside CBOR.ts
2. Route them to the offset-based equivalents (\`decodeItemAt\` etc.)
3. Delete the \`WithLength\` family
4. Run the full CBOR test suite (968 tests) to confirm no regression
5. Benchmark with a deeply nested PlutusData value to quantify the win (optional but useful)

## Context snapshot
Relevant section: \`packages/evolution/src/CBOR.ts\` ~lines 1600–1900.

The slice-based family:
\`\`\`typescript
const decodeItemWithLengthSync = (data: Uint8Array, options: CodecOptions): { item: CBOR; bytesConsumed: number } => {
// ... dispatches to decodeBytesWithLengthSync, decodeArrayWithLengthSync, etc.
// Each calls data.slice(offset) before recursing — one allocation per node
}
\`\`\`

The offset-based family (keeper):
\`\`\`typescript
const decodeItemAt = (data: Uint8Array, offset: number, options: CodecOptions): DecodeAtResult => {
// ... threads offset integer — zero allocation
}
\`\`\`
Both produce identical decoded values. The \`WithLength\` family exists as a legacy parallel path and has no unique capabilities the offset family lacks.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.