1use core::convert::TryInto;
4use core::fmt::Debug;
5
6pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq {
8    fn is_big_endian(self) -> bool;
10
11    #[inline]
13    fn is_little_endian(self) -> bool {
14        !self.is_big_endian()
15    }
16
17    #[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    #[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    #[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    #[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    #[inline]
84    fn read_i16(self, buf: &[u8]) -> i16 {
85        self.read_u16(buf) as i16
86    }
87
88    #[inline]
94    fn read_i32(self, buf: &[u8]) -> i32 {
95        self.read_u32(buf) as i32
96    }
97
98    #[inline]
104    fn read_i64(self, buf: &[u8]) -> i64 {
105        self.read_u64(buf) as i64
106    }
107
108    #[inline]
114    fn read_f32(self, buf: &[u8]) -> f32 {
115        f32::from_bits(self.read_u32(buf))
116    }
117
118    #[inline]
124    fn read_f64(self, buf: &[u8]) -> f64 {
125        f64::from_bits(self.read_u64(buf))
126    }
127
128    #[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    #[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    #[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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
176pub enum RunTimeEndian {
177    Little,
179    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#[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#[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#[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#[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;