ospf_rust_math/algebra/operator/comparison/
compare.rs

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