Skip to main content

gimli/
endianity.rs

1//! Types for compile-time and run-time endianity.
2
3use core::convert::TryInto;
4use core::fmt::Debug;
5
6/// A trait describing the endianity of some buffer.
7pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq {
8    /// Return true for big endian byte order.
9    fn is_big_endian(self) -> bool;
10
11    /// Return true for little endian byte order.
12    #[inline]
13    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]
23    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]
38    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]
53    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    /// Reads an unsigned 128 bit integer from `buf`.
63    ///
64    /// # Panics
65    ///
66    /// Panics when `buf.len() < 16`.
67    #[inline]
68    fn read_u128(self, buf: &[u8]) -> u128 {
69        let bytes: &[u8; 16] = buf[..16].try_into().unwrap();
70        if self.is_big_endian() {
71            u128::from_be_bytes(*bytes)
72        } else {
73            u128::from_le_bytes(*bytes)
74        }
75    }
76
77    /// Read an unsigned n-bytes integer u64.
78    ///
79    /// # Panics
80    ///
81    /// Panics when `buf.len() < 1` or `buf.len() > 8`.
82    #[inline]
83    fn read_uint(&mut self, buf: &[u8]) -> u64 {
84        let mut tmp = [0; 8];
85        if self.is_big_endian() {
86            tmp[8 - buf.len()..].copy_from_slice(buf);
87        } else {
88            tmp[..buf.len()].copy_from_slice(buf);
89        }
90        self.read_u64(&tmp)
91    }
92
93    /// Reads a signed 16 bit integer from `buf`.
94    ///
95    /// # Panics
96    ///
97    /// Panics when `buf.len() < 2`.
98    #[inline]
99    fn read_i16(self, buf: &[u8]) -> i16 {
100        self.read_u16(buf) as i16
101    }
102
103    /// Reads a signed 32 bit integer from `buf`.
104    ///
105    /// # Panics
106    ///
107    /// Panics when `buf.len() < 4`.
108    #[inline]
109    fn read_i32(self, buf: &[u8]) -> i32 {
110        self.read_u32(buf) as i32
111    }
112
113    /// Reads a signed 64 bit integer from `buf`.
114    ///
115    /// # Panics
116    ///
117    /// Panics when `buf.len() < 8`.
118    #[inline]
119    fn read_i64(self, buf: &[u8]) -> i64 {
120        self.read_u64(buf) as i64
121    }
122
123    /// Reads a 32 bit floating point number from `buf`.
124    ///
125    /// # Panics
126    ///
127    /// Panics when `buf.len() < 8`.
128    #[inline]
129    fn read_f32(self, buf: &[u8]) -> f32 {
130        f32::from_bits(self.read_u32(buf))
131    }
132
133    /// Reads a 32 bit floating point number from `buf`.
134    ///
135    /// # Panics
136    ///
137    /// Panics when `buf.len() < 8`.
138    #[inline]
139    fn read_f64(self, buf: &[u8]) -> f64 {
140        f64::from_bits(self.read_u64(buf))
141    }
142
143    /// Writes an unsigned 16 bit integer `n` to `buf`.
144    ///
145    /// # Panics
146    ///
147    /// Panics when `buf.len() < 2`.
148    #[inline]
149    fn write_u16(self, buf: &mut [u8], n: u16) {
150        let bytes = if self.is_big_endian() {
151            n.to_be_bytes()
152        } else {
153            n.to_le_bytes()
154        };
155        buf[..2].copy_from_slice(&bytes);
156    }
157
158    /// Writes an unsigned 32 bit integer `n` to `buf`.
159    ///
160    /// # Panics
161    ///
162    /// Panics when `buf.len() < 4`.
163    #[inline]
164    fn write_u32(self, buf: &mut [u8], n: u32) {
165        let bytes = if self.is_big_endian() {
166            n.to_be_bytes()
167        } else {
168            n.to_le_bytes()
169        };
170        buf[..4].copy_from_slice(&bytes);
171    }
172
173    /// Writes an unsigned 64 bit integer `n` to `buf`.
174    ///
175    /// # Panics
176    ///
177    /// Panics when `buf.len() < 8`.
178    #[inline]
179    fn write_u64(self, buf: &mut [u8], n: u64) {
180        let bytes = if self.is_big_endian() {
181            n.to_be_bytes()
182        } else {
183            n.to_le_bytes()
184        };
185        buf[..8].copy_from_slice(&bytes);
186    }
187
188    /// Writes an unsigned 128 bit integer `n` to `buf`.
189    ///
190    /// # Panics
191    ///
192    /// Panics when `buf.len() < 16`.
193    #[inline]
194    fn write_u128(self, buf: &mut [u8], n: u128) {
195        let bytes = if self.is_big_endian() {
196            n.to_be_bytes()
197        } else {
198            n.to_le_bytes()
199        };
200        buf[..16].copy_from_slice(&bytes);
201    }
202}
203
204/// Byte order that is selectable at runtime.
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
206pub enum RunTimeEndian {
207    /// Little endian byte order.
208    Little,
209    /// Big endian byte order.
210    Big,
211}
212
213impl Default for RunTimeEndian {
214    #[cfg(target_endian = "little")]
215    #[inline]
216    fn default() -> RunTimeEndian {
217        RunTimeEndian::Little
218    }
219
220    #[cfg(target_endian = "big")]
221    #[inline]
222    fn default() -> RunTimeEndian {
223        RunTimeEndian::Big
224    }
225}
226
227impl Endianity for RunTimeEndian {
228    #[inline]
229    fn is_big_endian(self) -> bool {
230        self != RunTimeEndian::Little
231    }
232}
233
234/// Little endian byte order.
235#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
236pub struct LittleEndian;
237
238impl Default for LittleEndian {
239    #[inline]
240    fn default() -> LittleEndian {
241        LittleEndian
242    }
243}
244
245impl Endianity for LittleEndian {
246    #[inline]
247    fn is_big_endian(self) -> bool {
248        false
249    }
250}
251
252/// Big endian byte order.
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
254pub struct BigEndian;
255
256impl Default for BigEndian {
257    #[inline]
258    fn default() -> BigEndian {
259        BigEndian
260    }
261}
262
263impl Endianity for BigEndian {
264    #[inline]
265    fn is_big_endian(self) -> bool {
266        true
267    }
268}
269
270/// The native endianity for the target platform.
271#[cfg(target_endian = "little")]
272pub type NativeEndian = LittleEndian;
273
274#[cfg(target_endian = "little")]
275#[allow(non_upper_case_globals)]
276#[doc(hidden)]
277pub const NativeEndian: LittleEndian = LittleEndian;
278
279/// The native endianity for the target platform.
280#[cfg(target_endian = "big")]
281pub type NativeEndian = BigEndian;
282
283#[cfg(target_endian = "big")]
284#[allow(non_upper_case_globals)]
285#[doc(hidden)]
286pub const NativeEndian: BigEndian = BigEndian;