use num_traits::{Bounded, NumCast, ToPrimitive};
use crate::core_type::I128;
impl<const SCALE: u32> I128<SCALE> {
pub fn from_num<T: ToPrimitive>(value: T) -> Self {
let int_signal = value.to_i128();
let uint_signal = value.to_u128();
let float_signal = if int_signal.is_none() && uint_signal.is_none() {
value.to_f64()
} else {
None
};
if let Some(f) = float_signal {
if f.is_nan() {
return Self::ZERO;
}
}
if let Some(d) = <Self as NumCast>::from(value) {
return d;
}
if let Some(i) = int_signal {
return if i < 0 { Self::MIN } else { Self::MAX };
}
if uint_signal.is_some() {
return Self::MAX;
}
match float_signal {
Some(f) if f.is_sign_negative() => Self::MIN,
Some(_) => Self::MAX,
None => Self::ZERO,
}
}
pub fn to_num<T: NumCast + Bounded>(self) -> T {
match T::from(self) {
Some(t) => t,
None => {
if self.0 >= 0 {
T::max_value()
} else {
T::min_value()
}
}
}
}
}
#[cfg(test)]
mod tests {
use crate::core_type::{I128, I128s12};
#[test]
fn from_num_i32_round_trip() {
let d = I128s12::from_num(42_i32);
assert_eq!(d, I128s12::from(42_i32));
assert_eq!(d.to_num::<i32>(), 42_i32);
}
#[test]
fn from_num_i64_matches_from() {
let d = I128s12::from_num(1_000_i64);
assert_eq!(d, I128s12::from(1_000_i64));
}
#[test]
fn from_num_f64_within_range() {
let d = I128s12::from_num(1.5_f64);
assert_eq!(d, I128s12::from_f64_lossy(1.5_f64));
}
#[test]
fn from_num_f64_inf_saturates_max() {
assert_eq!(I128s12::from_num(f64::INFINITY), I128s12::MAX);
}
#[test]
fn from_num_f64_neg_inf_saturates_min() {
assert_eq!(I128s12::from_num(f64::NEG_INFINITY), I128s12::MIN);
}
#[test]
fn from_num_f64_nan_is_zero() {
assert_eq!(I128s12::from_num(f64::NAN), I128s12::ZERO);
}
#[test]
fn from_num_f64_finite_oor_saturates() {
assert_eq!(I128s12::from_num(1e30_f64), I128s12::MAX);
assert_eq!(I128s12::from_num(-1e30_f64), I128s12::MIN);
}
#[test]
fn from_num_f32_inf_saturates() {
assert_eq!(I128s12::from_num(f32::INFINITY), I128s12::MAX);
assert_eq!(I128s12::from_num(f32::NEG_INFINITY), I128s12::MIN);
assert_eq!(I128s12::from_num(f32::NAN), I128s12::ZERO);
}
#[test]
fn from_num_does_not_panic_on_wider_range_than_i64f64() {
let v: i64 = 10_000_000_000_i64;
let d = I128s12::from_num(v);
assert_eq!(d.to_int_lossy(), v);
}
#[test]
fn to_num_f64_lossy() {
assert_eq!(I128s12::ONE.to_num::<f64>(), 1.0_f64);
assert_eq!((-I128s12::ONE).to_num::<f64>(), -1.0_f64);
assert_eq!(I128s12::ZERO.to_num::<f64>(), 0.0_f64);
}
#[test]
fn to_num_f32_lossy() {
assert_eq!(I128s12::ONE.to_num::<f32>(), 1.0_f32);
assert_eq!((-I128s12::ONE).to_num::<f32>(), -1.0_f32);
}
#[test]
fn to_num_i32_in_range() {
let d = I128s12::from(42_i32);
assert_eq!(d.to_num::<i32>(), 42_i32);
let neg = I128s12::from(-42_i32);
assert_eq!(neg.to_num::<i32>(), -42_i32);
}
#[test]
fn to_num_i32_out_of_range_saturates_max() {
assert_eq!(I128s12::MAX.to_num::<i32>(), i32::MAX);
}
#[test]
fn to_num_i32_out_of_range_saturates_min() {
assert_eq!(I128s12::MIN.to_num::<i32>(), i32::MIN);
}
#[test]
fn to_num_i64_saturates() {
assert_eq!(I128s12::MAX.to_num::<i64>(), i64::MAX);
assert_eq!(I128s12::MIN.to_num::<i64>(), i64::MIN);
assert_eq!(I128s12::from(42_i64).to_num::<i64>(), 42_i64);
}
#[test]
fn to_num_u32_negative_saturates_to_zero() {
assert_eq!((-I128s12::ONE).to_num::<u32>(), u32::MIN);
assert_eq!(I128s12::MIN.to_num::<u32>(), u32::MIN);
assert_eq!(I128s12::MAX.to_num::<u32>(), u32::MAX);
}
#[test]
fn from_num_to_num_round_trip_i32() {
for v in [0_i32, 1, -1, 42, -42, 1_000_000, -1_000_000] {
let d = I128s12::from_num(v);
assert_eq!(d.to_num::<i32>(), v);
}
}
#[test]
fn from_num_to_num_at_scale_6() {
type D6 = I128<6>;
let d = D6::from_num(7_i32);
assert_eq!(d, D6::from(7_i32));
assert_eq!(d.to_num::<i32>(), 7_i32);
}
#[test]
fn from_num_i128_max_saturates_via_int_signal() {
assert_eq!(I128s12::from_num(i128::MAX), I128s12::MAX);
}
#[test]
fn from_num_i128_min_saturates_via_int_signal() {
assert_eq!(I128s12::from_num(i128::MIN), I128s12::MIN);
}
#[test]
fn from_num_u128_max_saturates_via_uint_signal() {
assert_eq!(I128s12::from_num(u128::MAX), I128s12::MAX);
}
#[test]
fn from_num_u64_max_succeeds_without_saturation() {
let d = I128s12::from_num(u64::MAX);
assert_eq!(d, I128s12::from(u64::MAX));
}
}