1 //! Types for compile-time and run-time endianity. 2 3 use core::convert::TryInto; 4 use core::fmt::Debug; 5 6 /// A trait describing the endianity of some buffer. 7 pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { 8 /// Return true for big endian byte order. is_big_endian(self) -> bool9 fn is_big_endian(self) -> bool; 10 11 /// Return true for little endian byte order. 12 #[inline] is_little_endian(self) -> bool13 fn is_little_endian(self) -> bool { 14 !self.is_big_endian() 15 } 16 17 /// Reads an unsigned 16 bit integer from `buf`. 18 /// 19 /// # Panics 20 /// 21 /// Panics when `buf.len() < 2`. 22 #[inline] read_u16(self, buf: &[u8]) -> u1623 fn read_u16(self, buf: &[u8]) -> u16 { 24 let bytes: &[u8; 2] = buf[..2].try_into().unwrap(); 25 if self.is_big_endian() { 26 u16::from_be_bytes(*bytes) 27 } else { 28 u16::from_le_bytes(*bytes) 29 } 30 } 31 32 /// Reads an unsigned 32 bit integer from `buf`. 33 /// 34 /// # Panics 35 /// 36 /// Panics when `buf.len() < 4`. 37 #[inline] read_u32(self, buf: &[u8]) -> u3238 fn read_u32(self, buf: &[u8]) -> u32 { 39 let bytes: &[u8; 4] = buf[..4].try_into().unwrap(); 40 if self.is_big_endian() { 41 u32::from_be_bytes(*bytes) 42 } else { 43 u32::from_le_bytes(*bytes) 44 } 45 } 46 47 /// Reads an unsigned 64 bit integer from `buf`. 48 /// 49 /// # Panics 50 /// 51 /// Panics when `buf.len() < 8`. 52 #[inline] read_u64(self, buf: &[u8]) -> u6453 fn read_u64(self, buf: &[u8]) -> u64 { 54 let bytes: &[u8; 8] = buf[..8].try_into().unwrap(); 55 if self.is_big_endian() { 56 u64::from_be_bytes(*bytes) 57 } else { 58 u64::from_le_bytes(*bytes) 59 } 60 } 61 62 /// Read an unsigned n-bytes integer u64. 63 /// 64 /// # Panics 65 /// 66 /// Panics when `buf.len() < 1` or `buf.len() > 8`. 67 #[inline] read_uint(&mut self, buf: &[u8]) -> u6468 fn read_uint(&mut self, buf: &[u8]) -> u64 { 69 let mut tmp = [0; 8]; 70 if self.is_big_endian() { 71 tmp[8 - buf.len()..].copy_from_slice(buf); 72 } else { 73 tmp[..buf.len()].copy_from_slice(buf); 74 } 75 self.read_u64(&tmp) 76 } 77 78 /// Reads a signed 16 bit integer from `buf`. 79 /// 80 /// # Panics 81 /// 82 /// Panics when `buf.len() < 2`. 83 #[inline] read_i16(self, buf: &[u8]) -> i1684 fn read_i16(self, buf: &[u8]) -> i16 { 85 self.read_u16(buf) as i16 86 } 87 88 /// Reads a signed 32 bit integer from `buf`. 89 /// 90 /// # Panics 91 /// 92 /// Panics when `buf.len() < 4`. 93 #[inline] read_i32(self, buf: &[u8]) -> i3294 fn read_i32(self, buf: &[u8]) -> i32 { 95 self.read_u32(buf) as i32 96 } 97 98 /// Reads a signed 64 bit integer from `buf`. 99 /// 100 /// # Panics 101 /// 102 /// Panics when `buf.len() < 8`. 103 #[inline] read_i64(self, buf: &[u8]) -> i64104 fn read_i64(self, buf: &[u8]) -> i64 { 105 self.read_u64(buf) as i64 106 } 107 108 /// Reads a 32 bit floating point number from `buf`. 109 /// 110 /// # Panics 111 /// 112 /// Panics when `buf.len() < 8`. 113 #[inline] read_f32(self, buf: &[u8]) -> f32114 fn read_f32(self, buf: &[u8]) -> f32 { 115 f32::from_bits(self.read_u32(buf)) 116 } 117 118 /// Reads a 32 bit floating point number from `buf`. 119 /// 120 /// # Panics 121 /// 122 /// Panics when `buf.len() < 8`. 123 #[inline] read_f64(self, buf: &[u8]) -> f64124 fn read_f64(self, buf: &[u8]) -> f64 { 125 f64::from_bits(self.read_u64(buf)) 126 } 127 128 /// Writes an unsigned 16 bit integer `n` to `buf`. 129 /// 130 /// # Panics 131 /// 132 /// Panics when `buf.len() < 2`. 133 #[inline] write_u16(self, buf: &mut [u8], n: u16)134 fn write_u16(self, buf: &mut [u8], n: u16) { 135 let bytes = if self.is_big_endian() { 136 n.to_be_bytes() 137 } else { 138 n.to_le_bytes() 139 }; 140 buf[..2].copy_from_slice(&bytes); 141 } 142 143 /// Writes an unsigned 32 bit integer `n` to `buf`. 144 /// 145 /// # Panics 146 /// 147 /// Panics when `buf.len() < 4`. 148 #[inline] write_u32(self, buf: &mut [u8], n: u32)149 fn write_u32(self, buf: &mut [u8], n: u32) { 150 let bytes = if self.is_big_endian() { 151 n.to_be_bytes() 152 } else { 153 n.to_le_bytes() 154 }; 155 buf[..4].copy_from_slice(&bytes); 156 } 157 158 /// Writes an unsigned 64 bit integer `n` to `buf`. 159 /// 160 /// # Panics 161 /// 162 /// Panics when `buf.len() < 8`. 163 #[inline] write_u64(self, buf: &mut [u8], n: u64)164 fn write_u64(self, buf: &mut [u8], n: u64) { 165 let bytes = if self.is_big_endian() { 166 n.to_be_bytes() 167 } else { 168 n.to_le_bytes() 169 }; 170 buf[..8].copy_from_slice(&bytes); 171 } 172 } 173 174 /// Byte order that is selectable at runtime. 175 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 176 pub enum RunTimeEndian { 177 /// Little endian byte order. 178 Little, 179 /// Big endian byte order. 180 Big, 181 } 182 183 impl Default for RunTimeEndian { 184 #[cfg(target_endian = "little")] 185 #[inline] default() -> RunTimeEndian186 fn default() -> RunTimeEndian { 187 RunTimeEndian::Little 188 } 189 190 #[cfg(target_endian = "big")] 191 #[inline] default() -> RunTimeEndian192 fn default() -> RunTimeEndian { 193 RunTimeEndian::Big 194 } 195 } 196 197 impl Endianity for RunTimeEndian { 198 #[inline] is_big_endian(self) -> bool199 fn is_big_endian(self) -> bool { 200 self != RunTimeEndian::Little 201 } 202 } 203 204 /// Little endian byte order. 205 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 206 pub struct LittleEndian; 207 208 impl Default for LittleEndian { 209 #[inline] default() -> LittleEndian210 fn default() -> LittleEndian { 211 LittleEndian 212 } 213 } 214 215 impl Endianity for LittleEndian { 216 #[inline] is_big_endian(self) -> bool217 fn is_big_endian(self) -> bool { 218 false 219 } 220 } 221 222 /// Big endian byte order. 223 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 224 pub struct BigEndian; 225 226 impl Default for BigEndian { 227 #[inline] default() -> BigEndian228 fn default() -> BigEndian { 229 BigEndian 230 } 231 } 232 233 impl Endianity for BigEndian { 234 #[inline] is_big_endian(self) -> bool235 fn is_big_endian(self) -> bool { 236 true 237 } 238 } 239 240 /// The native endianity for the target platform. 241 #[cfg(target_endian = "little")] 242 pub type NativeEndian = LittleEndian; 243 244 #[cfg(target_endian = "little")] 245 #[allow(non_upper_case_globals)] 246 #[doc(hidden)] 247 pub const NativeEndian: LittleEndian = LittleEndian; 248 249 /// The native endianity for the target platform. 250 #[cfg(target_endian = "big")] 251 pub type NativeEndian = BigEndian; 252 253 #[cfg(target_endian = "big")] 254 #[allow(non_upper_case_globals)] 255 #[doc(hidden)] 256 pub const NativeEndian: BigEndian = BigEndian; 257