A no_std Rust library providing stack-allocated integer types of any byte width (uint<3>, int<5>, uint<10>, and so on) alongside familiar aliases like u24, i40, and u80.
Standard Rust gives you u8 through u128. exint fills every gap in between and beyond with types that behave like built-in integers: they implement the same traits, support the same operations, and work in const contexts.
Protocols, file formats, and hardware registers rarely align to powers of two. Rather than masking a u32 and hoping every call site remembers, uint<3> makes the 24-bit width part of the type system.
Under the hood, exint maps each width to an optimized code path: standard sizes (1|2|4|8|16 bytes) use native primitives directly, non-standard sizes (3|5|6|7|9..15 bytes) widen to the next primitive with LLVM-recognized narrowing patterns, and arbitrary sizes fall back to portable limb-based algorithms. The result is that u24::wrapping_add compiles to an add i24 in LLVM IR, not a u32 add with a manual mask.
use exint::primitive::u24;
fn main() {
let one: u24 = u24::from(1_u8);
let two: u24 = u24::from(2_u8);
assert_eq!(u24::MIN, u24::MAX.wrapping_add(one));
assert_eq!(u24::MAX, u24::try_from(16777215_u32).unwrap());
assert_eq!(u24::MAX / two, u24::MAX >> 1_u32);
}- Signed (
int<N>) and unsigned (uint<N>) types for any byte width - Convenient aliases:
u24,u40,i48,u80, ... no_stdcompatible, zero dependencies- Fully
const-evaluable - Compile-time specialization targeting ideal LLVM IR per width
- Literal macro support (
exint::uint!,exint::uint_strict!)
exint provides a simple procedural macro to simplify working with literal values.
The above example can be re-written as:
use exint::primitive::u24;
fn main() {
exint::uint! {
assert_eq!(u24::MIN, u24::MAX.wrapping_add(1_u24));
assert_eq!(u24::MAX, 16777215_u24);
assert_eq!(u24::MAX / 2_u24, u24::MAX >> 1_u32);
}
}Use the exint::uint_strict! macro to avoid converting the core integer types.
use exint::uint;
fn main() {
exint::uint! {
let a: uint<3> = 123_u24; // <-- Converted
let b: uint<4> = 456_u32; // <-- Converted
}
exint::uint_strict! {
let a: uint<3> = 123_u24; // <-- Converted
let b: u32 = 456_u32; // <-- Not converted
}
}This crate is not intended for cryptographic use. Consider using crypto-bigint if you need an integer type suitable for cryptographic applications.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.