lilliput_float/
validator.rs

1use 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);