| //! Types for compile-time and run-time endianity. |
| |
| use core::convert::TryInto; |
| use core::fmt::Debug; |
| |
| /// A trait describing the endianity of some buffer. |
| pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { |
| /// Return true for big endian byte order. |
| fn is_big_endian(self) -> bool; |
| |
| /// Return true for little endian byte order. |
| #[inline] |
| fn is_little_endian(self) -> bool { |
| !self.is_big_endian() |
| } |
| |
| /// Reads an unsigned 16 bit integer from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 2`. |
| #[inline] |
| fn read_u16(self, buf: &[u8]) -> u16 { |
| let bytes: &[u8; 2] = buf[..2].try_into().unwrap(); |
| if self.is_big_endian() { |
| u16::from_be_bytes(*bytes) |
| } else { |
| u16::from_le_bytes(*bytes) |
| } |
| } |
| |
| /// Reads an unsigned 32 bit integer from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 4`. |
| #[inline] |
| fn read_u32(self, buf: &[u8]) -> u32 { |
| let bytes: &[u8; 4] = buf[..4].try_into().unwrap(); |
| if self.is_big_endian() { |
| u32::from_be_bytes(*bytes) |
| } else { |
| u32::from_le_bytes(*bytes) |
| } |
| } |
| |
| /// Reads an unsigned 64 bit integer from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 8`. |
| #[inline] |
| fn read_u64(self, buf: &[u8]) -> u64 { |
| let bytes: &[u8; 8] = buf[..8].try_into().unwrap(); |
| if self.is_big_endian() { |
| u64::from_be_bytes(*bytes) |
| } else { |
| u64::from_le_bytes(*bytes) |
| } |
| } |
| |
| /// Read an unsigned n-bytes integer u64. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 1` or `buf.len() > 8`. |
| #[inline] |
| fn read_uint(&mut self, buf: &[u8]) -> u64 { |
| let mut tmp = [0; 8]; |
| if self.is_big_endian() { |
| tmp[8 - buf.len()..].copy_from_slice(buf); |
| } else { |
| tmp[..buf.len()].copy_from_slice(buf); |
| } |
| self.read_u64(&tmp) |
| } |
| |
| /// Reads a signed 16 bit integer from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 2`. |
| #[inline] |
| fn read_i16(self, buf: &[u8]) -> i16 { |
| self.read_u16(buf) as i16 |
| } |
| |
| /// Reads a signed 32 bit integer from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 4`. |
| #[inline] |
| fn read_i32(self, buf: &[u8]) -> i32 { |
| self.read_u32(buf) as i32 |
| } |
| |
| /// Reads a signed 64 bit integer from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 8`. |
| #[inline] |
| fn read_i64(self, buf: &[u8]) -> i64 { |
| self.read_u64(buf) as i64 |
| } |
| |
| /// Reads a 32 bit floating point number from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 8`. |
| #[inline] |
| fn read_f32(self, buf: &[u8]) -> f32 { |
| f32::from_bits(self.read_u32(buf)) |
| } |
| |
| /// Reads a 32 bit floating point number from `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 8`. |
| #[inline] |
| fn read_f64(self, buf: &[u8]) -> f64 { |
| f64::from_bits(self.read_u64(buf)) |
| } |
| |
| /// Writes an unsigned 16 bit integer `n` to `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 2`. |
| #[inline] |
| fn write_u16(self, buf: &mut [u8], n: u16) { |
| let bytes = if self.is_big_endian() { |
| n.to_be_bytes() |
| } else { |
| n.to_le_bytes() |
| }; |
| buf[..2].copy_from_slice(&bytes); |
| } |
| |
| /// Writes an unsigned 32 bit integer `n` to `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 4`. |
| #[inline] |
| fn write_u32(self, buf: &mut [u8], n: u32) { |
| let bytes = if self.is_big_endian() { |
| n.to_be_bytes() |
| } else { |
| n.to_le_bytes() |
| }; |
| buf[..4].copy_from_slice(&bytes); |
| } |
| |
| /// Writes an unsigned 64 bit integer `n` to `buf`. |
| /// |
| /// # Panics |
| /// |
| /// Panics when `buf.len() < 8`. |
| #[inline] |
| fn write_u64(self, buf: &mut [u8], n: u64) { |
| let bytes = if self.is_big_endian() { |
| n.to_be_bytes() |
| } else { |
| n.to_le_bytes() |
| }; |
| buf[..8].copy_from_slice(&bytes); |
| } |
| } |
| |
| /// Byte order that is selectable at runtime. |
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| pub enum RunTimeEndian { |
| /// Little endian byte order. |
| Little, |
| /// Big endian byte order. |
| Big, |
| } |
| |
| impl Default for RunTimeEndian { |
| #[cfg(target_endian = "little")] |
| #[inline] |
| fn default() -> RunTimeEndian { |
| RunTimeEndian::Little |
| } |
| |
| #[cfg(target_endian = "big")] |
| #[inline] |
| fn default() -> RunTimeEndian { |
| RunTimeEndian::Big |
| } |
| } |
| |
| impl Endianity for RunTimeEndian { |
| #[inline] |
| fn is_big_endian(self) -> bool { |
| self != RunTimeEndian::Little |
| } |
| } |
| |
| /// Little endian byte order. |
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| pub struct LittleEndian; |
| |
| impl Default for LittleEndian { |
| #[inline] |
| fn default() -> LittleEndian { |
| LittleEndian |
| } |
| } |
| |
| impl Endianity for LittleEndian { |
| #[inline] |
| fn is_big_endian(self) -> bool { |
| false |
| } |
| } |
| |
| /// Big endian byte order. |
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| pub struct BigEndian; |
| |
| impl Default for BigEndian { |
| #[inline] |
| fn default() -> BigEndian { |
| BigEndian |
| } |
| } |
| |
| impl Endianity for BigEndian { |
| #[inline] |
| fn is_big_endian(self) -> bool { |
| true |
| } |
| } |
| |
| /// The native endianity for the target platform. |
| #[cfg(target_endian = "little")] |
| pub type NativeEndian = LittleEndian; |
| |
| #[cfg(target_endian = "little")] |
| #[allow(non_upper_case_globals)] |
| #[doc(hidden)] |
| pub const NativeEndian: LittleEndian = LittleEndian; |
| |
| /// The native endianity for the target platform. |
| #[cfg(target_endian = "big")] |
| pub type NativeEndian = BigEndian; |
| |
| #[cfg(target_endian = "big")] |
| #[allow(non_upper_case_globals)] |
| #[doc(hidden)] |
| pub const NativeEndian: BigEndian = BigEndian; |