reweb3-num 0.2.4

Arbitrary precision, fixed-size signed and unsigned integer types for ethereum, this a fork of bnum crate.
Documentation
use crate::ExpType;
use crate::cast::CastFrom;

pub trait Mantissa: Sized {
    const ZERO: Self;
    
    fn checked_shr(self, n: ExpType) -> Option<Self>;
    fn bits(&self) -> ExpType;
}

pub trait Exponent {
    fn is_negative(&self) -> bool;
    fn neg(self) -> Self;
}

pub trait CastUintFromFloatConsts {
    const ZERO: Self;
    const MIN: Self;
    const MAX: Self;
    const BITS: ExpType;

    fn shl(self, n: ExpType) -> Self;
}

pub trait CastUintFromFloatHelper: CastFrom<Self::M> {
    type M: Mantissa;
    type E: Exponent;

    fn is_nan(&self) -> bool;
    fn is_sign_negative(&self) -> bool;
    fn is_infinite(&self) -> bool;
    fn decode(self) -> (Self::M, Self::E);
}

macro_rules! cast_uint_from_float_consts {
    ($($uint: ident), *) => {
        $(
            impl CastUintFromFloatConsts for $uint {
                const ZERO: Self = 0;
                const MIN: Self = Self::MIN;
                const MAX: Self = Self::MAX;
                const BITS: ExpType = Self::BITS;
            
                fn shl(self, n: ExpType) -> Self {
                    self << n
                }
            }
        )*
    };
}

pub(crate) use cast_uint_from_float_consts;

macro_rules! as_float {
    ($BUint: ident, $BInt: ident, $Digit: ident) => {
        impl<const N: usize> Mantissa for $BUint<N> {
            const ZERO: Self = Self::ZERO;
        
            #[inline]
            fn checked_shr(self, n: ExpType) -> Option<Self> {
                Self::checked_shr(self, n)
            }
        
            #[inline]
            fn bits(&self) -> ExpType {
                Self::bits(&self)
            }
        }
        
        impl<const N: usize> Exponent for $BInt<N> {
            #[inline]
            fn is_negative(&self) -> bool {
                Self::is_negative(*self)
            }
        
            #[inline]
            fn neg(self) -> Self {
                Self::neg(self)
            }
        }
        
        impl<const N: usize> CastUintFromFloatConsts for $BUint<N> {
            const ZERO: Self = Self::ZERO;
            const MIN: Self = Self::MIN;
            const MAX: Self = Self::MAX;
            const BITS: ExpType = Self::BITS;
        
            fn shl(self, n: ExpType) -> Self {
                Self::shl(self, n)
            }
        }
    };
}

pub(crate) use as_float;

pub fn uint_cast_from_float<F, U>(f: F) -> U
where
    F: CastUintFromFloatHelper,
    U: CastUintFromFloatConsts + CastFrom<F::M>,
    ExpType: TryFrom<F::E>
{
    if f.is_nan() {
        return U::ZERO;
    }
    if f.is_sign_negative() {
        return U::MIN;
    }
    if f.is_infinite() {
        return U::MAX;
    }
    let (mut mant, exp) = f.decode();
    if exp.is_negative() {
        let r: Result<ExpType, _> = exp.neg().try_into();
        mant = match r {
            Ok(exp) => mant.checked_shr(exp).unwrap_or(<F::M>::ZERO),
            _ => <F::M>::ZERO,
        };
        if mant.bits() > U::BITS {
            return U::MAX;
        }
        U::cast_from(mant)
    } else {
        let exp: Result<ExpType, _> = exp.try_into();
        match exp {
            Ok(exp) => {
                if mant.bits() + exp > U::BITS {
                    return U::MAX;
                }
                U::cast_from(mant).shl(exp)
            },
            _ => U::MAX
        }
    }
}

crate::macro_impl!(as_float);

crate::buint::float_as::cast_uint_from_float_consts!(u8, u16, u32, u64, u128, usize);

macro_rules! impl_mantissa_for_uint {
    ($($uint: ty), *) => {
        $(
            impl Mantissa for $uint {
                const ZERO: Self = 0;

                #[inline]
                fn checked_shr(self, n: ExpType) -> Option<Self> {
                    self.checked_shr(n as u32)
                }

                #[inline]
                fn bits(&self) -> ExpType {
                    (Self::BITS - self.leading_zeros()) as ExpType
                }
            }
        )*
    }
}

impl_mantissa_for_uint!(u32, u64);

impl Exponent for i16 {
    #[inline]
    fn is_negative(&self) -> bool {
        Self::is_negative(*self)
    }

    #[inline]
    fn neg(self) -> Self {
        -self
    }
}

macro_rules! impl_cast_uint_from_primitive_float_helper {
    ($float: ty, $mant: ty, $exp: ty, $decoder: ident) => {
        impl CastUintFromFloatHelper for $float {
            type M = $mant;
            type E = $exp;

            #[inline]
            fn is_nan(&self) -> bool {
                Self::is_nan(*self)
            }

            #[inline]
            fn is_sign_negative(&self) -> bool {
                Self::is_sign_negative(*self)
            }

            #[inline]
            fn is_infinite(&self) -> bool {
                Self::is_infinite(*self)
            }

            #[inline]
            fn decode(self) -> (Self::M, Self::E) {
                crate::buint::cast::$decoder(self)
            }
        }
    };
}

impl_cast_uint_from_primitive_float_helper!(f32, u32, i16, decode_f32);
impl_cast_uint_from_primitive_float_helper!(f64, u64, i16, decode_f64);