ospf_rust_math/algebra/operator/comparison/
equal.rs

1use std::ops::{Add, Sub};
2
3use crate::algebra::concept::*;
4use crate::algebra::operator::Abs;
5
6use super::ComparisonOperator;
7
8pub trait EqualOpr<T, Rhs = T>: ComparisonOperator<T, Rhs> {
9    fn precision(&self) -> Option<&T> {
10        None
11    }
12}
13
14impl<T, Rhs> FnOnce<(&T, &Rhs)> for &dyn EqualOpr<T, Rhs> {
15    type Output = bool;
16
17    extern "rust-call" fn call_once(self, (x, y): (&T, &Rhs)) -> bool {
18        self.cmp(x, y)
19    }
20}
21
22impl<T, Rhs> FnMut<(&T, &Rhs)> for &dyn EqualOpr<T, Rhs> {
23    extern "rust-call" fn call_mut(&mut self, (x, y): (&T, &Rhs)) -> bool {
24        self.cmp(x, y)
25    }
26}
27
28impl<T, Rhs> Fn<(&T, &Rhs)> for &dyn EqualOpr<T, Rhs> {
29    extern "rust-call" fn call(&self, (x, y): (&T, &Rhs)) -> bool {
30        self.cmp(x, y)
31    }
32}
33
34impl<T, Rhs> FnOnce<(&T, &Rhs)> for Box<dyn EqualOpr<T, Rhs>> {
35    type Output = bool;
36
37    extern "rust-call" fn call_once(self, (x, y): (&T, &Rhs)) -> bool {
38        self.cmp(x, y)
39    }
40}
41
42impl<T, Rhs> FnMut<(&T, &Rhs)> for Box<dyn EqualOpr<T, Rhs>> {
43    extern "rust-call" fn call_mut(&mut self, (x, y): (&T, &Rhs)) -> bool {
44        self.cmp(x, y)
45    }
46}
47
48impl<T, Rhs> Fn<(&T, &Rhs)> for Box<dyn EqualOpr<T, Rhs>> {
49    extern "rust-call" fn call(&self, (x, y): (&T, &Rhs)) -> bool {
50        self.cmp(x, y)
51    }
52}
53
54#[derive(Clone, Copy, Debug)]
55pub struct EqualInt {}
56
57impl EqualInt {
58    fn new() -> Self {
59        Self {}
60    }
61}
62
63impl<T: PartialEq<Rhs>, Rhs> ComparisonOperator<T, Rhs> for EqualInt {
64    fn cmp(&self, x: &T, y: &Rhs) -> bool {
65        x == y
66    }
67}
68
69impl<T: PartialEq<Rhs>, Rhs> EqualOpr<T, Rhs> for EqualInt {
70    default fn precision(&self) -> Option<&T> {
71        None
72    }
73}
74
75impl<T: SemiArithmetic + PartialEq<Rhs>, Rhs> EqualOpr<T, Rhs> for EqualInt {
76    fn precision(&self) -> Option<&T> {
77        Some(T::ZERO)
78    }
79}
80
81#[derive(Clone, Copy, Debug)]
82pub struct EqualFlt<T> {
83    pub(self) precision: T,
84}
85
86impl<T> From<T> for EqualFlt<T> {
87    default fn from(precision: T) -> Self {
88        Self { precision }
89    }
90}
91
92impl<T: Signed> From<&T> for EqualFlt<T>
93where
94    for<'a> &'a T: Abs<Output = T>,
95{
96    fn from(precision: &T) -> Self {
97        Self {
98            precision: precision.abs(),
99        }
100    }
101}
102
103impl<T: Signed + Copy + Abs<Output = T>> From<T> for EqualFlt<T> {
104    fn from(precision: T) -> Self {
105        Self {
106            precision: precision.abs(),
107        }
108    }
109}
110
111impl<T> EqualFlt<T> {
112    pub fn new() -> Self
113    where
114        T: Precision + Clone,
115    {
116        Self {
117            precision: <T as Precision>::DECIMAL_PRECISION.clone(),
118        }
119    }
120
121    pub fn new_with(precision: T) -> Self
122    where
123        Self: From<T>,
124    {
125        Self::from(precision)
126    }
127}
128
129impl<T: PartialOrd<Rhs>, Rhs> ComparisonOperator<T, Rhs> for EqualFlt<T>
130where
131    for<'a> &'a T: Add + Sub,
132    for<'a> <&'a T as Add>::Output: PartialOrd<Rhs>,
133    for<'a> <&'a T as Sub>::Output: PartialOrd<Rhs>,
134{
135    fn cmp(&self, x: &T, y: &Rhs) -> bool {
136        return &(x - &self.precision) <= y && &(x + &self.precision) >= y;
137    }
138}
139
140impl<T: PartialOrd<Rhs>, Rhs> EqualOpr<T, Rhs> for EqualFlt<T>
141where
142    for<'a> &'a T: Add + Sub,
143    for<'a> <&'a T as Add>::Output: PartialOrd<Rhs>,
144    for<'a> <&'a T as Sub>::Output: PartialOrd<Rhs>,
145{
146    fn precision(&self) -> Option<&T> {
147        Some(&self.precision)
148    }
149}
150
151pub trait EqualOprBuilder<T, Rhs = T> {
152    fn new() -> Box<dyn EqualOpr<T, Rhs>>;
153    fn new_with(precision: T) -> Box<dyn EqualOpr<T, Rhs>>;
154}
155
156pub struct Equal<T> {
157    _marker: std::marker::PhantomData<T>,
158}
159
160impl<T: PartialEq<Rhs>, Rhs> EqualOprBuilder<T, Rhs> for Equal<T> {
161    default fn new() -> Box<dyn EqualOpr<T, Rhs>> {
162        Box::new(EqualInt::new())
163    }
164
165    default fn new_with(precision: T) -> Box<dyn EqualOpr<T, Rhs>> {
166        Box::new(EqualInt::new())
167    }
168}
169
170impl<T: 'static + PartialOrd<Rhs>, Rhs> EqualOprBuilder<T, Rhs> for Equal<T>
171where
172    for<'a> &'a T: Add + Sub,
173    for<'a> <&'a T as Add>::Output: PartialOrd<Rhs>,
174    for<'a> <&'a T as Sub>::Output: PartialOrd<Rhs>,
175{
176    default fn new() -> Box<dyn EqualOpr<T, Rhs>> {
177        Box::new(EqualInt::new())
178    }
179
180    default fn new_with(precision: T) -> Box<dyn EqualOpr<T, Rhs>> {
181        Box::new(EqualFlt::new_with(precision))
182    }
183}
184
185impl<T: FloatingNumber + Clone + PartialOrd<Rhs>, Rhs> EqualOprBuilder<T, Rhs> for Equal<T>
186where
187    for<'a> &'a T: Add + Sub,
188    for<'a> <&'a T as Add>::Output: PartialOrd<Rhs>,
189    for<'a> <&'a T as Sub>::Output: PartialOrd<Rhs>,
190{
191    fn new() -> Box<dyn EqualOpr<T, Rhs>> {
192        Box::new(EqualFlt::new())
193    }
194
195    fn new_with(precision: T) -> Box<dyn EqualOpr<T, Rhs>> {
196        Box::new(EqualFlt::new_with(precision))
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203
204    #[test]
205    fn test_eq_int() {
206        let eq = Equal::<i64>::new();
207        assert_eq!(eq(&0, &0), true);
208        assert_eq!(eq(&1, &0), false);
209    }
210
211    #[test]
212    fn test_eq_flt() {
213        let eq = Equal::<f64>::new();
214        assert_eq!(eq(&0.0, &0.0), true);
215        assert_eq!(eq(&1e-6, &0.0), false);
216
217        let eq = Equal::<f64>::new_with(1e-5);
218        assert_eq!(eq(&0.0, &0.0), true);
219        assert_eq!(eq(&1e-6, &0.0), true);
220    }
221}