| /// A trait for working with structs as little-endian byte arrays. Automatically | |
| /// implemented for all built-in signed/unsigned integers. | |
| pub trait LeBytes: Sized { | |
| /// Write the memory representation of `self` as a byte array in | |
| /// little-endian byte order into the provided buffer. | |
| #[allow(clippy::wrong_self_convention)] | |
| fn to_le_bytes(self, buf: &mut [u8]) -> Option<usize>; | |
| /// Parse `self` from a byte array in little-endian byte order. | |
| /// Returns None upon overflow. | |
| fn from_le_bytes(buf: &[u8]) -> Option<Self>; | |
| } | |
| macro_rules! impl_to_le_bytes { | |
| ($($num:ty)*) => { | |
| $( | |
| impl LeBytes for $num { | |
| fn to_le_bytes(self, buf: &mut [u8]) -> Option<usize> { | |
| let len = core::mem::size_of::<$num>(); | |
| if buf.len() < len { | |
| return None | |
| } | |
| buf[..len].copy_from_slice(&<$num>::to_le_bytes(self)); | |
| Some(len) | |
| } | |
| fn from_le_bytes(buf: &[u8]) -> Option<Self> { | |
| let len = core::mem::size_of::<$num>(); | |
| let buf = if buf.len() > len { | |
| let (extra, buf) = buf.split_at(buf.len() - len); | |
| if extra.iter().any(|&b| b != 0) { | |
| return None | |
| } | |
| buf | |
| } else { | |
| buf | |
| }; | |
| let mut res: Self = 0; | |
| for b in buf.iter().copied().rev() { | |
| let b: Self = b as Self; | |
| // `res <<= 8` causes the compiler to complain in the `u8` case | |
| res <<= 4; | |
| res <<= 4; | |
| res |= b; | |
| } | |
| Some(res) | |
| } | |
| } | |
| )* | |
| }; | |
| } | |
| impl_to_le_bytes!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| #[test] | |
| fn basic() { | |
| assert_eq!( | |
| 0x12345678, | |
| LeBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]).unwrap() | |
| ) | |
| } | |
| #[test] | |
| fn small() { | |
| assert_eq!( | |
| 0x123456, | |
| LeBytes::from_le_bytes(&[0x56, 0x34, 0x12]).unwrap() | |
| ) | |
| } | |
| #[test] | |
| fn too_big() { | |
| assert_eq!( | |
| 0x1234_u16, | |
| LeBytes::from_le_bytes(&[0xde, 0xad, 0xbe, 0xef]).unwrap_or(0x1234) | |
| ) | |
| } | |
| } |