ospf_rust_math/algebra/operator/comparison/
compare.rs1use 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}