reweb3-num 0.2.4

Arbitrary precision, fixed-size signed and unsigned integer types for ethereum, this a fork of bnum crate.
Documentation
macro_rules! digit_module {
    ($Digit: ident, $SignedDigit: ty, $DoubleDigit: ty) => {
        pub mod $Digit {
            mod types {
                pub type Digit = $Digit;

                pub type SignedDigit = $SignedDigit;

                pub type DoubleDigit = $DoubleDigit;
            }

            use crate::ExpType;

            pub use types::*;

            pub const BITS: ExpType = $Digit::BITS as ExpType;

            pub const BITS_U8: u8 = BITS as u8;

            pub const BITS_MINUS_1: ExpType = BITS - 1;

            pub const BYTES: ExpType = BITS / 8;

            // This calculates log2 of BYTES as BYTES is guaranteed to only have one '1' bit, since it must be a power of two.
            pub const BYTE_SHIFT: ExpType = BYTES.trailing_zeros() as ExpType;

            pub const BIT_SHIFT: ExpType = BITS.trailing_zeros() as ExpType;

            #[inline]
            pub const fn to_double_digit(low: Digit, high: Digit) -> DoubleDigit {
                ((high as DoubleDigit) << BITS) | low as DoubleDigit
            }

            // TODO: these will no longer be necessary once const_bigint_helper_methods is stabilised: https://github.com/rust-lang/rust/issues/85532

            #[inline]
            pub const fn carrying_add(a: Digit, b: Digit, carry: bool) -> (Digit, bool) {
                let (s1, o1) = a.overflowing_add(b);
                if carry {
                    let (s2, o2) = s1.overflowing_add(1);
                    (s2, o1 || o2)
                } else {
                    (s1, o1)
                }
            }

            #[inline]
            pub const fn borrowing_sub(a: Digit, b: Digit, borrow: bool) -> (Digit, bool) {
                let (s1, o1) = a.overflowing_sub(b);
                if borrow {
                    let (s2, o2) = s1.overflowing_sub(1);
                    (s2, o1 || o2)
                } else {
                    (s1, o1)
                }
            }

            #[inline]
            pub const fn carrying_add_signed(
                a: SignedDigit,
                b: SignedDigit,
                carry: bool,
            ) -> (SignedDigit, bool) {
                let (s1, o1) = a.overflowing_add(b);
                if carry {
                    let (s2, o2) = s1.overflowing_add(1);
                    (s2, o1 != o2)
                } else {
                    (s1, o1)
                }
            }

            #[inline]
            pub const fn borrowing_sub_signed(
                a: SignedDigit,
                b: SignedDigit,
                borrow: bool,
            ) -> (SignedDigit, bool) {
                let (s1, o1) = a.overflowing_sub(b);
                if borrow {
                    let (s2, o2) = s1.overflowing_sub(1);
                    (s2, o1 != o2)
                } else {
                    (s1, o1)
                }
            }

            #[inline]
            pub const fn widening_mul(a: Digit, b: Digit) -> (Digit, Digit) {
                let prod = a as DoubleDigit * b as DoubleDigit;
                (prod as Digit, (prod >> BITS) as Digit)
            }

            #[inline]
            pub const fn carrying_mul(
                a: Digit,
                b: Digit,
                carry: Digit,
                current: Digit,
            ) -> (Digit, Digit) {
                let prod = carry as DoubleDigit
                    + current as DoubleDigit
                    + (a as DoubleDigit) * (b as DoubleDigit);
                (prod as Digit, (prod >> BITS) as Digit)
            }

            #[inline]
            pub const fn div_rem_wide(low: Digit, high: Digit, rhs: Digit) -> (Digit, Digit) {
                debug_assert!(high < rhs);

                let a = to_double_digit(low, high);
                (
                    (a / rhs as DoubleDigit) as Digit,
                    (a % rhs as DoubleDigit) as Digit,
                )
            }

            pub const HEX_PADDING: usize = BITS as usize / 4;
        }
    };
}

digit_module!(u8, i8, u16);
digit_module!(u16, i16, u32);
digit_module!(u32, i32, u64);
digit_module!(u64, i64, u128);