rinia 0.0.18

Stable numeric foundations for graphics, animation, and simulation.
Documentation
#![cfg(test)]

use alloc::vec::Vec;

use crate::numeric::{Cast, CastError, LossyCast, SaturatingCast, TryCast, TryExactCast};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Thin<T>(T);

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct ThickSingle<T> {
    pub value: T,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct ThickMulti<T> {
    pub value1: T,
    pub value2: T,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct ThickConst<T, const N: usize> {
    pub value1: T,
    pub value2: T,
}

crate::impl_numeric_casts_wrapper!(Thin<T>);

crate::impl_numeric_casts_wrapper!(ThickSingle<T>, [value]);

crate::impl_numeric_casts_wrapper!(ThickMulti<T>, [value1, value2]);

crate::impl_numeric_casts_wrapper!(
    [T, const N: usize],
    wrapper: ThickConst,
    ThickConst<T, N> => ThickConst<U, N>,
    item: T,
    fields: [value1, value2],
);

#[test]
fn transparent_casts_thin_inherent_surface() {
    let src = Thin(123_i32);

    assert_eq!(src.cast::<i64>(), Thin(123_i64));
    assert_eq!(Thin::<i64>::cast_from(src), Thin(123_i64));

    assert_eq!(src.lossy_cast::<u8>(), Thin(123_u8));
    assert_eq!(Thin::<u8>::lossy_cast_from(src), Thin(123_u8));

    assert_eq!(Thin(300_i32).saturating_cast::<u8>(), Thin(u8::MAX));
    assert_eq!(Thin::<u8>::saturating_cast_from(Thin(300_i32)), Thin(u8::MAX));

    assert_eq!(Thin(255_i32).try_cast::<u8>(), Ok(Thin(255_u8)));
    assert_eq!(Thin::<u8>::try_cast_from(Thin(255_i32)), Ok(Thin(255_u8)));
    assert_eq!(Thin(256_i32).try_cast::<u8>(), Err(CastError::OutOfRange));

    assert_eq!(Thin(42_i32).try_exact_cast::<i64>(), Ok(Thin(42_i64)));
    assert_eq!(Thin::<i64>::try_exact_cast_from(Thin(42_i32)), Ok(Thin(42_i64)));
    assert_eq!(Thin(1.5_f32).try_exact_cast::<i32>(), Err(CastError::Fractional));
}

#[test]
fn transparent_casts_thin_trait_surface() {
    let src = Thin(200_i32);

    let casted = <Thin<i32> as Cast<Thin<i64>>>::cast(src);
    assert_eq!(casted, Thin(200_i64));

    let lossy = <Thin<i32> as LossyCast<Thin<u8>>>::lossy_cast(src);
    assert_eq!(lossy, Thin(200_u8));

    let saturating = <Thin<i32> as SaturatingCast<Thin<u8>>>::saturating_cast(Thin(300_i32));
    assert_eq!(saturating, Thin(u8::MAX));

    let try_ok = <Thin<i32> as TryCast<Thin<u8>>>::try_cast(src);
    assert_eq!(try_ok, Ok(Thin(200_u8)));

    let try_err = <Thin<i32> as TryCast<Thin<u8>>>::try_cast(Thin(300_i32));
    assert_eq!(try_err, Err(CastError::OutOfRange));

    let try_exact_ok = <Thin<i32> as TryExactCast<Thin<i64>>>::try_exact_cast(Thin(7_i32));
    assert_eq!(try_exact_ok, Ok(Thin(7_i64)));

    let try_exact_err = <Thin<f32> as TryExactCast<Thin<i32>>>::try_exact_cast(Thin(2.25_f32));
    assert_eq!(try_exact_err, Err(CastError::Fractional));
}

#[test]
fn transparent_casts_thick_multi_inherent_surface() {
    let src = ThickMulti { value1: 100_i32, value2: 300_i32 };

    assert_eq!(src.cast::<i64>(), ThickMulti { value1: 100_i64, value2: 300_i64 });
    assert_eq!(ThickMulti::<i64>::cast_from(src), ThickMulti { value1: 100_i64, value2: 300_i64 });

    assert_eq!(src.lossy_cast::<u8>(), ThickMulti { value1: 100_u8, value2: 44_u8 });

    assert_eq!(
        ThickMulti::<u8>::lossy_cast_from(src),
        ThickMulti { value1: 100_u8, value2: 44_u8 }
    );

    assert_eq!(src.saturating_cast::<u8>(), ThickMulti { value1: 100_u8, value2: u8::MAX });

    assert_eq!(
        ThickMulti::<u8>::saturating_cast_from(src),
        ThickMulti { value1: 100_u8, value2: u8::MAX }
    );

    assert_eq!(
        ThickMulti { value1: 10_i32, value2: 255_i32 }.try_cast::<u8>(),
        Ok(ThickMulti { value1: 10_u8, value2: 255_u8 })
    );

    assert_eq!(
        ThickMulti::<u8>::try_cast_from(ThickMulti { value1: 10_i32, value2: 300_i32 }),
        Err(CastError::OutOfRange)
    );

    assert_eq!(
        ThickMulti::<i64>::try_exact_cast_from(ThickMulti { value1: 1_i32, value2: 2_i32 }),
        Ok(ThickMulti { value1: 1_i64, value2: 2_i64 })
    );
}

#[test]
fn transparent_casts_thick_multi_trait_surface() {
    let src = ThickMulti { value1: 7_i32, value2: 8_i32 };

    let casted = <ThickMulti<i32> as Cast<ThickMulti<i64>>>::cast(src);
    assert_eq!(casted, ThickMulti { value1: 7_i64, value2: 8_i64 });

    let lossy = <ThickMulti<i32> as LossyCast<ThickMulti<u8>>>::lossy_cast(ThickMulti {
        value1: 300_i32,
        value2: 511_i32,
    });
    assert_eq!(lossy, ThickMulti { value1: 44_u8, value2: 255_u8 });

    let saturating =
        <ThickMulti<i32> as SaturatingCast<ThickMulti<u8>>>::saturating_cast(ThickMulti {
            value1: 300_i32,
            value2: -1_i32,
        });
    assert_eq!(saturating, ThickMulti { value1: u8::MAX, value2: 0_u8 });

    let try_ok = <ThickMulti<i32> as TryCast<ThickMulti<u8>>>::try_cast(ThickMulti {
        value1: 1_i32,
        value2: 2_i32,
    });
    assert_eq!(try_ok, Ok(ThickMulti { value1: 1_u8, value2: 2_u8 }));

    let try_err = <ThickMulti<i32> as TryCast<ThickMulti<u8>>>::try_cast(ThickMulti {
        value1: 1_i32,
        value2: 300_i32,
    });
    assert_eq!(try_err, Err(CastError::OutOfRange));

    let try_exact_err =
        <ThickMulti<f32> as TryExactCast<ThickMulti<i32>>>::try_exact_cast(ThickMulti {
            value1: 1.0_f32,
            value2: 1.5_f32,
        });
    assert_eq!(try_exact_err, Err(CastError::Fractional));
}

#[test]
fn transparent_casts_thick_single_surface() {
    let src = ThickSingle { value: 300_i32 };

    assert_eq!(src.cast::<i64>(), ThickSingle { value: 300_i64 });
    assert_eq!(ThickSingle::<i64>::cast_from(src), ThickSingle { value: 300_i64 });

    assert_eq!(src.lossy_cast::<u8>(), ThickSingle { value: 44_u8 });
    assert_eq!(ThickSingle::<u8>::lossy_cast_from(src), ThickSingle { value: 44_u8 });

    assert_eq!(src.saturating_cast::<u8>(), ThickSingle { value: u8::MAX });
    assert_eq!(ThickSingle::<u8>::saturating_cast_from(src), ThickSingle { value: u8::MAX });

    assert_eq!(src.try_cast::<u8>(), Err(CastError::OutOfRange));
    assert_eq!(ThickSingle::<u8>::try_cast_from(src), Err(CastError::OutOfRange));

    assert_eq!(
        ThickSingle::<i64>::try_exact_cast_from(ThickSingle { value: 7_i32 }),
        Ok(ThickSingle { value: 7_i64 })
    );

    let trait_casted =
        <ThickSingle<i32> as Cast<ThickSingle<i64>>>::cast(ThickSingle { value: 7_i32 });
    assert_eq!(trait_casted, ThickSingle { value: 7_i64 });

    let trait_lossy = <ThickSingle<i32> as LossyCast<ThickSingle<u8>>>::lossy_cast(src);
    assert_eq!(trait_lossy, ThickSingle { value: 44_u8 });

    let trait_saturating =
        <ThickSingle<i32> as SaturatingCast<ThickSingle<u8>>>::saturating_cast(src);
    assert_eq!(trait_saturating, ThickSingle { value: u8::MAX });

    let trait_try = <ThickSingle<i32> as TryCast<ThickSingle<u8>>>::try_cast(src);
    assert_eq!(trait_try, Err(CastError::OutOfRange));

    let trait_try_exact =
        <ThickSingle<i32> as TryExactCast<ThickSingle<i64>>>::try_exact_cast(ThickSingle {
            value: 7_i32,
        });
    assert_eq!(trait_try_exact, Ok(ThickSingle { value: 7_i64 }));
}

#[test]
fn transparent_casts_thick_const_surface() {
    let src = ThickConst::<i32, 2> { value1: 7_i32, value2: 300_i32 };

    let casted: ThickConst<i64, 2> = src.cast();
    assert_eq!(casted, ThickConst { value1: 7_i64, value2: 300_i64 });
    assert_eq!(
        ThickConst::<i64, 2>::cast_from(ThickConst::<i32, 2> { value1: 7_i32, value2: 300_i32 }),
        ThickConst { value1: 7_i64, value2: 300_i64 }
    );

    let lossy: ThickConst<u8, 2> = src.lossy_cast();
    assert_eq!(lossy, ThickConst { value1: 7_u8, value2: 44_u8 });
    assert_eq!(
        ThickConst::<u8, 2>::lossy_cast_from(ThickConst::<i32, 2> {
            value1: 7_i32,
            value2: 300_i32
        }),
        ThickConst { value1: 7_u8, value2: 44_u8 }
    );

    let saturating: ThickConst<u8, 2> = src.saturating_cast();
    assert_eq!(saturating, ThickConst { value1: 7_u8, value2: u8::MAX });
    assert_eq!(
        ThickConst::<u8, 2>::saturating_cast_from(ThickConst::<i32, 2> {
            value1: 7_i32,
            value2: 300_i32,
        }),
        ThickConst { value1: 7_u8, value2: u8::MAX }
    );

    let try_err: Result<ThickConst<u8, 2>, CastError> = src.try_cast();
    assert_eq!(try_err, Err(CastError::OutOfRange));
    assert_eq!(
        ThickConst::<u8, 2>::try_cast_from(ThickConst::<i32, 2> { value1: 7_i32, value2: 300_i32 }),
        Err(CastError::OutOfRange)
    );

    let try_exact_err: Result<ThickConst<i32, 2>, CastError> =
        ThickConst::<f32, 2> { value1: 1.0_f32, value2: 1.5_f32 }.try_exact_cast();
    assert_eq!(try_exact_err, Err(CastError::Fractional));
    assert_eq!(
        ThickConst::<i32, 2>::try_exact_cast_from(ThickConst::<f32, 2> {
            value1: 1.0_f32,
            value2: 1.5_f32,
        }),
        Err(CastError::Fractional)
    );

    let trait_casted = <ThickConst<i32, 2> as Cast<ThickConst<i64, 2>>>::cast(src);
    assert_eq!(trait_casted, ThickConst { value1: 7_i64, value2: 300_i64 });

    let trait_lossy = <ThickConst<i32, 2> as LossyCast<ThickConst<u8, 2>>>::lossy_cast(src);
    assert_eq!(trait_lossy, ThickConst { value1: 7_u8, value2: 44_u8 });

    let trait_saturating =
        <ThickConst<i32, 2> as SaturatingCast<ThickConst<u8, 2>>>::saturating_cast(src);
    assert_eq!(trait_saturating, ThickConst { value1: 7_u8, value2: u8::MAX });

    let trait_try = <ThickConst<i32, 2> as TryCast<ThickConst<u8, 2>>>::try_cast(src);
    assert_eq!(trait_try, Err(CastError::OutOfRange));

    let trait_try_exact =
        <ThickConst<i32, 2> as TryExactCast<ThickConst<i64, 2>>>::try_exact_cast(ThickConst {
            value1: 1_i32,
            value2: 2_i32,
        });
    assert_eq!(trait_try_exact, Ok(ThickConst { value1: 1_i64, value2: 2_i64 }));
}

#[test]
fn vec_casts_surface() {
    let src = Vec::from([1_i32, 200, 300]);

    let casted: Vec<i64> = src.clone().cast();
    assert_eq!(casted, Vec::from([1_i64, 200, 300]));

    let lossy: Vec<u8> = src.clone().lossy_cast();
    assert_eq!(lossy, Vec::from([1_u8, 200, 44]));

    let saturating: Vec<u8> = src.clone().saturating_cast();
    assert_eq!(saturating, Vec::from([1_u8, 200, u8::MAX]));

    let try_err: Result<Vec<u8>, CastError> = src.clone().try_cast();
    assert_eq!(try_err, Err(CastError::OutOfRange));

    let try_ok: Result<Vec<u8>, CastError> = Vec::from([1_i32, 200]).try_cast();
    assert_eq!(try_ok, Ok(Vec::from([1_u8, 200])));

    let try_exact_ok: Result<Vec<i64>, CastError> = Vec::from([1_i32, 2]).try_exact_cast();
    assert_eq!(try_exact_ok, Ok(Vec::from([1_i64, 2])));

    let try_exact_err: Result<Vec<i32>, CastError> = Vec::from([1.0_f32, 1.5]).try_exact_cast();
    assert_eq!(try_exact_err, Err(CastError::Fractional));
}