lilliput_float/
bits.rs

1use crate::floats::{F16, F24, F32, F40, F48, F56, F64, F8};
2
3pub trait FpFromBits {
4    type Bits;
5
6    fn from_bits(bits: Self::Bits) -> Self;
7}
8
9macro_rules! impl_float_from_bits {
10    ($t:ty => bytes: [u8; $bytes:expr], bits: $bits:ty) => {
11        impl FpFromBits for $t {
12            type Bits = $bits;
13
14            fn from_bits(bits: Self::Bits) -> Self {
15                const PADDED_BYTES: usize = (<$bits>::BITS / u8::BITS) as usize;
16                const PADDING: usize = (PADDED_BYTES - $bytes) as usize;
17                const MASK: $bits = (!0b0) >> PADDING;
18                debug_assert_eq!(bits, bits & MASK);
19
20                Self(bits & MASK)
21            }
22        }
23    };
24}
25
26impl_float_from_bits!(F8 => bytes: [u8; 1], bits: u8);
27impl_float_from_bits!(F16 => bytes: [u8; 2], bits: u16);
28impl_float_from_bits!(F24 => bytes: [u8; 3], bits: u32);
29impl_float_from_bits!(F32 => bytes: [u8; 4], bits: u32);
30impl_float_from_bits!(F40 => bytes: [u8; 5], bits: u64);
31impl_float_from_bits!(F48 => bytes: [u8; 6], bits: u64);
32impl_float_from_bits!(F56 => bytes: [u8; 7], bits: u64);
33impl_float_from_bits!(F64 => bytes: [u8; 8], bits: u64);
34
35pub trait FpToBits {
36    type Bits;
37
38    fn to_bits(self) -> Self::Bits;
39}
40
41macro_rules! impl_float_to_bits {
42    ($t:ty => bytes: [u8; $bytes:expr], bits: $bits:ty) => {
43        impl FpToBits for $t {
44            type Bits = $bits;
45
46            fn to_bits(self) -> Self::Bits {
47                self.0
48            }
49        }
50    };
51}
52
53impl_float_to_bits!(F8 => bytes: [u8; 1], bits: u8);
54impl_float_to_bits!(F16 => bytes: [u8; 2], bits: u16);
55impl_float_to_bits!(F24 => bytes: [u8; 3], bits: u32);
56impl_float_to_bits!(F32 => bytes: [u8; 4], bits: u32);
57impl_float_to_bits!(F40 => bytes: [u8; 5], bits: u64);
58impl_float_to_bits!(F48 => bytes: [u8; 6], bits: u64);
59impl_float_to_bits!(F56 => bytes: [u8; 7], bits: u64);
60impl_float_to_bits!(F64 => bytes: [u8; 8], bits: u64);
61
62#[cfg(test)]
63mod tests {
64    use proptest::prelude::*;
65
66    use super::*;
67
68    proptest! {
69        #[test]
70        fn f8_from_to_bits_roundtrip(bits_before in (0_u8..=!0b_0)) {
71            let float = F8::from_bits(bits_before);
72            let bits_after = float.to_bits();
73            prop_assert_eq!(bits_before, bits_after);
74        }
75
76        #[test]
77        fn f16_from_to_bits_roundtrip(bits_before in (0_u16..=!0b_0)) {
78            let float = F16::from_bits(bits_before);
79            let bits_after = float.to_bits();
80            prop_assert_eq!(bits_before, bits_after);
81        }
82
83        #[test]
84        fn f24_from_to_bits_roundtrip(bits_before in (0_u32..=(!0b_0 >> 8))) {
85            let float = F24::from_bits(bits_before);
86            let bits_after = float.to_bits();
87            prop_assert_eq!(bits_before, bits_after);
88        }
89
90        #[test]
91        fn f32_from_to_bits_roundtrip(bits_before in (0_u32..=!0b_0)) {
92            let float = F32::from_bits(bits_before);
93            let bits_after = float.to_bits();
94            prop_assert_eq!(bits_before, bits_after);
95        }
96
97        #[test]
98        fn f40_from_to_bits_roundtrip(bits_before in (0_u64..=(!0b_0 >> 24))) {
99            let float = F40::from_bits(bits_before);
100            let bits_after = float.to_bits();
101            prop_assert_eq!(bits_before, bits_after);
102        }
103
104        #[test]
105        fn f48_from_to_bits_roundtrip(bits_before in (0_u64..=(!0b_0 >> 16))) {
106            let float = F48::from_bits(bits_before);
107            let bits_after = float.to_bits();
108            prop_assert_eq!(bits_before, bits_after);
109        }
110
111        #[test]
112        fn f56_from_to_bits_roundtrip(bits_before in (0_u64..=(!0b_0 >> 8))) {
113            let float = F56::from_bits(bits_before);
114            let bits_after = float.to_bits();
115            prop_assert_eq!(bits_before, bits_after);
116        }
117
118        #[test]
119        fn f64_from_to_bits_roundtrip(bits_before in (0_u64..=!0b_0)) {
120            let float = F64::from_bits(bits_before);
121            let bits_after = float.to_bits();
122            prop_assert_eq!(bits_before, bits_after);
123        }
124    }
125}