Skip to main content

flatty_portable/
float.rs

1use crate::{derive_display, NativeCast, Portable};
2use core::{
3    cmp::{Ordering, PartialOrd},
4    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
5};
6use flatty_base::{
7    error::Error,
8    traits::{Flat, FlatValidate},
9};
10use num_traits::{Bounded, FromPrimitive, Num, NumCast, One, ToPrimitive, Zero};
11
12/// Generic portable floating-point number. Has alignment == 1.
13///
14/// Parameters:
15/// + `BE`: Endianness. `false` => little-endian, `true` => big-endian.
16/// + `N`: Width in bytes.
17#[repr(C)]
18#[derive(Clone, Copy, PartialEq, Eq, Hash)]
19pub struct Float<const BE: bool, const N: usize> {
20    bytes: [u8; N],
21}
22
23impl<const BE: bool, const N: usize> Default for Float<BE, N> {
24    fn default() -> Self {
25        Self { bytes: [0; N] }
26    }
27}
28
29impl<const BE: bool, const N: usize> Float<BE, N> {
30    pub fn from_bytes(bytes: [u8; N]) -> Self {
31        Self { bytes }
32    }
33    pub fn to_bytes(self) -> [u8; N] {
34        self.bytes
35    }
36}
37
38unsafe impl<const BE: bool, const N: usize> FlatValidate for Float<BE, N> {
39    unsafe fn validate_unchecked(_: &[u8]) -> Result<(), Error> {
40        Ok(())
41    }
42}
43
44unsafe impl<const BE: bool, const N: usize> Flat for Float<BE, N> {}
45
46unsafe impl<const BE: bool, const N: usize> Portable for Float<BE, N> {}
47
48macro_rules! derive_float {
49    ($self:ty, $native:ty, $from_bytes:ident, $to_bytes:ident$(,)?) => {
50        impl NativeCast for $self {
51            type Native = $native;
52            fn from_native(n: $native) -> Self {
53                Float::from_bytes(n.$to_bytes())
54            }
55            fn to_native(&self) -> Self::Native {
56                <$native>::$from_bytes(self.to_bytes())
57            }
58        }
59
60        impl From<$native> for $self {
61            fn from(n: $native) -> Self {
62                Self::from_native(n)
63            }
64        }
65        impl From<$self> for $native {
66            fn from(s: $self) -> Self {
67                s.to_native()
68            }
69        }
70
71        impl NumCast for $self {
72            fn from<T: ToPrimitive>(n: T) -> Option<Self> {
73                Some(Self::from_native(<$native as NumCast>::from::<T>(n)?))
74            }
75        }
76        impl ToPrimitive for $self {
77            fn to_u64(&self) -> Option<u64> {
78                self.to_native().to_u64()
79            }
80            fn to_i64(&self) -> Option<i64> {
81                self.to_native().to_i64()
82            }
83        }
84        impl FromPrimitive for $self {
85            fn from_u64(n: u64) -> Option<Self> {
86                Some(Float::from_native(<$native>::from_u64(n)?))
87            }
88            fn from_i64(n: i64) -> Option<Self> {
89                Some(Float::from_native(<$native>::from_i64(n)?))
90            }
91        }
92
93        impl Num for $self {
94            type FromStrRadixErr = <$native as Num>::FromStrRadixErr;
95            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
96                Ok(Self::from_native(<$native as Num>::from_str_radix(str, radix)?))
97            }
98        }
99
100        impl Bounded for $self {
101            fn min_value() -> Self {
102                Self::from_native(<$native>::MIN)
103            }
104            fn max_value() -> Self {
105                Self::from_native(<$native>::MAX)
106            }
107        }
108
109        impl One for $self {
110            fn one() -> Self {
111                Self::from_native(<$native>::one())
112            }
113        }
114        impl Zero for $self {
115            fn zero() -> Self {
116                Self::from_native(<$native>::zero())
117            }
118            fn is_zero(&self) -> bool {
119                self.to_native().is_zero()
120            }
121        }
122
123        impl Add for $self {
124            type Output = Self;
125            fn add(self, rhs: Self) -> Self {
126                Self::from_native(self.to_native() + rhs.to_native())
127            }
128        }
129        impl Sub for $self {
130            type Output = Self;
131            fn sub(self, rhs: Self) -> Self {
132                Self::from_native(self.to_native() - rhs.to_native())
133            }
134        }
135        impl Mul for $self {
136            type Output = Self;
137            fn mul(self, rhs: Self) -> Self {
138                Self::from_native(self.to_native() * rhs.to_native())
139            }
140        }
141        impl Div for $self {
142            type Output = Self;
143            fn div(self, rhs: Self) -> Self {
144                Self::from_native(self.to_native() / rhs.to_native())
145            }
146        }
147        impl Rem for $self {
148            type Output = Self;
149            fn rem(self, rhs: Self) -> Self {
150                Self::from_native(self.to_native() % rhs.to_native())
151            }
152        }
153        impl Neg for $self {
154            type Output = Self;
155            fn neg(self) -> Self::Output {
156                Self::from_native(-self.to_native())
157            }
158        }
159
160        impl PartialOrd for $self {
161            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
162                self.to_native().partial_cmp(&other.to_native())
163            }
164        }
165
166        impl AddAssign for $self {
167            fn add_assign(&mut self, rhs: Self) {
168                *self = self.add(rhs);
169            }
170        }
171        impl SubAssign for $self {
172            fn sub_assign(&mut self, rhs: Self) {
173                *self = self.sub(rhs);
174            }
175        }
176        impl MulAssign for $self {
177            fn mul_assign(&mut self, rhs: Self) {
178                *self = self.mul(rhs);
179            }
180        }
181        impl DivAssign for $self {
182            fn div_assign(&mut self, rhs: Self) {
183                *self = self.div(rhs);
184            }
185        }
186        impl RemAssign for $self {
187            fn rem_assign(&mut self, rhs: Self) {
188                *self = self.rem(rhs);
189            }
190        }
191
192        derive_display!($self, $native);
193    };
194}
195
196macro_rules! derive_le_float {
197    ($self:ty, $native:ty $(,)?) => {
198        derive_float!($self, $native, from_le_bytes, to_le_bytes);
199    };
200}
201
202macro_rules! derive_be_float {
203    ($self:ty, $native:ty $(,)?) => {
204        derive_float!($self, $native, from_be_bytes, to_be_bytes);
205    };
206}
207
208derive_le_float!(Float<false, 4>, f32);
209derive_le_float!(Float<false, 8>, f64);
210
211derive_be_float!(Float<true, 4>, f32);
212derive_be_float!(Float<true, 8>, f64);
213
214pub mod le {
215    use super::Float;
216
217    pub type F32 = Float<false, 4>;
218    pub type F64 = Float<false, 8>;
219}
220
221pub mod be {
222    use super::Float;
223
224    pub type F32 = Float<true, 4>;
225    pub type F64 = Float<true, 8>;
226}