lilliput_float/
validator.rs1use std::num::FpCategory;
2
3#[derive(Clone, PartialEq, Debug)]
4pub enum PackedFloatValidator<T> {
5 Relative(T),
6 Absolute(T),
7 Custom(fn(T, T) -> bool),
8}
9
10macro_rules! impl_packed_float_validator {
11 ($t:ty) => {
12 impl Default for PackedFloatValidator<$t> {
13 fn default() -> Self {
14 Self::Absolute(0.0)
15 }
16 }
17
18 impl PackedFloatValidator<$t> {
19 pub fn validate(&self, before: $t, after: $t) -> bool {
20 match *self {
21 Self::Relative(relative_max_eps) => {
22 Self::validate_relative(before, after, relative_max_eps)
23 }
24 Self::Absolute(absolute_max_eps) => {
25 Self::validate_absolute(before, after, absolute_max_eps)
26 }
27 Self::Custom(custom_fn) => Self::validate_custom(before, after, custom_fn),
28 }
29 }
30
31 fn validate_relative(before: $t, after: $t, relative_max_eps: $t) -> bool {
32 let max_eps = before * relative_max_eps;
33 Self::validate_absolute(before, after, max_eps)
34 }
35
36 fn validate_absolute(before: $t, after: $t, max_eps: $t) -> bool {
37 let is_normal_or_subnormal = matches!(
38 before.classify(),
39 FpCategory::Normal | FpCategory::Subnormal
40 );
41
42 if is_normal_or_subnormal {
43 (before - after).abs() <= max_eps.abs()
44 } else {
45 true
46 }
47 }
48
49 fn validate_custom(before: $t, after: $t, custom_fn: fn($t, $t) -> bool) -> bool {
50 let is_normal_or_subnormal = matches!(
51 before.classify(),
52 FpCategory::Normal | FpCategory::Subnormal
53 );
54
55 if is_normal_or_subnormal {
56 (custom_fn)(before, after)
57 } else {
58 true
59 }
60 }
61 }
62 };
63}
64
65impl_packed_float_validator!(f32);
66impl_packed_float_validator!(f64);