numeric_cast 0.3.0

Safely cast between numbers
Documentation
#[inline(always)]
#[must_use]
pub fn truncating_cast<X, Y>(x: X) -> Y
where
    Y: TruncatingCastFrom<X>,
{
    Y::truncating_cast_from(x)
}

pub trait TruncatingCast: Sized {
    #[inline(always)]
    #[must_use]
    fn truncating_cast<T: TruncatingCastFrom<Self>>(self) -> T {
        T::truncating_cast_from(self)
    }
}

macro_rules! impl_truncating_cast {
($($t:ty,)*) => {
    $(
        impl TruncatingCast for $t {}
    )*
};
}

impl_truncating_cast!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize,);

pub trait TruncatingCastFrom<T>: Sized {
    fn truncating_cast_from(val: T) -> Self;
}

macro_rules! truncating_cast {
    ($lhs: ty=>$rhs:ty) => {
        impl TruncatingCastFrom<$lhs> for $rhs {
            #[inline(always)]
            #[must_use]
            fn truncating_cast_from(val: $lhs) -> $rhs {
                val as $rhs
            }
        }
    };
}

truncating_cast!(u16  => u8  );
truncating_cast!(u32  => u8  );
truncating_cast!(u64  => u8  );
truncating_cast!(u128 => u8  );
truncating_cast!(u32  => u16 );
truncating_cast!(u64  => u16 );
truncating_cast!(u128 => u16 );
truncating_cast!(u64  => u32 );
truncating_cast!(u128 => u32 );
truncating_cast!(u128 => u64 );

truncating_cast!(usize => u8    );
truncating_cast!(usize => u16   );
truncating_cast!(usize => u32   );
truncating_cast!(u32   => usize );
truncating_cast!(u64   => usize );
truncating_cast!(u128  => usize );

truncating_cast!(i16  => i8  );
truncating_cast!(i32  => i8  );
truncating_cast!(i64  => i8  );
truncating_cast!(i128 => i8  );
truncating_cast!(i32  => i16 );
truncating_cast!(i64  => i16 );
truncating_cast!(i128 => i16 );
truncating_cast!(i64  => i32 );
truncating_cast!(i128 => i32 );
truncating_cast!(i128 => i64 );

truncating_cast!(isize => i8    );
truncating_cast!(isize => i16   );
truncating_cast!(isize => i32   );
truncating_cast!(i32   => isize );
truncating_cast!(i64   => isize );
truncating_cast!(i128  => isize );

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn truncating() {
        let x: i16 = -1;
        let y: i8 = truncating_cast(x);
        assert_eq!(y, -1);

        let y: u8 = 256u32.truncating_cast();
        assert_eq!(y, 0);

        let y = 257u16.truncating_cast::<u8>();
        assert_eq!(y, 1);
    }
}