lilliput-float 0.1.0

IEEE-754-compliant float-packing implementation, used in lilliput-core
Documentation
use std::num::FpCategory;

#[derive(Clone, PartialEq, Debug)]
pub enum PackedFloatValidator<T> {
    Relative(T),
    Absolute(T),
    Custom(fn(T, T) -> bool),
}

macro_rules! impl_packed_float_validator {
    ($t:ty) => {
        impl Default for PackedFloatValidator<$t> {
            fn default() -> Self {
                Self::Absolute(0.0)
            }
        }

        impl PackedFloatValidator<$t> {
            pub fn validate(&self, before: $t, after: $t) -> bool {
                match *self {
                    Self::Relative(relative_max_eps) => {
                        Self::validate_relative(before, after, relative_max_eps)
                    }
                    Self::Absolute(absolute_max_eps) => {
                        Self::validate_absolute(before, after, absolute_max_eps)
                    }
                    Self::Custom(custom_fn) => Self::validate_custom(before, after, custom_fn),
                }
            }

            fn validate_relative(before: $t, after: $t, relative_max_eps: $t) -> bool {
                let max_eps = before * relative_max_eps;
                Self::validate_absolute(before, after, max_eps)
            }

            fn validate_absolute(before: $t, after: $t, max_eps: $t) -> bool {
                let is_normal_or_subnormal = matches!(
                    before.classify(),
                    FpCategory::Normal | FpCategory::Subnormal
                );

                if is_normal_or_subnormal {
                    (before - after).abs() <= max_eps.abs()
                } else {
                    true
                }
            }

            fn validate_custom(before: $t, after: $t, custom_fn: fn($t, $t) -> bool) -> bool {
                let is_normal_or_subnormal = matches!(
                    before.classify(),
                    FpCategory::Normal | FpCategory::Subnormal
                );

                if is_normal_or_subnormal {
                    (custom_fn)(before, after)
                } else {
                    true
                }
            }
        }
    };
}

impl_packed_float_validator!(f32);
impl_packed_float_validator!(f64);