rinia 0.0.14

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

use alloc::vec::Vec;

use crate::algebra::{ApproxEqAbs, ApproxEqRel};

#[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,
}

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

crate::impl_approx_eq_wrapper!([
    T
], impl: Thin<T>, item: T);

crate::impl_approx_eq_wrapper!([
    T
], impl: ThickSingle<T>, item: T, field: value);

crate::impl_approx_eq_wrapper!([
    T
], impl: ThickMulti<T>, item: T, fields: [value1, value2]);

crate::impl_approx_eq_wrapper!([
    T, const N: usize
], impl: ThickConst<T, N>, item: T, fields: [value1, value2]);

crate::impl_approx_eq_wrapper!(
    [T],
    impl: SignedEq<T>,
    item: T,
    extra_bounds: [core::ops::Neg<Output = T>],
    compare_abs: |lhs, rhs, tol| {
        lhs.value.approx_eq_abs_tol(rhs.value, tol) || lhs.value.approx_eq_abs_tol(-rhs.value, tol)
    },
    compare_rel: |lhs, rhs, tol| {
        lhs.value.approx_eq_rel_tol(rhs.value, tol) || lhs.value.approx_eq_rel_tol(-rhs.value, tol)
    },
);

#[test]
fn approx_eq_wrapper_thin_surface() {
    let lhs = Thin(1.0_f32);
    let rhs_close = Thin(1.0005_f32);
    let rhs_far = Thin(1.01_f32);

    assert!(lhs.approx_eq_abs_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_rel_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_abs(lhs));
    assert!(lhs.approx_eq_rel(lhs));

    assert!(<Thin<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_close, 0.001_f32));
    assert!(!<Thin<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_far, 0.001_f32));
    assert!(<Thin<f32> as ApproxEqAbs>::approx_eq_abs(lhs, lhs));

    assert!(<Thin<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_close, 0.001_f32));
    assert!(!<Thin<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_far, 0.001_f32));
    assert!(<Thin<f32> as ApproxEqRel>::approx_eq_rel(lhs, lhs));
}

#[test]
fn approx_eq_wrapper_thick_single_surface() {
    let lhs = ThickSingle { value: 1.0_f32 };
    let rhs_close = ThickSingle { value: 1.0005_f32 };
    let rhs_far = ThickSingle { value: 1.01_f32 };

    assert!(lhs.approx_eq_abs_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_rel_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_abs(lhs));
    assert!(lhs.approx_eq_rel(lhs));

    assert!(<ThickSingle<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_close, 0.001_f32));
    assert!(!<ThickSingle<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_far, 0.001_f32));
    assert!(<ThickSingle<f32> as ApproxEqAbs>::approx_eq_abs(lhs, lhs));

    assert!(<ThickSingle<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_close, 0.001_f32));
    assert!(!<ThickSingle<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_far, 0.001_f32));
    assert!(<ThickSingle<f32> as ApproxEqRel>::approx_eq_rel(lhs, lhs));
}

#[test]
fn approx_eq_wrapper_thick_multi_surface() {
    let lhs = ThickMulti { value1: 10.0_f32, value2: 20.0_f32 };
    let rhs_close = ThickMulti { value1: 10.0_f32, value2: 20.01_f32 };
    let rhs_far = ThickMulti { value1: 10.0_f32, value2: 20.5_f32 };

    assert!(lhs.approx_eq_abs_tol(rhs_close, 0.02_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_far, 0.02_f32));

    assert!(lhs.approx_eq_rel_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_abs(lhs));
    assert!(lhs.approx_eq_rel(lhs));

    assert!(<ThickMulti<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_close, 0.02_f32));
    assert!(!<ThickMulti<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_far, 0.02_f32));
    assert!(<ThickMulti<f32> as ApproxEqAbs>::approx_eq_abs(lhs, lhs));

    assert!(<ThickMulti<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_close, 0.001_f32));
    assert!(!<ThickMulti<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_far, 0.001_f32));
    assert!(<ThickMulti<f32> as ApproxEqRel>::approx_eq_rel(lhs, lhs));
}

#[test]
fn approx_eq_wrapper_thick_const_surface() {
    let lhs = ThickConst::<f32, 2> { value1: 10.0_f32, value2: 20.0_f32 };
    let rhs_close = ThickConst::<f32, 2> { value1: 10.0_f32, value2: 20.01_f32 };
    let rhs_far = ThickConst::<f32, 2> { value1: 10.0_f32, value2: 20.5_f32 };

    assert!(lhs.approx_eq_abs_tol(rhs_close, 0.02_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_far, 0.02_f32));

    assert!(lhs.approx_eq_rel_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_abs(lhs));
    assert!(lhs.approx_eq_rel(lhs));

    assert!(<ThickConst<f32, 2> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_close, 0.02_f32));
    assert!(!<ThickConst<f32, 2> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_far, 0.02_f32));
    assert!(<ThickConst<f32, 2> as ApproxEqAbs>::approx_eq_abs(lhs, lhs));

    assert!(<ThickConst<f32, 2> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_close, 0.001_f32));
    assert!(!<ThickConst<f32, 2> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_far, 0.001_f32));
    assert!(<ThickConst<f32, 2> as ApproxEqRel>::approx_eq_rel(lhs, lhs));
}

#[test]
fn approx_eq_wrapper_signed_callback_surface() {
    let lhs = SignedEq { value: 2.0_f32 };
    let rhs_sign_flipped = SignedEq { value: -2.0_f32 };
    let rhs_far = SignedEq { value: -3.0_f32 };

    assert!(lhs.approx_eq_abs_tol(rhs_sign_flipped, 0.001_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_rel_tol(rhs_sign_flipped, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_far, 0.001_f32));

    assert!(lhs.approx_eq_abs(lhs));
    assert!(lhs.approx_eq_rel(lhs));

    assert!(<SignedEq<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_sign_flipped, 0.001_f32));
    assert!(!<SignedEq<f32> as ApproxEqAbs>::approx_eq_abs_tol(lhs, rhs_far, 0.001_f32));
    assert!(<SignedEq<f32> as ApproxEqAbs>::approx_eq_abs(lhs, lhs));

    assert!(<SignedEq<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_sign_flipped, 0.001_f32));
    assert!(!<SignedEq<f32> as ApproxEqRel>::approx_eq_rel_tol(lhs, rhs_far, 0.001_f32));
    assert!(<SignedEq<f32> as ApproxEqRel>::approx_eq_rel(lhs, lhs));
}

#[test]
fn approx_eq_abs_array_blanket_impl() {
    let lhs = [1.0_f32, 2.0_f32, 3.0_f32];
    let rhs_close = [1.0_f32, 2.0005_f32, 3.0_f32];
    let rhs_far = [1.0_f32, 2.01_f32, 3.0_f32];

    assert!(lhs.approx_eq_abs_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_far, 0.001_f32));
}

#[test]
fn approx_eq_rel_array_blanket_impl() {
    let lhs = [100.0_f32, 200.0_f32, 300.0_f32];
    let rhs_close = [100.05_f32, 200.0_f32, 300.0_f32];
    let rhs_far = [101.0_f32, 200.0_f32, 300.0_f32];

    assert!(lhs.approx_eq_rel_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_far, 0.001_f32));
}

#[test]
fn approx_eq_abs_slice_blanket_impl() {
    let lhs = [1.0_f32, 2.0_f32, 3.0_f32, 4.0_f32];
    let rhs_close = [1.0_f32, 2.0_f32, 3.0005_f32, 4.0_f32];
    let rhs_short = [1.0_f32, 2.0_f32, 3.0_f32];

    assert!((&lhs[..]).approx_eq_abs_tol(&rhs_close[..], 0.001_f32));
    assert!(!(&lhs[..]).approx_eq_abs_tol(&rhs_short[..], 0.001_f32));
}

#[test]
fn approx_eq_rel_slice_blanket_impl() {
    let lhs = [10.0_f32, 20.0_f32, 30.0_f32, 40.0_f32];
    let rhs_close = [10.0_f32, 20.01_f32, 30.0_f32, 40.0_f32];
    let rhs_short = [10.0_f32, 20.0_f32, 30.0_f32];

    assert!((&lhs[..]).approx_eq_rel_tol(&rhs_close[..], 0.001_f32));
    assert!(!(&lhs[..]).approx_eq_rel_tol(&rhs_short[..], 0.001_f32));
}

#[test]
fn approx_eq_abs_vec_blanket_impl() {
    let lhs = Vec::from([1.0_f32, 2.0_f32, 3.0_f32]);
    let rhs_close = Vec::from([1.0_f32, 2.0_f32, 3.0005_f32]);
    let rhs_short = Vec::from([1.0_f32, 2.0_f32]);

    assert!(lhs.clone().approx_eq_abs_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_abs_tol(rhs_short, 0.001_f32));
}

#[test]
fn approx_eq_rel_vec_blanket_impl() {
    let lhs = Vec::from([10.0_f32, 20.0_f32, 30.0_f32]);
    let rhs_close = Vec::from([10.0_f32, 20.01_f32, 30.0_f32]);
    let rhs_short = Vec::from([10.0_f32, 20.0_f32]);

    assert!(lhs.clone().approx_eq_rel_tol(rhs_close, 0.001_f32));
    assert!(!lhs.approx_eq_rel_tol(rhs_short, 0.001_f32));
}