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