1//! Newtypes that exist mainly to make variants of f32/f64 that can safely implement Eq and Hash
2
3use bincode::{Decode, Encode};
4use std::fmt::{Display, Formatter};
5use std::ops::{Add, AddAssign, Mul, MulAssign};
6
7macro_rules! define_finite_float {
8    ($name:ident, $ft:ty, $ut:ty) => {
9        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)]
10        pub struct $name($ut);
11
12        impl $name {
13            pub const ZERO: Self = Self((0 as $ft).to_bits());
14            pub const ONE: Self = Self((1 as $ft).to_bits());
15
16            #[must_use]
17            pub fn get(self) -> $ft {
18                <$ft>::from_bits(self.0)
19            }
20        }
21
22        impl Default for $name {
23            #[inline]
24            fn default() -> Self {
25                Self::ZERO
26            }
27        }
28
29        impl Display for $name {
30            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31                write!(f, "{}", <$ft>::from_bits(self.0))
32            }
33        }
34
35        impl TryFrom<$ft> for $name {
36            type Error = String;
37
38            fn try_from(value: $ft) -> Result<Self, Self::Error> {
39                if value.is_finite() {
40                    Ok(Self(value.to_bits()))
41                } else {
42                    Err(format!("Not a finite value: {value}"))
43                }
44            }
45        }
46
47        impl From<$name> for $ft {
48            fn from(value: $name) -> Self {
49                <$ft>::from_bits(value.0)
50            }
51        }
52
53        impl Add for $name {
54            type Output = Self;
55
56            #[inline]
57            fn add(self, rhs: Self) -> Self::Output {
58                let lhs = <$ft>::from(self);
59                let rhs = <$ft>::from(rhs);
60                Self((lhs + rhs).to_bits())
61            }
62        }
63
64        impl AddAssign for $name {
65            #[inline]
66            fn add_assign(&mut self, rhs: Self) {
67                *self = *self + rhs;
68            }
69        }
70
71        impl Mul for $name {
72            type Output = Self;
73
74            #[inline]
75            fn mul(self, rhs: Self) -> Self::Output {
76                let lhs = <$ft>::from(self);
77                let rhs = <$ft>::from(rhs);
78                Self((lhs * rhs).to_bits())
79            }
80        }
81
82        impl MulAssign for $name {
83            #[inline]
84            fn mul_assign(&mut self, rhs: Self) {
85                *self = *self * rhs;
86            }
87        }
88    };
89}
90
91define_finite_float!(FiniteF32, f32, u32);
92define_finite_float!(FiniteF64, f64, u64);