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    /// Read an unsigned n-bytes integer u64.
63    ///
64    /// # Panics
65    ///
66    /// Panics when `buf.len() < 1` or `buf.len() > 8`.
67    #[inline]
68    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]
84    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]
94    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]
104    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]
114    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]
124    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]
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]
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]
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)]
176pub enum RunTimeEndian {
177    /// Little endian byte order.
178    Little,
179    /// Big endian byte order.
180    Big,
181}
182
183impl Default for RunTimeEndian {
184    #[cfg(target_endian = "little")]
185    #[inline]
186    fn default() -> RunTimeEndian {
187        RunTimeEndian::Little
188    }
189
190    #[cfg(target_endian = "big")]
191    #[inline]
192    fn default() -> RunTimeEndian {
193        RunTimeEndian::Big
194    }
195}
196
197impl Endianity for RunTimeEndian {
198    #[inline]
199    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)]
206pub struct LittleEndian;
207
208impl Default for LittleEndian {
209    #[inline]
210    fn default() -> LittleEndian {
211        LittleEndian
212    }
213}
214
215impl Endianity for LittleEndian {
216    #[inline]
217    fn is_big_endian(self) -> bool {
218        false
219    }
220}
221
222/// Big endian byte order.
223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
224pub struct BigEndian;
225
226impl Default for BigEndian {
227    #[inline]
228    fn default() -> BigEndian {
229        BigEndian
230    }
231}
232
233impl Endianity for BigEndian {
234    #[inline]
235    fn is_big_endian(self) -> bool {
236        true
237    }
238}
239
240/// The native endianity for the target platform.
241#[cfg(target_endian = "little")]
242pub type NativeEndian = LittleEndian;
243
244#[cfg(target_endian = "little")]
245#[allow(non_upper_case_globals)]
246#[doc(hidden)]
247pub const NativeEndian: LittleEndian = LittleEndian;
248
249/// The native endianity for the target platform.
250#[cfg(target_endian = "big")]
251pub type NativeEndian = BigEndian;
252
253#[cfg(target_endian = "big")]
254#[allow(non_upper_case_globals)]
255#[doc(hidden)]
256pub const NativeEndian: BigEndian = BigEndian;