1#![no_std]
19
20use core::{
21 borrow::Borrow,
22 fmt::{self, Display},
23};
24use num_traits::float::FloatCore;
25
26#[doc(hidden)]
28#[allow(clippy::too_many_arguments)]
29pub fn assert_within_add_impl<N: Display + FloatCore>(
30 file: &'static str,
31 line: u32,
32 val: impl Borrow<N>,
33 val_str: &'static str,
34 target: impl Borrow<N>,
35 target_str: &'static str,
36 eps: impl Borrow<N>,
37 context: fmt::Arguments,
38) {
39 let val = val.borrow();
40 let target = target.borrow();
41 let eps = eps.borrow();
42
43 if eps.is_nan() {
44 panic!("assert_within failed at {file}:{line}:\nepsilon was Nan: {eps}\n{context}");
45 }
46
47 if *eps < N::zero() {
48 panic!(
49 "assert_within failed at {file}:{line}:\nEpsilon cannot be negative when used with assert_within! macro: {eps}\n{context}"
50 )
51 }
52
53 if val.is_nan() {
54 panic!("assert_within failed at {file}:{line}:\n`{val_str}` was Nan: {val}\n{context}");
55 }
56
57 if target.is_nan() {
58 panic!(
59 "assert_within failed at {file}:{line}:\n`{target_str}` was Nan: {target}\n{context}"
60 );
61 }
62
63 if *val < *target - *eps {
64 panic!(
65 "assert_within failed at {file}:{line}:\n`{val_str}` was less than `{target_str}` - {eps})\nleft: {val}\nright: {target}\n{context}"
66 );
67 }
68
69 if *val > *target + *eps {
70 panic!(
71 "assert_within failed at {file}:{line}:\n`{val_str}` was greater than `{target_str}` + {eps})\nleft: {val}\nright: {target}\n{context}"
72 );
73 }
74}
75
76#[doc(hidden)]
78#[allow(clippy::too_many_arguments)]
79pub fn assert_within_mul_impl<N: Display + FloatCore>(
80 file: &'static str,
81 line: u32,
82 val: impl Borrow<N>,
83 val_str: &'static str,
84 target: impl Borrow<N>,
85 target_str: &'static str,
86 eps: impl Borrow<N>,
87 context: fmt::Arguments,
88) {
89 let val = val.borrow();
90 let target = target.borrow();
91 let eps = eps.borrow();
92
93 if eps.is_nan() {
94 panic!("assert_within failed at {file}:{line}:\nepsilon was Nan: {eps}\n{context}");
95 }
96
97 if *eps < N::zero() {
98 panic!(
99 "assert_within failed at {file}:{line}:\nEpsilon cannot be negative when used with assert_within! macro: {eps}\n{context}"
100 )
101 }
102
103 if val.is_nan() {
104 panic!("assert_within failed at {file}:{line}:\n`{val_str}` was Nan: {val}\n{context}");
105 }
106
107 if target.is_nan() {
108 panic!(
109 "assert_within failed at {file}:{line}:\n`{target_str}` was Nan: {target}\n{context}"
110 );
111 }
112
113 let one_minus_eps = N::one() - *eps;
114 let one_plus_eps = N::one() + *eps;
115 if target.is_sign_positive() {
116 if *val < one_minus_eps * *target {
117 panic!(
118 "assert_within failed at {file}:{line}:\n`{val_str}` was less than (1 ± {eps}) * `{target_str}`\nleft: {val}\nright: {target}\n{context}"
119 );
120 }
121
122 if *val > one_plus_eps * *target {
123 panic!(
124 "assert_within failed at {file}:{line}:\n`{val_str}` was greater than (1 ± {eps}) * `{target_str}`\nleft: {val}\nright: {target}\n{context}"
125 );
126 }
127 } else {
128 if *val < one_plus_eps * *target {
129 panic!(
130 "assert_within failed at {file}:{line}:\n`{val_str}` was less than (1 ± {eps}) * `{target_str}`\nleft: {val}\nright: {target}\n{context}"
131 );
132 }
133 if *val > one_minus_eps * *target {
134 panic!(
135 "assert_within failed at {file}:{line}:\n`{val_str}` was greater than (1 ± {eps}) * `{target_str}`\nleft: {val}\nright: {target}\n{context}"
136 );
137 }
138 }
139}
140
141#[macro_export]
142macro_rules! assert_within {
143 (+ $epsilon:expr, $val:expr, $target:expr) => {
144 $crate::assert_within_add_impl(
145 file!(),
146 line!(),
147 $val,
148 stringify!($val),
149 $target,
150 stringify!($target),
151 $epsilon,
152 format_args!(""),
153 )
154 };
155
156 (+ $epsilon:expr, $val:expr, $target:expr, $($fmt_args:tt)*) => {
157 $crate::assert_within_add_impl(
158 file!(),
159 line!(),
160 $val,
161 stringify!($val),
162 $target,
163 stringify!($target),
164 $epsilon,
165 format_args!($($fmt_args)*),
166 )
167 };
168
169 (~ $epsilon:expr, $val:expr, $target:expr) => {
170 $crate::assert_within_mul_impl(
171 file!(),
172 line!(),
173 $val,
174 stringify!($val),
175 $target,
176 stringify!($target),
177 $epsilon,
178 format_args!(""),
179 )
180 };
181
182 (~ $epsilon:expr, $val:expr, $target:expr, $($fmt_args:tt)*) => {
183 $crate::assert_within_mul_impl(
184 file!(),
185 line!(),
186 $val,
187 stringify!($val),
188 $target,
189 stringify!($target),
190 $epsilon,
191 format_args!($($fmt_args)*),
192 )
193 };
194}