1 //! Types for compile-time and run-time endianity. 2 3 use byteorder; 4 use byteorder::ByteOrder; 5 use core::fmt::Debug; 6 7 /// A trait describing the endianity of some buffer. 8 pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { 9 /// Return true for big endian byte order. is_big_endian(self) -> bool10 fn is_big_endian(self) -> bool; 11 12 /// Return true for little endian byte order. 13 #[inline] is_little_endian(self) -> bool14 fn is_little_endian(self) -> bool { 15 !self.is_big_endian() 16 } 17 18 /// Reads an unsigned 16 bit integer from `buf`. 19 /// 20 /// # Panics 21 /// 22 /// Panics when `buf.len() < 2`. 23 #[inline] read_u16(self, buf: &[u8]) -> u1624 fn read_u16(self, buf: &[u8]) -> u16 { 25 if self.is_big_endian() { 26 byteorder::BigEndian::read_u16(buf) 27 } else { 28 byteorder::LittleEndian::read_u16(buf) 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 if self.is_big_endian() { 40 byteorder::BigEndian::read_u32(buf) 41 } else { 42 byteorder::LittleEndian::read_u32(buf) 43 } 44 } 45 46 /// Reads an unsigned 64 bit integer from `buf`. 47 /// 48 /// # Panics 49 /// 50 /// Panics when `buf.len() < 8`. 51 #[inline] read_u64(self, buf: &[u8]) -> u6452 fn read_u64(self, buf: &[u8]) -> u64 { 53 if self.is_big_endian() { 54 byteorder::BigEndian::read_u64(buf) 55 } else { 56 byteorder::LittleEndian::read_u64(buf) 57 } 58 } 59 60 /// Read an unsigned n-bytes integer u64. 61 /// 62 /// # Panics 63 /// 64 /// Panics when `buf.len() < 1` or `buf.len() > 8`. 65 #[inline] read_uint(&mut self, buf: &[u8]) -> u6466 fn read_uint(&mut self, buf: &[u8]) -> u64 { 67 if self.is_big_endian() { 68 byteorder::BigEndian::read_uint(buf, buf.len()) 69 } else { 70 byteorder::LittleEndian::read_uint(buf, buf.len()) 71 } 72 } 73 74 /// Reads a signed 16 bit integer from `buf`. 75 /// 76 /// # Panics 77 /// 78 /// Panics when `buf.len() < 2`. 79 #[inline] read_i16(self, buf: &[u8]) -> i1680 fn read_i16(self, buf: &[u8]) -> i16 { 81 self.read_u16(buf) as i16 82 } 83 84 /// Reads a signed 32 bit integer from `buf`. 85 /// 86 /// # Panics 87 /// 88 /// Panics when `buf.len() < 4`. 89 #[inline] read_i32(self, buf: &[u8]) -> i3290 fn read_i32(self, buf: &[u8]) -> i32 { 91 self.read_u32(buf) as i32 92 } 93 94 /// Reads a signed 64 bit integer from `buf`. 95 /// 96 /// # Panics 97 /// 98 /// Panics when `buf.len() < 8`. 99 #[inline] read_i64(self, buf: &[u8]) -> i64100 fn read_i64(self, buf: &[u8]) -> i64 { 101 self.read_u64(buf) as i64 102 } 103 104 /// Reads a 32 bit floating point number from `buf`. 105 /// 106 /// # Panics 107 /// 108 /// Panics when `buf.len() < 8`. 109 #[inline] read_f32(self, buf: &[u8]) -> f32110 fn read_f32(self, buf: &[u8]) -> f32 { 111 f32::from_bits(self.read_u32(buf)) 112 } 113 114 /// Reads a 32 bit floating point number from `buf`. 115 /// 116 /// # Panics 117 /// 118 /// Panics when `buf.len() < 8`. 119 #[inline] read_f64(self, buf: &[u8]) -> f64120 fn read_f64(self, buf: &[u8]) -> f64 { 121 f64::from_bits(self.read_u64(buf)) 122 } 123 124 /// Writes an unsigned 16 bit integer `n` to `buf`. 125 /// 126 /// # Panics 127 /// 128 /// Panics when `buf.len() < 2`. 129 #[inline] write_u16(self, buf: &mut [u8], n: u16)130 fn write_u16(self, buf: &mut [u8], n: u16) { 131 if self.is_big_endian() { 132 byteorder::BigEndian::write_u16(buf, n) 133 } else { 134 byteorder::LittleEndian::write_u16(buf, n) 135 } 136 } 137 138 /// Writes an unsigned 32 bit integer `n` to `buf`. 139 /// 140 /// # Panics 141 /// 142 /// Panics when `buf.len() < 4`. 143 #[inline] write_u32(self, buf: &mut [u8], n: u32)144 fn write_u32(self, buf: &mut [u8], n: u32) { 145 if self.is_big_endian() { 146 byteorder::BigEndian::write_u32(buf, n) 147 } else { 148 byteorder::LittleEndian::write_u32(buf, n) 149 } 150 } 151 152 /// Writes an unsigned 64 bit integer `n` to `buf`. 153 /// 154 /// # Panics 155 /// 156 /// Panics when `buf.len() < 8`. 157 #[inline] write_u64(self, buf: &mut [u8], n: u64)158 fn write_u64(self, buf: &mut [u8], n: u64) { 159 if self.is_big_endian() { 160 byteorder::BigEndian::write_u64(buf, n) 161 } else { 162 byteorder::LittleEndian::write_u64(buf, n) 163 } 164 } 165 } 166 167 /// Byte order that is selectable at runtime. 168 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 169 pub enum RunTimeEndian { 170 /// Little endian byte order. 171 Little, 172 /// Big endian byte order. 173 Big, 174 } 175 176 impl Default for RunTimeEndian { 177 #[cfg(target_endian = "little")] 178 #[inline] default() -> RunTimeEndian179 fn default() -> RunTimeEndian { 180 RunTimeEndian::Little 181 } 182 183 #[cfg(target_endian = "big")] 184 #[inline] default() -> RunTimeEndian185 fn default() -> RunTimeEndian { 186 RunTimeEndian::Big 187 } 188 } 189 190 impl Endianity for RunTimeEndian { 191 #[inline] is_big_endian(self) -> bool192 fn is_big_endian(self) -> bool { 193 self != RunTimeEndian::Little 194 } 195 } 196 197 /// Little endian byte order. 198 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 199 pub struct LittleEndian; 200 201 impl Default for LittleEndian { 202 #[inline] default() -> LittleEndian203 fn default() -> LittleEndian { 204 LittleEndian 205 } 206 } 207 208 impl Endianity for LittleEndian { 209 #[inline] is_big_endian(self) -> bool210 fn is_big_endian(self) -> bool { 211 false 212 } 213 } 214 215 /// Big endian byte order. 216 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 217 pub struct BigEndian; 218 219 impl Default for BigEndian { 220 #[inline] default() -> BigEndian221 fn default() -> BigEndian { 222 BigEndian 223 } 224 } 225 226 impl Endianity for BigEndian { 227 #[inline] is_big_endian(self) -> bool228 fn is_big_endian(self) -> bool { 229 true 230 } 231 } 232 233 /// The native endianity for the target platform. 234 #[cfg(target_endian = "little")] 235 pub type NativeEndian = LittleEndian; 236 237 #[cfg(target_endian = "little")] 238 #[allow(non_upper_case_globals)] 239 #[doc(hidden)] 240 pub const NativeEndian: LittleEndian = LittleEndian; 241 242 /// The native endianity for the target platform. 243 #[cfg(target_endian = "big")] 244 pub type NativeEndian = BigEndian; 245 246 #[cfg(target_endian = "big")] 247 #[allow(non_upper_case_globals)] 248 #[doc(hidden)] 249 pub const NativeEndian: BigEndian = BigEndian; 250