/** * @pwngh/money * * Copyright (c) Preston Neal * * This source code is licensed under the MIT license found in the * LICENSE.md file in the root directory of this source tree. * * @license MIT * * Vendored from @pwngh/money@0.3.0 (src/fold.ts), reflowed to this repo's line * width; content otherwise identical. */ /** * Checked i64 balance folding in WebAssembly: the hot path beneath @pwngh/money, * shipped as its /fold subpath so the importer composes it in — the main entry never * loads it. Still a single-file amalgamation: zero imports, and no binary blob ships; * the module is assembled at load time by the * micro-assembler below, so the reviewable TypeScript stays the audit target — the * schema-as-string-constant rule applied to executable code. The WAT mirror * (`foldWat`) is the human-readable statement of the same instructions. * * Semantics, pinned by `vectors`: a left fold with overflow checked at every step * against i64 bounds. Order matters — an intermediate overflow traps even when the * final total would fit — because a balance fold that silently passes through an * unrepresentable intermediate state is not auditable. Traps surface as RangeError, * matching @pwngh/money arithmetic. * * Composes further than TypeScript source can: the same assembled module runs under * Node, browsers, Deno, Bun, and .NET or Unity via wasmtime. Emit it for those hosts: * * node -e 'import("./fold.js").then(m => process.stdout.write(m.moduleBytes()))' > fold.wasm * * UdonSharp remains the vectors-only boundary: Udon loads nothing, so Pwngh.Fold * reimplements against the same embedded conformance vectors. */ export declare const I64_MIN: bigint; export declare const I64_MAX: bigint; /** The module's instructions in WebAssembly text form: what the assembler below emits. */ export declare const foldWat = "(module\n (memory (export \"memory\") 1)\n (func (export \"fold\") (param $ptr i32) (param $len i32) (result i64)\n (local $sum i64) (local $v i64) (local $s i64) (local $end i32)\n local.get $ptr local.get $len i32.const 3 i32.shl i32.add local.set $end\n block $done\n loop $next\n local.get $ptr local.get $end i32.ge_u br_if $done\n local.get $ptr i64.load align=8 local.set $v\n local.get $sum local.get $v i64.add local.set $s\n local.get $sum local.get $s i64.xor\n local.get $v local.get $s i64.xor\n i64.and i64.const 0 i64.lt_s\n if unreachable end\n local.get $s local.set $sum\n local.get $ptr i32.const 8 i32.add local.set $ptr\n br $next\n end\n end\n local.get $sum))"; /** Assembles the fold module. Deterministic, 125 bytes, built fresh on each call. */ export declare function moduleBytes(): Uint8Array; /** * Reference implementation with identical semantics, in plain bigint. The slow, * obviously-correct half of the cross-check; also the fallback where WebAssembly * is unavailable. */ export declare function foldRef(values: Iterable): bigint; export interface Fold { fold(values: BigInt64Array | readonly bigint[]): bigint; view(count: number): BigInt64Array; } /** * Instantiates the module once and returns a folder that reuses its linear memory. * `view` hands the caller that memory directly: a column built in place folds with * zero copies, because the column IS the buffer the kernel reads. A grow detaches * earlier views, so take the view after sizing, not before. */ export declare function createFold(): Fold; /** Conformance vectors, JSON-safe. 'throws' marks folds that must trap. */ export type Vector = readonly ['fold', readonly string[], string | 'throws']; export declare const vectors: readonly Vector[]; /** * Runs every vector against both implementations, then cross-checks them on a * 65,537-element seeded LCG array (one past a wasm page of i64s, forcing a grow), * built through `view` so the zero-copy path is conformance-covered too. * Returns failures; empty means conformant. */ export declare function selfTest(): string[];