gdbstub/internal/
le_bytes.rs

1/// A trait for working with structs as little-endian byte arrays. Automatically
2/// implemented for all built-in signed/unsigned integers.
3pub trait LeBytes: Sized {
4    /// Write the memory representation of `self` as a byte array in
5    /// little-endian byte order into the provided buffer.
6    #[allow(clippy::wrong_self_convention)]
7    fn to_le_bytes(self, buf: &mut [u8]) -> Option<usize>;
8
9    /// Parse `self` from a byte array in little-endian byte order.
10    /// Returns None upon overflow.
11    fn from_le_bytes(buf: &[u8]) -> Option<Self>;
12}
13
14macro_rules! impl_to_le_bytes {
15    ($($num:ty)*) => {
16        $(
17            impl LeBytes for $num {
18                fn to_le_bytes(self, buf: &mut [u8]) -> Option<usize> {
19                    let len = core::mem::size_of::<$num>();
20                    if buf.len() < len {
21                        return None
22                    }
23                    buf[..len].copy_from_slice(&<$num>::to_le_bytes(self));
24                    Some(len)
25                }
26
27                fn from_le_bytes(buf: &[u8]) -> Option<Self> {
28                    let len = core::mem::size_of::<$num>();
29
30                    let buf = if buf.len() > len {
31                        let (extra, buf) = buf.split_at(buf.len() - len);
32                        if extra.iter().any(|&b| b != 0) {
33                            return None
34                        }
35                        buf
36                    } else {
37                        buf
38                    };
39
40                    let mut res: Self = 0;
41                    for b in buf.iter().copied().rev() {
42                        let b: Self = b as Self;
43                        // `res <<= 8` causes the compiler to complain in the `u8` case
44                        res <<= 4;
45                        res <<= 4;
46                        res |= b;
47                    }
48
49                    Some(res)
50                }
51            }
52        )*
53    };
54}
55
56impl_to_le_bytes!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn basic() {
64        assert_eq!(
65            0x12345678,
66            LeBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]).unwrap()
67        )
68    }
69
70    #[test]
71    fn small() {
72        assert_eq!(
73            0x123456,
74            LeBytes::from_le_bytes(&[0x56, 0x34, 0x12]).unwrap()
75        )
76    }
77
78    #[test]
79    fn too_big() {
80        assert_eq!(
81            0x1234_u16,
82            LeBytes::from_le_bytes(&[0xde, 0xad, 0xbe, 0xef]).unwrap_or(0x1234)
83        )
84    }
85}