num_valid/functions/
max_min.rs1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::core::traits::{raw::RawScalarValidate, validation::sealed::NativeReal};
9use duplicate::duplicate_item;
10
11pub trait Max: PartialOrd + Sized {
31 fn max_by_ref<'a>(&'a self, other: &'a Self) -> &'a Self {
42 if self >= other { self } else { other }
43 }
44
45 fn max_by_value(self, other: Self) -> Self {
56 if self >= other { self } else { other }
57 }
58}
59
60pub trait Min: PartialOrd + Sized {
78 fn min_by_ref<'a>(&'a self, other: &'a Self) -> &'a Self {
89 if self <= other { self } else { other }
90 }
91
92 fn min_by_value(self, other: Self) -> Self {
103 if self <= other { self } else { other }
104 }
105}
106
107#[inline(always)]
115fn validate_raw_scalar_in_debug<T: RawScalarValidate>(value: &T, msg: &str) {
116 #[cfg(debug_assertions)]
117 {
118 if let Err(e) = value.validate_raw_scalar_ref() {
119 panic!("Debug validation of {msg} value failed: {e}");
120 }
121 }
122 #[cfg(not(debug_assertions))]
123 {
124 let _ = value;
126 let _ = msg;
127 }
128}
129#[duplicate_item(
134 trait_name func_by_ref func_by_value implementation;
135 [Max] [max_by_ref] [max_by_value] [if self >= other { self } else { other }];
136 [Min] [min_by_ref] [min_by_value] [if self <= other { self } else { other }];
137)]
138impl<T: NativeReal> trait_name for T {
140 fn func_by_ref<'a>(&'a self, other: &'a Self) -> &'a Self {
141 validate_raw_scalar_in_debug(self, "left");
143 validate_raw_scalar_in_debug(other, "right");
144
145 implementation
146 }
147
148 fn func_by_value(self, other: Self) -> Self {
149 validate_raw_scalar_in_debug(&self, "left");
151 validate_raw_scalar_in_debug(&other, "right");
152
153 implementation
154 }
155}
156#[cfg(test)]
160mod tests {
161 use super::*;
162
163 mod max {
164 use super::*;
165
166 mod native {
167 use super::*;
168
169 #[test]
170 fn test_f64_max_valid() {
171 let a = 3.0;
172 let b = 5.0;
173 let expected_result = 5.0;
174 assert_eq!(Max::max_by_ref(&a, &b), &expected_result);
175 assert_eq!(Max::max_by_value(a, b), expected_result);
176 }
177
178 #[test]
179 fn test_f64_max_equal_values() {
180 let a = 3.0;
181 let b = 3.0;
182 let expected_result = 3.0;
183 assert_eq!(Max::max_by_ref(&a, &b), &expected_result);
184 assert_eq!(Max::max_by_value(a, b), expected_result);
185 }
186
187 #[test]
188 fn test_f64_max_negative_values() {
189 let a = -3.0;
190 let b = -5.0;
191 let expected_result = -3.0;
192 assert_eq!(Max::max_by_ref(&a, &b), &expected_result);
193 assert_eq!(Max::max_by_value(a, b), expected_result);
194 }
195
196 #[test]
197 #[cfg(debug_assertions)]
198 #[should_panic(expected = "Debug validation of left value failed: Value is NaN")]
199 fn test_f64_max_nan_value() {
200 let a = f64::NAN;
201 let b = 5.0;
202 let _result = Max::max_by_ref(&a, &b);
203 }
204
205 #[test]
206 #[cfg(debug_assertions)]
207 #[should_panic(expected = "Debug validation of right value failed: Value is NaN")]
208 fn test_f64_max_nan_other() {
209 let a = 3.0;
210 let b = f64::NAN;
211 let _result = Max::max_by_ref(&a, &b);
212 }
213
214 #[test]
215 #[cfg(debug_assertions)]
216 #[should_panic(
217 expected = "Debug validation of left value failed: Value is positive infinity"
218 )]
219 fn test_f64_max_infinite_value() {
220 let a = f64::INFINITY;
221 let b = 5.0;
222 let _result = Max::max_by_ref(&a, &b);
223 }
224
225 #[test]
226 #[cfg(debug_assertions)]
227 #[should_panic(
228 expected = "Debug validation of right value failed: Value is positive infinity"
229 )]
230 fn test_f64_max_infinite_other() {
231 let a = 3.0;
232 let b = f64::INFINITY;
233 let _result = Max::max_by_ref(&a, &b);
234 }
235
236 #[test]
237 #[cfg(debug_assertions)]
238 #[should_panic(
239 expected = "Debug validation of left value failed: Value is negative infinity"
240 )]
241 fn test_f64_max_neg_infinite_value() {
242 let a = f64::NEG_INFINITY;
243 let b = 5.0;
244 let _result = Max::max_by_ref(&a, &b);
245 }
246
247 #[test]
248 #[cfg(debug_assertions)]
249 #[should_panic(
250 expected = "Debug validation of right value failed: Value is negative infinity"
251 )]
252 fn test_f64_max_neg_infinite_other() {
253 let a = 3.0;
254 let b = f64::NEG_INFINITY;
255 let _result = Max::max_by_ref(&a, &b);
256 }
257
258 #[test]
259 #[cfg(debug_assertions)]
260 #[should_panic(expected = "Debug validation of left value failed: Value is subnormal")]
261 fn test_f64_max_subnormal_value() {
262 let a = f64::MIN_POSITIVE / 2.0;
263 let b = 5.0;
264 let _result = Max::max_by_ref(&a, &b);
265 }
266
267 #[test]
268 #[cfg(debug_assertions)]
269 #[should_panic(expected = "Debug validation of right value failed: Value is subnormal")]
270 fn test_f64_max_subnormal_other() {
271 let a = 3.0;
272 let b = f64::MIN_POSITIVE / 2.0;
273 let _result = Max::max_by_ref(&a, &b);
274 }
275 }
276
277 mod native64_strict_finite {
278 use try_create::TryNew;
279
280 use super::*;
281 use crate::backends::native::validated::RealNative64StrictFinite;
282
283 #[test]
284 fn test_f64_max_validated() {
285 let a = RealNative64StrictFinite::try_new(3.0).unwrap();
286 let b = RealNative64StrictFinite::try_new(5.0).unwrap();
287 let expected_result = RealNative64StrictFinite::try_new(5.0).unwrap();
288 assert_eq!(Max::max_by_ref(&a, &b), &expected_result);
289 assert_eq!(Max::max_by_value(a, b), expected_result);
290 }
291
292 #[test]
293 fn test_f64_max_validated_equal() {
294 let a = RealNative64StrictFinite::try_new(3.0).unwrap();
295 let b = RealNative64StrictFinite::try_new(3.0).unwrap();
296 let expected_result = RealNative64StrictFinite::try_new(3.0).unwrap();
297 assert_eq!(Max::max_by_ref(&a, &b), &expected_result);
298 assert_eq!(Max::max_by_value(a, b), expected_result);
299 }
300 }
301 }
302
303 mod min {
304 use super::*;
305
306 mod native {
307 use super::*;
308
309 #[test]
310 fn test_f64_min_valid() {
311 let a = 3.0;
312 let b = 5.0;
313 let expected_result = 3.0;
314 assert_eq!(Min::min_by_ref(&a, &b), &expected_result);
315 assert_eq!(Min::min_by_value(a, b), expected_result);
316 }
317
318 #[test]
319 fn test_f64_min_equal_values() {
320 let a = 3.0;
321 let b = 3.0;
322 let expected_result = 3.0;
323 assert_eq!(Min::min_by_ref(&a, &b), &expected_result);
324 assert_eq!(Min::min_by_value(a, b), expected_result);
325 }
326
327 #[test]
328 fn test_f64_min_negative_values() {
329 let a = -3.0;
330 let b = -5.0;
331 let expected_result = -5.0;
332 assert_eq!(Min::min_by_ref(&a, &b), &expected_result);
333 assert_eq!(Min::min_by_value(a, b), expected_result);
334 }
335
336 #[test]
337 #[cfg(debug_assertions)]
338 #[should_panic(expected = "Debug validation of left value failed: Value is NaN")]
339 fn test_f64_min_nan_value() {
340 let a = f64::NAN;
341 let b = 5.0;
342 let _result = Min::min_by_ref(&a, &b);
343 }
344
345 #[test]
346 #[cfg(debug_assertions)]
347 #[should_panic(expected = "Debug validation of right value failed: Value is NaN")]
348 fn test_f64_min_nan_other() {
349 let a = 3.0;
350 let b = f64::NAN;
351 let _result = Min::min_by_ref(&a, &b);
352 }
353 }
354
355 mod native64_strict_finite {
356 use try_create::TryNew;
357
358 use super::*;
359 use crate::backends::native::validated::RealNative64StrictFinite;
360
361 #[test]
362 fn test_f64_min_validated() {
363 let a = RealNative64StrictFinite::try_new(3.0).unwrap();
364 let b = RealNative64StrictFinite::try_new(5.0).unwrap();
365 let expected_result = RealNative64StrictFinite::try_new(3.0).unwrap();
366 assert_eq!(Min::min_by_ref(&a, &b), &expected_result);
367 assert_eq!(Min::min_by_value(a, b), expected_result);
368 }
369
370 #[test]
371 fn test_f64_min_validated_equal() {
372 let a = RealNative64StrictFinite::try_new(3.0).unwrap();
373 let b = RealNative64StrictFinite::try_new(3.0).unwrap();
374 let expected_result = RealNative64StrictFinite::try_new(3.0).unwrap();
375 assert_eq!(Min::min_by_ref(&a, &b), &expected_result);
376 assert_eq!(Min::min_by_value(a, b), expected_result);
377 }
378 }
379 }
380}
381