ospf_rust_math/algebra/operator/algorithmic/
abs.rs

1use std::ops::Neg;
2
3use crate::algebra::concept::{Arithmetic, SemiArithmetic, Signed, Unsigned};
4
5pub trait Abs {
6    type Output;
7
8    fn abs(self) -> Self::Output;
9}
10
11pub fn abs<T: Abs>(value: T) -> T::Output {
12    value.abs()
13}
14
15macro_rules! unsigned_abs_template {
16    ($($type:ident)*) => ($(
17        impl Abs for $type {
18            type Output = $type;
19
20            fn abs(self) -> $type {
21                self
22            }
23        }
24
25        impl Abs for &$type {
26            type Output = $type;
27
28            fn abs(self) -> $type {
29                self.clone()
30            }
31        }
32    )*)
33}
34unsigned_abs_template! { bool u8 u16 u32 u64 u128 usize }
35
36macro_rules! signed_abs_template {
37    ($($type:ident)*) => ($(
38        impl Abs for $type {
39            type Output = $type;
40
41            fn abs(self) -> $type {
42                if &self < $type::ZERO { -self } else { self }
43            }
44        }
45
46        impl Abs for &$type {
47            type Output = $type;
48
49            fn abs(self) -> $type {
50                if self < $type::ZERO { -self } else { *self }
51            }
52        }
53    )*)
54}
55signed_abs_template! { i8 i16 i32 i64 i128 isize f32 f64 }
56
57#[cfg(test)]
58mod tests {
59    use std::fmt::Debug;
60    use std::ops::Add;
61
62    use crate::algebra::concept::{Bounded, FloatingNumber, IntegerNumber, UIntegerNumber};
63
64    use super::*;
65
66    fn test_bounded<T: Arithmetic + Bounded + Abs<Output = T> + Debug>()
67    where
68        for<'a> &'a T: Abs<Output = T>,
69    {
70        assert_eq!(&(T::ZERO.clone().abs()), T::ZERO);
71        assert_eq!(&(T::ZERO.abs()), T::ZERO);
72        assert_eq!(&abs(T::ZERO.clone()), T::ZERO);
73        assert_eq!(&abs(T::ZERO), T::ZERO);
74
75        assert_eq!(&(T::POSITIVE_MINIMUM.clone()).abs(), T::POSITIVE_MINIMUM);
76        assert_eq!(&(T::POSITIVE_MINIMUM.abs()), T::POSITIVE_MINIMUM);
77        assert_eq!(&abs(T::POSITIVE_MINIMUM.clone()), T::POSITIVE_MINIMUM);
78        assert_eq!(&abs(T::POSITIVE_MINIMUM), T::POSITIVE_MINIMUM);
79
80        assert_eq!(&T::MAXIMUM.as_ref().map(|x| x.clone().abs()), T::MAXIMUM);
81        assert_eq!(&T::MAXIMUM.as_ref().map(|x| x.abs()), T::MAXIMUM);
82        assert_eq!(&T::MAXIMUM.as_ref().map(|x| abs(x.clone())), T::MAXIMUM);
83        assert_eq!(&T::MAXIMUM.as_ref().map(|x| abs(x)), T::MAXIMUM);
84    }
85
86    fn test_signed<T: Arithmetic + Bounded + Signed + Abs<Output = T> + Debug>()
87    where
88        for<'a> &'a T: Neg<Output = T> + Abs<Output = T>,
89    {
90        test_bounded::<T>();
91
92        assert_eq!(&(-T::POSITIVE_MINIMUM).abs(), T::POSITIVE_MINIMUM);
93        assert_eq!(&(&-T::POSITIVE_MINIMUM).abs(), T::POSITIVE_MINIMUM);
94        assert_eq!(&abs(-T::POSITIVE_MINIMUM), T::POSITIVE_MINIMUM);
95        assert_eq!(&abs(&-T::POSITIVE_MINIMUM), T::POSITIVE_MINIMUM);
96    }
97
98    fn test_int<T: IntegerNumber + Abs<Output = T> + Debug>()
99    where
100        for<'a> &'a T: Add<Output = T> + Neg<Output = T> + Abs<Output = T>,
101    {
102        test_signed::<T>();
103
104        assert_eq!(&T::MINIMUM.as_ref().map(|x| (x + T::ONE).abs()), T::MAXIMUM);
105        assert_eq!(
106            &T::MINIMUM.as_ref().map(|x| (&(x + T::ONE)).abs()),
107            T::MAXIMUM
108        );
109        assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(x + T::ONE)), T::MAXIMUM);
110        assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(&(x + T::ONE))), T::MAXIMUM);
111    }
112
113    fn test_uint<T: UIntegerNumber + Abs<Output = T> + Debug>()
114    where
115        for<'a> &'a T: Abs<Output = T>,
116    {
117        test_bounded::<T>();
118    }
119
120    fn test_flt<T: FloatingNumber + Abs<Output = T> + Debug>()
121    where
122        for<'a> &'a T: Neg<Output = T> + Abs<Output = T>,
123    {
124        test_signed::<T>();
125
126        assert_eq!(&T::MINIMUM.as_ref().map(|x| x.clone().abs()), T::MAXIMUM);
127        assert_eq!(&T::MINIMUM.as_ref().map(|x| x.abs()), T::MAXIMUM);
128        assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(x.clone())), T::MAXIMUM);
129        assert_eq!(&T::MINIMUM.as_ref().map(|x| abs(x)), T::MAXIMUM);
130    }
131
132    #[test]
133    fn test() {
134        test_int::<i8>();
135        test_int::<i16>();
136        test_int::<i32>();
137        test_int::<i64>();
138        test_int::<i128>();
139        test_uint::<u8>();
140        test_uint::<u16>();
141        test_uint::<u32>();
142        test_uint::<u64>();
143        test_uint::<u128>();
144        test_flt::<f32>();
145        test_flt::<f64>();
146    }
147}