safe-bigmath
Safe, non-panicking numeric primitives built on pure-Rust num-bigint. safe-bigmath gives you:
SafeInt: arbitrary-precision integers with ergonomic operator overloads.SafeDec<D>: fixed-scale decimals backed by arbitrary-precisionSafeInt; the const genericDsets how many decimal places are stored exactly.- Parsing helpers for turning strings into safe numeric values.
- No hidden panics: division returns
Option, parsing reports structured errors. stdby default; disable default features forno_std+alloc(works onwasm32-unknown-unknown).- Extremely efficient binary wire format and encoding/decoding provided by a custom lencode implementation
- Only possible way this library can panic is if the host runs out of memory, which would take some truly large numbers
Quick start
[]
= "0.2"
# Optional: go `no_std` + `alloc`
# safe-bigmath = { version = "0.2", default-features = false }
Safe integers
use SafeInt;
let a = from;
let b = from;
assert_eq!; // division is fallible
assert_eq!;
assert_eq!; // no panic on zero div
Fixed-scale decimals
use SafeDec;
let price: = "12.50".parse.unwrap;
let qty: = "3.00".parse.unwrap;
let total = price * qty;
assert_eq!;
Pow of ratios with scaling
Compute (x / (x + dx))^(w1 / w2) scaled to perquintill:
use SafeInt;
let x = from;
let dx = from;
let w1 = from;
let w2 = from;
let perquintill = from;
let result = pow_ratio_scaled.unwrap;
assert_eq!;
Feature flags
std(on by default): enablesstdsupport for downstream crates; disable default features forno_std+alloc.
Lencode encoding/decoding
SafeInt and SafeDec<D> implement lencode::Encode and lencode::Decode. The format is
stable and no_std-friendly, and always uses little-endian byte order for the payload.
SafeInt encoding is zigzag over the signed magnitude, then a compact header:
- Header byte layout (from MSB to LSB):
V S LLLLLLV(bit 7): variant.0= varint path,1= bytes path.S(bit 6): size mode (varint path only).0= small (value fits in 6 bits),1= large (nextLbytes are the little-endian payload).L(bits 0..5): whenS=0, the value itself; whenS=1, the payload length in bytes.
- Varint path (V=0):
- Small: one byte total, supports zigzag values in
[0, 63]. - Large:
1 + Lbytes total, supports zigzag payloads up to 63 bytes.
- Small: one byte total, supports zigzag values in
- Bytes path (V=1):
- Encodes the zigzag payload as
Vec<u8>using lencode (varint length + payload, with optional compression), allowing arbitrary magnitudes.
- Encodes the zigzag payload as
Range note: the varint path covers signed values in [-2^503, 2^503 - 1]. Larger magnitudes
use the bytes path automatically.
Approximate sizes for common ranges (zigzag is the unsigned value after zigzag encoding):
| SafeInt range (inclusive) | Zigzag range | Encoding | Total bytes |
|---|---|---|---|
| -32..31 | 0..63 | varint small | 1 |
| -128..-33, 32..127 | 64..255 | varint L=1 | 2 |
| -32_768..-129, 128..32_767 | 256..65_535 | varint L=2 | 3 |
| -8_388_608..-32_769, 32_768..8_388_607 | 65_536..16_777_215 | varint L=3 | 4 |
| -2_147_483_648..-8_388_609, 8_388_608..2_147_483_647 | 16_777_216..4_294_967_295 | varint L=4 | 5 |
| ... | ... | varint L=5..63 | 6..64 |
| n | >= 2^503 | zigzag payload >63 bytes |
SafeDec<D> encodes exactly like its underlying scaled SafeInt (the raw integer at scale D).
Supported targets
stdtargets (default).no_stdtargets withallocvia--no-default-features.wasm32-unknown-unknown(CI builds and test-compiles both--no-default-featuresand--all-features).
Testing
License
MIT © sam0x17