use num_traits::ToPrimitive;
use crate::i256;
pub trait ToI256 {
fn to_i256(&self) -> Option<i256>;
}
macro_rules! impl_toprimitive_lossless {
($T:ty) => {
impl ToI256 for $T {
#[inline]
fn to_i256(&self) -> Option<i256> {
Some(i256::from_i128(*self as i128))
}
}
};
}
impl_toprimitive_lossless!(u8);
impl_toprimitive_lossless!(u16);
impl_toprimitive_lossless!(u32);
impl_toprimitive_lossless!(u64);
impl_toprimitive_lossless!(i8);
impl_toprimitive_lossless!(i16);
impl_toprimitive_lossless!(i32);
impl_toprimitive_lossless!(i64);
impl_toprimitive_lossless!(i128);
impl ToI256 for u128 {
fn to_i256(&self) -> Option<i256> {
Some(i256::from_parts(*self, 0))
}
}
impl ToI256 for i256 {
fn to_i256(&self) -> Option<i256> {
Some(*self)
}
}
pub trait BigCast: Sized + ToPrimitive + ToI256 {
fn from<T: ToPrimitive + ToI256>(n: T) -> Option<Self>;
}
macro_rules! impl_big_cast {
($T:ty, $conv:ident) => {
impl BigCast for $T {
fn from<T: ToPrimitive + ToI256>(n: T) -> Option<Self> {
n.$conv()
}
}
};
}
impl_big_cast!(u8, to_u8);
impl_big_cast!(u16, to_u16);
impl_big_cast!(u32, to_u32);
impl_big_cast!(u64, to_u64);
impl_big_cast!(u128, to_u128);
impl_big_cast!(i8, to_i8);
impl_big_cast!(i16, to_i16);
impl_big_cast!(i32, to_i32);
impl_big_cast!(i64, to_i64);
impl_big_cast!(i128, to_i128);
impl_big_cast!(i256, to_i256);
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use rstest::rstest;
use super::*;
#[rstest]
#[case(u8::MAX)]
#[case(u16::MAX)]
#[case(u32::MAX)]
#[case(u64::MAX)]
#[case(u128::MAX)]
#[case(i8::MAX)]
#[case(i16::MAX)]
#[case(i32::MAX)]
#[case(i64::MAX)]
#[case(i128::MAX)]
#[case(i256::MAX)]
fn test_big_cast_identity<T: BigCast + Eq + Debug + Copy>(#[case] n: T) {
assert_eq!(<T as BigCast>::from(n).unwrap(), n);
}
macro_rules! test_big_cast_overflow {
($name:ident, $src:ty => $dst:ty, $max:expr, $one:expr) => {
#[test]
fn $name() {
let v = <$dst as BigCast>::from($max).unwrap();
assert_eq!(<$src as BigCast>::from(v), Some($max));
let v = v + $one;
assert_eq!(<$src as BigCast>::from(v), None);
}
};
}
test_big_cast_overflow!(test_i8_overflow, i8 => i16, i8::MAX, 1i16);
test_big_cast_overflow!(test_i16_overflow, i16 => i32, i16::MAX, 1i32);
test_big_cast_overflow!(test_i32_overflow, i32 => i64, i32::MAX, 1i64);
test_big_cast_overflow!(test_i64_overflow, i64 => i128, i64::MAX, 1i128);
test_big_cast_overflow!(test_i128_overflow, i128 => i256, i128::MAX, i256::ONE);
test_big_cast_overflow!(test_u8_overflow, u8 => u16, u8::MAX, 1u16);
test_big_cast_overflow!(test_u16_overflow, u16 => u32, u16::MAX, 1u32);
test_big_cast_overflow!(test_u32_overflow, u32 => u64, u32::MAX, 1u64);
test_big_cast_overflow!(test_u64_overflow, u64 => u128, u64::MAX, 1u128);
}