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