lilliput_float/
be_bytes.rs

1use crate::floats::{F16, F24, F32, F40, F48, F56, F64, F8};
2
3pub trait FpFromBeBytes {
4    type Bytes;
5
6    fn from_be_bytes(be_bytes: Self::Bytes) -> Self;
7}
8
9macro_rules! impl_float_from_be_bytes {
10    ($t:ty => bytes: [u8; $bytes:expr], bits: $bits:ty) => {
11        impl FpFromBeBytes for $t {
12            type Bytes = [u8; $bytes];
13
14            fn from_be_bytes(be_bytes: Self::Bytes) -> Self {
15                const PADDED_BYTES: usize = (<$bits>::BITS / u8::BITS) as usize;
16                const PADDING: usize = (PADDED_BYTES - $bytes) as usize;
17                let zeroed_bits: $bits = 0b0;
18                let mut padded_be_bytes: [u8; PADDED_BYTES] = zeroed_bits.to_be_bytes();
19                padded_be_bytes[PADDING..].copy_from_slice(&be_bytes);
20                Self(<$bits>::from_be_bytes(padded_be_bytes))
21            }
22        }
23    };
24}
25
26impl_float_from_be_bytes!(F8 => bytes: [u8; 1], bits: u8);
27impl_float_from_be_bytes!(F16 => bytes: [u8; 2], bits: u16);
28impl_float_from_be_bytes!(F24 => bytes: [u8; 3], bits: u32);
29impl_float_from_be_bytes!(F32 => bytes: [u8; 4], bits: u32);
30impl_float_from_be_bytes!(F40 => bytes: [u8; 5], bits: u64);
31impl_float_from_be_bytes!(F48 => bytes: [u8; 6], bits: u64);
32impl_float_from_be_bytes!(F56 => bytes: [u8; 7], bits: u64);
33impl_float_from_be_bytes!(F64 => bytes: [u8; 8], bits: u64);
34
35pub trait FpToBeBytes {
36    type Bytes;
37
38    fn to_be_bytes(self) -> Self::Bytes;
39}
40
41macro_rules! impl_float_to_be_bytes {
42    ($t:ty => bytes: [u8; $bytes:expr], bits: $bits:ty) => {
43        impl FpToBeBytes for $t {
44            type Bytes = [u8; $bytes];
45
46            fn to_be_bytes(self) -> Self::Bytes {
47                const PADDED_BYTES: usize = (<$bits>::BITS / u8::BITS) as usize;
48                const PADDING: usize = (PADDED_BYTES - $bytes) as usize;
49                let padded_be_bytes: [u8; PADDED_BYTES] = self.0.to_be_bytes();
50                let mut be_bytes: [u8; $bytes] = [0b0; $bytes];
51                be_bytes.copy_from_slice(&padded_be_bytes[PADDING..]);
52                be_bytes
53            }
54        }
55    };
56}
57
58impl_float_to_be_bytes!(F8 => bytes: [u8; 1], bits: u8);
59impl_float_to_be_bytes!(F16 => bytes: [u8; 2], bits: u16);
60impl_float_to_be_bytes!(F24 => bytes: [u8; 3], bits: u32);
61impl_float_to_be_bytes!(F32 => bytes: [u8; 4], bits: u32);
62impl_float_to_be_bytes!(F40 => bytes: [u8; 5], bits: u64);
63impl_float_to_be_bytes!(F48 => bytes: [u8; 6], bits: u64);
64impl_float_to_be_bytes!(F56 => bytes: [u8; 7], bits: u64);
65impl_float_to_be_bytes!(F64 => bytes: [u8; 8], bits: u64);
66
67#[cfg(test)]
68mod tests {
69    use proptest::prelude::*;
70
71    use super::*;
72
73    proptest! {
74        #[test]
75        fn f8_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 1]>::arbitrary()) {
76            let float = F8::from_be_bytes(be_bytes_before);
77            let be_bytes_after = float.to_be_bytes();
78            prop_assert_eq!(be_bytes_before, be_bytes_after);
79        }
80
81        #[test]
82        fn f16_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 2]>::arbitrary()) {
83            let float = F16::from_be_bytes(be_bytes_before);
84            let be_bytes_after = float.to_be_bytes();
85            prop_assert_eq!(be_bytes_before, be_bytes_after);
86        }
87
88        #[test]
89        fn f24_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 3]>::arbitrary()) {
90            let float = F24::from_be_bytes(be_bytes_before);
91            let be_bytes_after = float.to_be_bytes();
92            prop_assert_eq!(be_bytes_before, be_bytes_after);
93        }
94
95        #[test]
96        fn f32_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 4]>::arbitrary()) {
97            let float = F32::from_be_bytes(be_bytes_before);
98            let be_bytes_after = float.to_be_bytes();
99            prop_assert_eq!(be_bytes_before, be_bytes_after);
100        }
101
102        #[test]
103        fn f40_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 5]>::arbitrary()) {
104            let float = F40::from_be_bytes(be_bytes_before);
105            let be_bytes_after = float.to_be_bytes();
106            prop_assert_eq!(be_bytes_before, be_bytes_after);
107        }
108
109        #[test]
110        fn f48_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 6]>::arbitrary()) {
111            let float = F48::from_be_bytes(be_bytes_before);
112            let be_bytes_after = float.to_be_bytes();
113            prop_assert_eq!(be_bytes_before, be_bytes_after);
114        }
115
116        #[test]
117        fn f56_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 7]>::arbitrary()) {
118            let float = F56::from_be_bytes(be_bytes_before);
119            let be_bytes_after = float.to_be_bytes();
120            prop_assert_eq!(be_bytes_before, be_bytes_after);
121        }
122
123        #[test]
124        fn f64_from_to_be_bytes_roundtrip(be_bytes_before in <[u8; 8]>::arbitrary()) {
125            let float = F64::from_be_bytes(be_bytes_before);
126            let be_bytes_after = float.to_be_bytes();
127            prop_assert_eq!(be_bytes_before, be_bytes_after);
128        }
129    }
130}