1pub struct AbsDiff<A, B = A>
17where
18 A: AbsDiffEq<B> + ?Sized,
19 B: ?Sized,
20{
21 pub epsilon: A::Epsilon,
23}
24
25impl<A, B> Default for AbsDiff<A, B>
26where
27 A: AbsDiffEq<B> + ?Sized,
28 B: ?Sized,
29{
30 fn default() -> AbsDiff<A, B> {
31 AbsDiff {
32 epsilon: A::default_epsilon(),
33 }
34 }
35}
36
37impl<A, B> AbsDiff<A, B>
38where
39 A: AbsDiffEq<B> + ?Sized,
40 B: ?Sized,
41{
42 pub fn epsilon(self, epsilon: A::Epsilon) -> AbsDiff<A, B> {
44 AbsDiff { epsilon }
45 }
46
47 pub fn eq(self, lhs: &A, rhs: &B) -> bool {
49 A::abs_diff_eq(lhs, rhs, self.epsilon)
50 }
51
52 pub fn ne(self, lhs: &A, rhs: &B) -> bool {
54 A::abs_diff_ne(lhs, rhs, self.epsilon)
55 }
56}
57
58pub trait AbsDiffEq<Rhs = Self>: PartialEq<Rhs>
60where
61 Rhs: ?Sized,
62{
63 type Epsilon;
65
66 fn default_epsilon() -> Self::Epsilon;
70
71 fn abs_diff_eq(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool;
74
75 fn abs_diff_ne(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool {
77 !Self::abs_diff_eq(self, other, epsilon)
78 }
79}
80
81macro_rules! impl_abs_diff_eq {
82 ($T:ident) => {
83 impl AbsDiffEq for $T {
84 type Epsilon = $T;
85
86 fn default_epsilon() -> $T {
87 $T::EPSILON
88 }
89
90 fn abs_diff_eq(&self, other: &$T, epsilon: $T) -> bool {
91 (if self > other {
92 self - other
93 } else {
94 other - self
95 }) <= epsilon
96 }
97 }
98 };
99}
100
101impl_abs_diff_eq!(f32);
102impl_abs_diff_eq!(f64);
103
104#[macro_export]
106macro_rules! abs_diff_eq {
107 ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => {
108 $crate::algebra::abstr::AbsDiff::default()$(.$opt($val))*.eq(&$lhs, &$rhs)
109 };
110 ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => {
111 $crate::algebra::abstr::AbsDiff::default()$(.$opt($val))*.eq(&$lhs, &$rhs)
112 };
113}
114
115#[macro_export]
117macro_rules! abs_diff_ne {
118 ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => {
119 $crate::algebra::abstr::AbsDiff::default()$(.$opt($val))*.ne(&$lhs, &$rhs)
120 };
121 ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => {
122 $crate::algebra::abstr::AbsDiff::default()$(.$opt($val))*.ne(&$lhs, &$rhs)
123 };
124}
125
126#[doc(hidden)]
127#[macro_export]
128macro_rules! __assert_approx {
129 ($eq:ident, $given:expr, $expected:expr) => {{
130 let (given, expected) = (&($given), &($expected));
131
132 if !$eq!(*given, *expected) {
133 panic!(
134 "assert_{}!({}, {})
135 left = {:?}
136 right = {:?}
137 ",
138 stringify!($eq),
139 stringify!($given),
140 stringify!($expected),
141 given, expected,
142 );
143 }
144 }};
145 ($eq:ident, $given:expr, $expected:expr, $($opt:ident = $val:expr),+) => {{
146 let (given, expected) = (&($given), &($expected));
147
148 if !$eq!(*given, *expected, $($opt = $val),+) {
149 panic!(
150"assert_{}!({}, {}, {})
151 left = {:?}
152 right = {:?}
153",
154 stringify!($eq),
155 stringify!($given),
156 stringify!($expected),
157 stringify!($($opt = $val),+),
158 given, expected,
159 );
160 }
161 }};
162}
163
164#[macro_export(local_inner_macros)]
166macro_rules! assert_abs_diff_eq {
167 ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => {
168 __assert_approx!(abs_diff_eq, $given, $expected $(, $opt = $val)*)
169 };
170 ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => {
171 __assert_approx!(abs_diff_eq, $given, $expected $(, $opt = $val)*)
172 };
173}
174
175#[macro_export(local_inner_macros)]
177macro_rules! assert_abs_diff_ne {
178 ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => {
179 __assert_approx!(abs_diff_ne, $given, $expected $(, $opt = $val)*)
180 };
181 ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => {
182 __assert_approx!(abs_diff_ne, $given, $expected $(, $opt = $val)*)
183 };
184}