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. |
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)] |
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 ] |
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 | |
197 | impl 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)] |
206 | pub struct LittleEndian; |
207 | |
208 | impl Default for LittleEndian { |
209 | #[inline ] |
210 | fn default() -> LittleEndian { |
211 | LittleEndian |
212 | } |
213 | } |
214 | |
215 | impl 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)] |
224 | pub struct BigEndian; |
225 | |
226 | impl Default for BigEndian { |
227 | #[inline ] |
228 | fn default() -> BigEndian { |
229 | BigEndian |
230 | } |
231 | } |
232 | |
233 | impl 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" )] |
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 | |