//! Provides traits for types that can be represented as both big and little-endian byte arrays. //! Types that have a "canonical" byte array representation are not appropriate implementors of //! [`ByteOrdered`]. #![feature(generic_const_exprs)] mod private { pub trait Sealed {} } /// Order of bits or bytes. pub trait Order { fn from_bytes(bytes: [u8; T::BYTES]) -> T; fn to_bytes(value: T) -> [u8; T::BYTES]; } #[derive(Clone, Copy)] pub struct Big; #[derive(Clone, Copy)] pub struct Little; impl Order for Big { #[inline(always)] fn from_bytes(bytes: [u8; T::BYTES]) -> T { T::from_be_bytes(bytes) } #[inline(always)] fn to_bytes(value: T) -> [u8; T::BYTES] { value.to_be_bytes() } } impl Order for Little { #[inline(always)] fn from_bytes(bytes: [u8; T::BYTES]) -> T { T::from_le_bytes(bytes) } #[inline(always)] fn to_bytes(value: T) -> [u8; T::BYTES] { value.to_le_bytes() } } pub trait ByteOrdered: Copy { /// Length of the type in bytes. const BYTES: usize; #[inline(always)] fn to_bytes(self) -> [u8; Self::BYTES] { O::to_bytes(self) } #[inline(always)] fn from_bytes(bytes: [u8; Self::BYTES]) -> Self { O::from_bytes(bytes) } fn to_be_bytes(self) -> [u8; Self::BYTES]; fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self; fn to_le_bytes(self) -> [u8; Self::BYTES]; fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self; } // TODO: file a bug report "Use-sites of this trait as a bound are required to also duplicate the // where clause" pub trait ByteOrderedA: ByteOrdered where [(); ::BYTES]:, { } impl ByteOrderedA for T where T: ByteOrdered, [(); T::BYTES]:, { } macro_rules! num_impl { ($ty:ty) => { impl ByteOrdered for $ty { const BYTES: usize = std::mem::size_of::<$ty>(); #[inline(always)] fn to_be_bytes(self) -> [u8; Self::BYTES] { <$ty>::to_be_bytes(self) } #[inline(always)] fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self { <$ty>::from_be_bytes(bytes) } #[inline(always)] fn to_le_bytes(self) -> [u8; Self::BYTES] { <$ty>::to_le_bytes(self) } #[inline(always)] fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self { <$ty>::from_le_bytes(bytes) } } }; } num_impl!(u8); num_impl!(u16); num_impl!(u32); num_impl!(u64); num_impl!(u128); num_impl!(i8); num_impl!(i16); num_impl!(i32); num_impl!(i64); num_impl!(i128); num_impl!(f32); num_impl!(f64); #[cfg(test)] mod tests { use super::*; #[test] fn to_be_bytes() { const CASES: &[(u32, [u8; 4])] = &[ (0x420, [0x00, 0x00, 0x04, 0x20]), (0x69, [0x00, 0x00, 0x00, 0x69]), (u32::MAX, [0xFF, 0xFF, 0xFF, 0xFF]), (32, [0, 0, 0, 32]), ]; for (n, bytes) in CASES { assert_eq!(n.to_be_bytes(), *bytes); assert_eq!(n.to_bytes::(), *bytes); assert_eq!(Big::to_bytes(*n), *bytes); assert_eq!(u32::from_be_bytes(*bytes), *n); } } #[test] fn to_le_bytes() { const CASES: &[(u32, [u8; 4])] = &[ (0x420, [0x20, 0x04, 0x00, 0x00]), (0x69, [0x69, 0x00, 0x00, 0x00]), (u32::MAX, [0xFF, 0xFF, 0xFF, 0xFF]), (32, [32, 0, 0, 0]), ]; for (n, bytes) in CASES { assert_eq!(n.to_le_bytes(), *bytes); assert_eq!(n.to_bytes::(), *bytes); assert_eq!(Little::to_bytes(*n), *bytes); assert_eq!(u32::from_le_bytes(*bytes), *n); } } }