Skip to main content

Module heapless

Module heapless 

Source
Expand description

Fixed-capacity, runtime-length unsigned bignum. See the module header. Unsigned integer whose width is chosen at runtime, not by the type.

A HeaplessBigInt<T, CAP> carried at len = k is a k-word integer and behaves bit-for-bit like FixedUInt<T, k>: arithmetic wraps, << truncates, and overflow is reported at the value’s width — it is not a growable bignum. The only difference from FixedUInt is that the width is len, a runtime (public) shape parameter, rather than the const N. You pick len at construction the way you pick N; CAP is only the storage ceiling (len <= CAP), invisible to arithmetic. Every op iterates 0..self.len, never 0..CAP. Same Personality typestate (Nct / Ct) and T: MachineWord bound as FixedUInt.

Because the width is len, a value must be constructed at its intended width: zero() / one() / short decodes are minimal-width, so anywhere the operating width matters (accumulators, field elements, reduction targets) pin it from a witness with WithPrecision — e.g. zero_with_precision_of(&modulus) — rather than seeding from an identity and letting it silently run narrow.

§Width contract

Every operation resolves at the value width len·word_bits and returns bit-for-bit what the same-width FixedUInt would — no op grows past max(operand len) or narrows the magnitude, and CAP never enters a result. The result len of each op:

operationresult len
wrapping/overflowing/checked add·sub·mul, + - *max(a.len, b.len)
Shl (<<), overflowing/wrapping/checked/unbounded/exact shl, FunnelShlself.len — high bits past the width are discarded
Shr (>>), overflowing/wrapping/checked/unbounded/exact shr, FunnelShrself.len minus the whole-word shift
WideMul / CarryingMullo and hi each max(a.len, b.len); reconstruct hi·2^(W·word_bits) + lo
Div (/), Rem (%)max(dividend.len, divisor.len)
BitAnd (&), BitOr, BitXormax(a.len, b.len)
NextPowerOfTwo next/checked/wrappingself.lenone is widened before the shift
NextMultipleOf next/checkedmax(self.len, rhs.len) (via % and +)
Isqrt, Roots::nth_rootself.len — estimate seeded at the operand width
Ilog2 / Ilog10 / Ilogreturns u32 — no result width
HighestOne / LowestOnereturns Option<u32> — no result width
IsolateHighestOne / IsolateLowestOneself.len — the single-bit mask carries the operand width
DepositBits / ExtractBitsmax(self.len, mask.len)
Sum / Productmax(operand len); empty iterator yields the minimal-width identity
widened / WithPrecisionthe requested width (grow-only)

§Construction & serialization widths

Constructors and byte I/O carry different widths for the same value — there is no single “natural” one for a runtime carrier. When the width matters, pick the row you mean, or pin afterward with WithPrecision:

pathwidth
From<u8/u16/u32/u64>ceil(size_of::<uN>() / word) — the source int’s width
inherent from_le_bytes / from_be_bytes(&[u8])ceil(slice.len() / word) — the slice width
new_zero_with_len / from_limbsexactly the given len
FromBytes trait (BytesHolder<T, CAP>)CAP — an owned holder can’t be runtime-sized
inherent to_le_bytes / to_be_bytes(&mut [u8])value width (len·word bytes)
ToBytes trait (BytesHolder<T, CAP>)CAP — same reason

The trait (ToBytes/FromBytes) paths are capacity-width because their owned Bytes associated type is fixed-size — the intended shape for a full-precision operand (a modulus with len == CAP) and for round-tripping against FixedUInt<T, CAP>. For value-width bytes use the inherent methods.

Structs§

HeaplessBigInt
A len-word unsigned integer whose width is chosen at runtime.
NonZeroHeaplessBigInt
Non-zero HeaplessBigInt. Constructed via HasNonZero::into_nonzero.