integer_encoding/
fixed.rs

1use std::mem::{size_of, transmute};
2
3/// `FixedInt` provides encoding/decoding to and from fixed int representations.
4///
5/// The emitted bytestring contains the bytes of the integer in machine endianness.
6pub trait FixedInt: Sized + Copy {
7    const REQUIRED_SPACE: usize;
8    /// Returns how many bytes are required to represent the given type.
9    fn required_space() -> usize;
10    /// Encode a value into the given slice. `dst` must be exactly `REQUIRED_SPACE` bytes.
11    fn encode_fixed(self, dst: &mut [u8]);
12    /// Decode a value from the given slice. `src` must be exactly `REQUIRED_SPACE` bytes.
13    fn decode_fixed(src: &[u8]) -> Self;
14    /// Perform a transmute, i.e. return a "view" into the integer's memory, which is faster than
15    /// performing a copy.
16    fn encode_fixed_light<'a>(&'a self) -> &'a [u8];
17
18    /// Helper: Encode the value and return a Vec.
19    fn encode_fixed_vec(self) -> Vec<u8> {
20        let mut v = Vec::new();
21        v.resize(Self::required_space(), 0);
22        self.encode_fixed(&mut v[..]);
23        v
24    }
25    /// Helper: Decode the value from the Vec.
26    fn decode_fixed_vec(v: &Vec<u8>) -> Self {
27        assert_eq!(v.len(), Self::required_space());
28        Self::decode_fixed(&v[..])
29    }
30}
31
32macro_rules! impl_fixedint {
33    ($t:ty) => {
34        impl FixedInt for $t {
35            const REQUIRED_SPACE: usize = size_of::<Self>();
36
37            fn required_space() -> usize {
38                Self::REQUIRED_SPACE
39            }
40
41            fn encode_fixed_light<'a>(&'a self) -> &'a [u8] {
42                return unsafe {
43                    std::slice::from_raw_parts(
44                        transmute::<&$t, *const u8>(&self),
45                        Self::REQUIRED_SPACE,
46                    )
47                };
48            }
49
50            fn encode_fixed(self, dst: &mut [u8]) {
51                assert_eq!(dst.len(), Self::REQUIRED_SPACE);
52
53                #[allow(unused_mut)]
54                let mut encoded =
55                    unsafe { &*(&self as *const $t as *const [u8; Self::REQUIRED_SPACE]) };
56
57                #[cfg(target_endian = "big")]
58                if Self::REQUIRED_SPACE > 1 {
59                    let mut encoded_rev = [0 as u8; Self::REQUIRED_SPACE];
60                    encoded_rev.copy_from_slice(encoded);
61                    encoded_rev.reverse();
62                    dst.clone_from_slice(&encoded_rev);
63                    return;
64                }
65
66                dst.clone_from_slice(encoded);
67            }
68
69            #[cfg(target_endian = "little")]
70            fn decode_fixed(src: &[u8]) -> $t {
71                unsafe { (src.as_ptr() as *const $t).read_unaligned() }
72            }
73
74            #[cfg(target_endian = "big")]
75            fn decode_fixed(src: &[u8]) -> $t {
76                match Self::REQUIRED_SPACE {
77                    1 => unsafe { (src.as_ptr() as *const $t).read_unaligned() },
78                    _ => {
79                        let mut src_fin = [0 as u8; Self::REQUIRED_SPACE];
80                        src_fin.copy_from_slice(src);
81                        src_fin.reverse();
82                        unsafe { (src_fin.as_ptr() as *const $t).read_unaligned() }
83                    }
84                }
85            }
86        }
87    };
88}
89
90impl_fixedint!(usize);
91impl_fixedint!(u64);
92impl_fixedint!(u32);
93impl_fixedint!(u16);
94impl_fixedint!(u8);
95impl_fixedint!(isize);
96impl_fixedint!(i64);
97impl_fixedint!(i32);
98impl_fixedint!(i16);
99impl_fixedint!(i8);