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;
257