1 //! Types for compile-time and run-time endianness.
2 
3 use crate::pod::Pod;
4 use core::fmt::{self, Debug};
5 use core::marker::PhantomData;
6 
7 /// A trait for using an endianness specification.
8 ///
9 /// Provides methods for converting between the specified endianness and
10 /// the native endianness of the target machine.
11 ///
12 /// This trait does not require that the endianness is known at compile time.
13 pub trait Endian: Debug + Default + Clone + Copy + PartialEq + Eq + 'static {
14     /// Construct a specification for the endianness of some values.
15     ///
16     /// Returns `None` if the type does not support specifying the given endianness.
from_big_endian(big_endian: bool) -> Option<Self>17     fn from_big_endian(big_endian: bool) -> Option<Self>;
18 
19     /// Construct a specification for the endianness of some values.
20     ///
21     /// Returns `None` if the type does not support specifying the given endianness.
from_little_endian(little_endian: bool) -> Option<Self>22     fn from_little_endian(little_endian: bool) -> Option<Self> {
23         Self::from_big_endian(!little_endian)
24     }
25 
26     /// Return true for big endian byte order.
is_big_endian(self) -> bool27     fn is_big_endian(self) -> bool;
28 
29     /// Return true for little endian byte order.
30     #[inline]
is_little_endian(self) -> bool31     fn is_little_endian(self) -> bool {
32         !self.is_big_endian()
33     }
34 
35     /// Converts an unsigned 16 bit integer to native endian.
36     #[inline]
read_u16(self, n: u16) -> u1637     fn read_u16(self, n: u16) -> u16 {
38         if self.is_big_endian() {
39             u16::from_be(n)
40         } else {
41             u16::from_le(n)
42         }
43     }
44 
45     /// Converts an unsigned 32 bit integer to native endian.
46     #[inline]
read_u32(self, n: u32) -> u3247     fn read_u32(self, n: u32) -> u32 {
48         if self.is_big_endian() {
49             u32::from_be(n)
50         } else {
51             u32::from_le(n)
52         }
53     }
54 
55     /// Converts an unsigned 64 bit integer to native endian.
56     #[inline]
read_u64(self, n: u64) -> u6457     fn read_u64(self, n: u64) -> u64 {
58         if self.is_big_endian() {
59             u64::from_be(n)
60         } else {
61             u64::from_le(n)
62         }
63     }
64 
65     /// Converts a signed 16 bit integer to native endian.
66     #[inline]
read_i16(self, n: i16) -> i1667     fn read_i16(self, n: i16) -> i16 {
68         if self.is_big_endian() {
69             i16::from_be(n)
70         } else {
71             i16::from_le(n)
72         }
73     }
74 
75     /// Converts a signed 32 bit integer to native endian.
76     #[inline]
read_i32(self, n: i32) -> i3277     fn read_i32(self, n: i32) -> i32 {
78         if self.is_big_endian() {
79             i32::from_be(n)
80         } else {
81             i32::from_le(n)
82         }
83     }
84 
85     /// Converts a signed 64 bit integer to native endian.
86     #[inline]
read_i64(self, n: i64) -> i6487     fn read_i64(self, n: i64) -> i64 {
88         if self.is_big_endian() {
89             i64::from_be(n)
90         } else {
91             i64::from_le(n)
92         }
93     }
94 
95     /// Converts an unaligned unsigned 16 bit integer to native endian.
96     #[inline]
read_u16_bytes(self, n: [u8; 2]) -> u1697     fn read_u16_bytes(self, n: [u8; 2]) -> u16 {
98         if self.is_big_endian() {
99             u16::from_be_bytes(n)
100         } else {
101             u16::from_le_bytes(n)
102         }
103     }
104 
105     /// Converts an unaligned unsigned 32 bit integer to native endian.
106     #[inline]
read_u32_bytes(self, n: [u8; 4]) -> u32107     fn read_u32_bytes(self, n: [u8; 4]) -> u32 {
108         if self.is_big_endian() {
109             u32::from_be_bytes(n)
110         } else {
111             u32::from_le_bytes(n)
112         }
113     }
114 
115     /// Converts an unaligned unsigned 64 bit integer to native endian.
116     #[inline]
read_u64_bytes(self, n: [u8; 8]) -> u64117     fn read_u64_bytes(self, n: [u8; 8]) -> u64 {
118         if self.is_big_endian() {
119             u64::from_be_bytes(n)
120         } else {
121             u64::from_le_bytes(n)
122         }
123     }
124 
125     /// Converts an unaligned signed 16 bit integer to native endian.
126     #[inline]
read_i16_bytes(self, n: [u8; 2]) -> i16127     fn read_i16_bytes(self, n: [u8; 2]) -> i16 {
128         if self.is_big_endian() {
129             i16::from_be_bytes(n)
130         } else {
131             i16::from_le_bytes(n)
132         }
133     }
134 
135     /// Converts an unaligned signed 32 bit integer to native endian.
136     #[inline]
read_i32_bytes(self, n: [u8; 4]) -> i32137     fn read_i32_bytes(self, n: [u8; 4]) -> i32 {
138         if self.is_big_endian() {
139             i32::from_be_bytes(n)
140         } else {
141             i32::from_le_bytes(n)
142         }
143     }
144 
145     /// Converts an unaligned signed 64 bit integer to native endian.
146     #[inline]
read_i64_bytes(self, n: [u8; 8]) -> i64147     fn read_i64_bytes(self, n: [u8; 8]) -> i64 {
148         if self.is_big_endian() {
149             i64::from_be_bytes(n)
150         } else {
151             i64::from_le_bytes(n)
152         }
153     }
154 
155     /// Converts an unsigned 16 bit integer from native endian.
156     #[inline]
write_u16(self, n: u16) -> u16157     fn write_u16(self, n: u16) -> u16 {
158         if self.is_big_endian() {
159             u16::to_be(n)
160         } else {
161             u16::to_le(n)
162         }
163     }
164 
165     /// Converts an unsigned 32 bit integer from native endian.
166     #[inline]
write_u32(self, n: u32) -> u32167     fn write_u32(self, n: u32) -> u32 {
168         if self.is_big_endian() {
169             u32::to_be(n)
170         } else {
171             u32::to_le(n)
172         }
173     }
174 
175     /// Converts an unsigned 64 bit integer from native endian.
176     #[inline]
write_u64(self, n: u64) -> u64177     fn write_u64(self, n: u64) -> u64 {
178         if self.is_big_endian() {
179             u64::to_be(n)
180         } else {
181             u64::to_le(n)
182         }
183     }
184 
185     /// Converts a signed 16 bit integer from native endian.
186     #[inline]
write_i16(self, n: i16) -> i16187     fn write_i16(self, n: i16) -> i16 {
188         if self.is_big_endian() {
189             i16::to_be(n)
190         } else {
191             i16::to_le(n)
192         }
193     }
194 
195     /// Converts a signed 32 bit integer from native endian.
196     #[inline]
write_i32(self, n: i32) -> i32197     fn write_i32(self, n: i32) -> i32 {
198         if self.is_big_endian() {
199             i32::to_be(n)
200         } else {
201             i32::to_le(n)
202         }
203     }
204 
205     /// Converts a signed 64 bit integer from native endian.
206     #[inline]
write_i64(self, n: i64) -> i64207     fn write_i64(self, n: i64) -> i64 {
208         if self.is_big_endian() {
209             i64::to_be(n)
210         } else {
211             i64::to_le(n)
212         }
213     }
214 
215     /// Converts an unaligned unsigned 16 bit integer from native endian.
216     #[inline]
write_u16_bytes(self, n: u16) -> [u8; 2]217     fn write_u16_bytes(self, n: u16) -> [u8; 2] {
218         if self.is_big_endian() {
219             u16::to_be_bytes(n)
220         } else {
221             u16::to_le_bytes(n)
222         }
223     }
224 
225     /// Converts an unaligned unsigned 32 bit integer from native endian.
226     #[inline]
write_u32_bytes(self, n: u32) -> [u8; 4]227     fn write_u32_bytes(self, n: u32) -> [u8; 4] {
228         if self.is_big_endian() {
229             u32::to_be_bytes(n)
230         } else {
231             u32::to_le_bytes(n)
232         }
233     }
234 
235     /// Converts an unaligned unsigned 64 bit integer from native endian.
236     #[inline]
write_u64_bytes(self, n: u64) -> [u8; 8]237     fn write_u64_bytes(self, n: u64) -> [u8; 8] {
238         if self.is_big_endian() {
239             u64::to_be_bytes(n)
240         } else {
241             u64::to_le_bytes(n)
242         }
243     }
244 
245     /// Converts an unaligned signed 16 bit integer from native endian.
246     #[inline]
write_i16_bytes(self, n: i16) -> [u8; 2]247     fn write_i16_bytes(self, n: i16) -> [u8; 2] {
248         if self.is_big_endian() {
249             i16::to_be_bytes(n)
250         } else {
251             i16::to_le_bytes(n)
252         }
253     }
254 
255     /// Converts an unaligned signed 32 bit integer from native endian.
256     #[inline]
write_i32_bytes(self, n: i32) -> [u8; 4]257     fn write_i32_bytes(self, n: i32) -> [u8; 4] {
258         if self.is_big_endian() {
259             i32::to_be_bytes(n)
260         } else {
261             i32::to_le_bytes(n)
262         }
263     }
264 
265     /// Converts an unaligned signed 64 bit integer from native endian.
266     #[inline]
write_i64_bytes(self, n: i64) -> [u8; 8]267     fn write_i64_bytes(self, n: i64) -> [u8; 8] {
268         if self.is_big_endian() {
269             i64::to_be_bytes(n)
270         } else {
271             i64::to_le_bytes(n)
272         }
273     }
274 }
275 
276 /// An endianness that is selectable at run-time.
277 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
278 pub enum Endianness {
279     /// Little endian byte order.
280     Little,
281     /// Big endian byte order.
282     Big,
283 }
284 
285 impl Default for Endianness {
286     #[cfg(target_endian = "little")]
287     #[inline]
default() -> Endianness288     fn default() -> Endianness {
289         Endianness::Little
290     }
291 
292     #[cfg(target_endian = "big")]
293     #[inline]
default() -> Endianness294     fn default() -> Endianness {
295         Endianness::Big
296     }
297 }
298 
299 impl Endian for Endianness {
300     #[inline]
from_big_endian(big_endian: bool) -> Option<Self>301     fn from_big_endian(big_endian: bool) -> Option<Self> {
302         Some(if big_endian {
303             Endianness::Big
304         } else {
305             Endianness::Little
306         })
307     }
308 
309     #[inline]
is_big_endian(self) -> bool310     fn is_big_endian(self) -> bool {
311         self != Endianness::Little
312     }
313 }
314 
315 /// Compile-time little endian byte order.
316 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
317 pub struct LittleEndian;
318 
319 impl Default for LittleEndian {
320     #[inline]
default() -> LittleEndian321     fn default() -> LittleEndian {
322         LittleEndian
323     }
324 }
325 
326 impl Endian for LittleEndian {
327     #[inline]
from_big_endian(big_endian: bool) -> Option<Self>328     fn from_big_endian(big_endian: bool) -> Option<Self> {
329         if big_endian {
330             None
331         } else {
332             Some(LittleEndian)
333         }
334     }
335 
336     #[inline]
is_big_endian(self) -> bool337     fn is_big_endian(self) -> bool {
338         false
339     }
340 }
341 
342 /// Compile-time big endian byte order.
343 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
344 pub struct BigEndian;
345 
346 impl Default for BigEndian {
347     #[inline]
default() -> BigEndian348     fn default() -> BigEndian {
349         BigEndian
350     }
351 }
352 
353 impl Endian for BigEndian {
354     #[inline]
from_big_endian(big_endian: bool) -> Option<Self>355     fn from_big_endian(big_endian: bool) -> Option<Self> {
356         if big_endian {
357             Some(BigEndian)
358         } else {
359             None
360         }
361     }
362 
363     #[inline]
is_big_endian(self) -> bool364     fn is_big_endian(self) -> bool {
365         true
366     }
367 }
368 
369 /// The native endianness for the target platform.
370 #[cfg(target_endian = "little")]
371 pub type NativeEndian = LittleEndian;
372 
373 #[cfg(target_endian = "little")]
374 #[allow(non_upper_case_globals)]
375 #[doc(hidden)]
376 pub const NativeEndian: LittleEndian = LittleEndian;
377 
378 /// The native endianness for the target platform.
379 #[cfg(target_endian = "big")]
380 pub type NativeEndian = BigEndian;
381 
382 #[cfg(target_endian = "big")]
383 #[allow(non_upper_case_globals)]
384 #[doc(hidden)]
385 pub const NativeEndian: BigEndian = BigEndian;
386 
387 macro_rules! unsafe_impl_endian_pod {
388     ($($struct_name:ident),+ $(,)?) => {
389         $(
390             unsafe impl<E: Endian> Pod for $struct_name<E> { }
391         )+
392     }
393 }
394 
395 #[cfg(not(feature = "unaligned"))]
396 mod aligned {
397     use super::{fmt, Endian, PhantomData, Pod};
398 
399     /// A `u16` value with an externally specified endianness of type `E`.
400     #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
401     #[repr(transparent)]
402     pub struct U16<E: Endian>(u16, PhantomData<E>);
403 
404     impl<E: Endian> U16<E> {
405         /// Construct a new value given a native endian value.
new(e: E, n: u16) -> Self406         pub fn new(e: E, n: u16) -> Self {
407             Self(e.write_u16(n), PhantomData)
408         }
409 
410         /// Return the value as a native endian value.
get(self, e: E) -> u16411         pub fn get(self, e: E) -> u16 {
412             e.read_u16(self.0)
413         }
414 
415         /// Set the value given a native endian value.
set(&mut self, e: E, n: u16)416         pub fn set(&mut self, e: E, n: u16) {
417             self.0 = e.write_u16(n);
418         }
419     }
420 
421     /// A `u32` value with an externally specified endianness of type `E`.
422     #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
423     #[repr(transparent)]
424     pub struct U32<E: Endian>(u32, PhantomData<E>);
425 
426     impl<E: Endian> U32<E> {
427         /// Construct a new value given a native endian value.
new(e: E, n: u32) -> Self428         pub fn new(e: E, n: u32) -> Self {
429             Self(e.write_u32(n), PhantomData)
430         }
431         /// Return the value as a native endian value.
get(self, e: E) -> u32432         pub fn get(self, e: E) -> u32 {
433             e.read_u32(self.0)
434         }
435         /// Set the value given a native endian value.
set(&mut self, e: E, n: u32)436         pub fn set(&mut self, e: E, n: u32) {
437             self.0 = e.write_u32(n);
438         }
439     }
440 
441     /// A `u64` value with an externally specified endianness of type `E`.
442     #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
443     #[repr(transparent)]
444     pub struct U64<E: Endian>(u64, PhantomData<E>);
445 
446     impl<E: Endian> U64<E> {
447         /// Construct a new value given a native endian value.
new(e: E, n: u64) -> Self448         pub fn new(e: E, n: u64) -> Self {
449             Self(e.write_u64(n), PhantomData)
450         }
451         /// Return the value as a native endian value.
get(self, e: E) -> u64452         pub fn get(self, e: E) -> u64 {
453             e.read_u64(self.0)
454         }
455         /// Set the value given a native endian value.
set(&mut self, e: E, n: u64)456         pub fn set(&mut self, e: E, n: u64) {
457             self.0 = e.write_u64(n);
458         }
459     }
460 
461     /// An `i16` value with an externally specified endianness of type `E`.
462     #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
463     #[repr(transparent)]
464     pub struct I16<E: Endian>(i16, PhantomData<E>);
465 
466     impl<E: Endian> I16<E> {
467         /// Construct a new value given a native endian value.
new(e: E, n: i16) -> Self468         pub fn new(e: E, n: i16) -> Self {
469             Self(e.write_i16(n), PhantomData)
470         }
471         /// Return the value as a native endian value.
get(self, e: E) -> i16472         pub fn get(self, e: E) -> i16 {
473             e.read_i16(self.0)
474         }
475         /// Set the value given a native endian value.
set(&mut self, e: E, n: i16)476         pub fn set(&mut self, e: E, n: i16) {
477             self.0 = e.write_i16(n);
478         }
479     }
480 
481     /// An `i32` value with an externally specified endianness of type `E`.
482     #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
483     #[repr(transparent)]
484     pub struct I32<E: Endian>(i32, PhantomData<E>);
485 
486     impl<E: Endian> I32<E> {
487         /// Construct a new value given a native endian value.
new(e: E, n: i32) -> Self488         pub fn new(e: E, n: i32) -> Self {
489             Self(e.write_i32(n), PhantomData)
490         }
491         /// Return the value as a native endian value.
get(self, e: E) -> i32492         pub fn get(self, e: E) -> i32 {
493             e.read_i32(self.0)
494         }
495         /// Set the value given a native endian value.
set(&mut self, e: E, n: i32)496         pub fn set(&mut self, e: E, n: i32) {
497             self.0 = e.write_i32(n);
498         }
499     }
500 
501     /// An `i64` value with an externally specified endianness of type `E`.
502     #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
503     #[repr(transparent)]
504     pub struct I64<E: Endian>(i64, PhantomData<E>);
505 
506     impl<E: Endian> I64<E> {
507         /// Construct a new value given a native endian value.
new(e: E, n: i64) -> Self508         pub fn new(e: E, n: i64) -> Self {
509             Self(e.write_i64(n), PhantomData)
510         }
511         /// Return the value as a native endian value.
get(self, e: E) -> i64512         pub fn get(self, e: E) -> i64 {
513             e.read_i64(self.0)
514         }
515         /// Set the value given a native endian value.
set(&mut self, e: E, n: i64)516         pub fn set(&mut self, e: E, n: i64) {
517             self.0 = e.write_i64(n);
518         }
519     }
520 
521     impl<E: Endian> fmt::Debug for U16<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result522         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523             write!(f, "U16({:x})", self.0)
524         }
525     }
526 
527     impl<E: Endian> fmt::Debug for U32<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result528         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529             write!(f, "U32({:x})", self.0)
530         }
531     }
532 
533     impl<E: Endian> fmt::Debug for U64<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result534         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535             write!(f, "U64({:x})", self.0)
536         }
537     }
538 
539     impl<E: Endian> fmt::Debug for I16<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result540         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541             write!(f, "I16({:x})", self.0)
542         }
543     }
544 
545     impl<E: Endian> fmt::Debug for I32<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result546         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547             write!(f, "I32({:x})", self.0)
548         }
549     }
550 
551     impl<E: Endian> fmt::Debug for I64<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result552         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553             write!(f, "I64({:x})", self.0)
554         }
555     }
556 
557     unsafe_impl_endian_pod!(U16, U32, U64, I16, I32, I64);
558 }
559 
560 #[cfg(not(feature = "unaligned"))]
561 pub use aligned::*;
562 
563 /// A `u16` value with an externally specified endianness of type `E`.
564 #[cfg(feature = "unaligned")]
565 pub type U16<E> = U16Bytes<E>;
566 
567 /// A `u32` value with an externally specified endianness of type `E`.
568 #[cfg(feature = "unaligned")]
569 pub type U32<E> = U32Bytes<E>;
570 
571 /// A `u64` value with an externally specified endianness of type `E`.
572 #[cfg(feature = "unaligned")]
573 pub type U64<E> = U64Bytes<E>;
574 
575 /// An `i16` value with an externally specified endianness of type `E`.
576 #[cfg(feature = "unaligned")]
577 pub type I16<E> = I16Bytes<E>;
578 
579 /// An `i32` value with an externally specified endianness of type `E`.
580 #[cfg(feature = "unaligned")]
581 pub type I32<E> = I32Bytes<E>;
582 
583 /// An `i64` value with an externally specified endianness of type `E`.
584 #[cfg(feature = "unaligned")]
585 pub type I64<E> = I64Bytes<E>;
586 
587 /// An unaligned `u16` value with an externally specified endianness of type `E`.
588 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
589 #[repr(transparent)]
590 pub struct U16Bytes<E: Endian>([u8; 2], PhantomData<E>);
591 
592 impl<E: Endian> U16Bytes<E> {
593     /// Construct a new value given a native endian value.
new(e: E, n: u16) -> Self594     pub fn new(e: E, n: u16) -> Self {
595         Self(e.write_u16_bytes(n), PhantomData)
596     }
597 
598     /// Return the value as a native endian value.
get(self, e: E) -> u16599     pub fn get(self, e: E) -> u16 {
600         e.read_u16_bytes(self.0)
601     }
602 
603     /// Set the value given a native endian value.
set(&mut self, e: E, n: u16)604     pub fn set(&mut self, e: E, n: u16) {
605         self.0 = e.write_u16_bytes(n);
606     }
607 }
608 
609 /// An unaligned `u32` value with an externally specified endianness of type `E`.
610 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
611 #[repr(transparent)]
612 pub struct U32Bytes<E: Endian>([u8; 4], PhantomData<E>);
613 
614 impl<E: Endian> U32Bytes<E> {
615     /// Construct a new value given a native endian value.
new(e: E, n: u32) -> Self616     pub fn new(e: E, n: u32) -> Self {
617         Self(e.write_u32_bytes(n), PhantomData)
618     }
619 
620     /// Return the value as a native endian value.
get(self, e: E) -> u32621     pub fn get(self, e: E) -> u32 {
622         e.read_u32_bytes(self.0)
623     }
624 
625     /// Set the value given a native endian value.
set(&mut self, e: E, n: u32)626     pub fn set(&mut self, e: E, n: u32) {
627         self.0 = e.write_u32_bytes(n);
628     }
629 }
630 
631 /// An unaligned `u64` value with an externally specified endianness of type `E`.
632 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
633 #[repr(transparent)]
634 pub struct U64Bytes<E: Endian>([u8; 8], PhantomData<E>);
635 
636 impl<E: Endian> U64Bytes<E> {
637     /// Construct a new value given a native endian value.
new(e: E, n: u64) -> Self638     pub fn new(e: E, n: u64) -> Self {
639         Self(e.write_u64_bytes(n), PhantomData)
640     }
641 
642     /// Return the value as a native endian value.
get(self, e: E) -> u64643     pub fn get(self, e: E) -> u64 {
644         e.read_u64_bytes(self.0)
645     }
646 
647     /// Set the value given a native endian value.
set(&mut self, e: E, n: u64)648     pub fn set(&mut self, e: E, n: u64) {
649         self.0 = e.write_u64_bytes(n);
650     }
651 }
652 
653 /// An unaligned `i16` value with an externally specified endianness of type `E`.
654 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
655 #[repr(transparent)]
656 pub struct I16Bytes<E: Endian>([u8; 2], PhantomData<E>);
657 
658 impl<E: Endian> I16Bytes<E> {
659     /// Construct a new value given a native endian value.
new(e: E, n: i16) -> Self660     pub fn new(e: E, n: i16) -> Self {
661         Self(e.write_i16_bytes(n), PhantomData)
662     }
663 
664     /// Return the value as a native endian value.
get(self, e: E) -> i16665     pub fn get(self, e: E) -> i16 {
666         e.read_i16_bytes(self.0)
667     }
668 
669     /// Set the value given a native endian value.
set(&mut self, e: E, n: i16)670     pub fn set(&mut self, e: E, n: i16) {
671         self.0 = e.write_i16_bytes(n);
672     }
673 }
674 
675 /// An unaligned `i32` value with an externally specified endianness of type `E`.
676 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
677 #[repr(transparent)]
678 pub struct I32Bytes<E: Endian>([u8; 4], PhantomData<E>);
679 
680 impl<E: Endian> I32Bytes<E> {
681     /// Construct a new value given a native endian value.
new(e: E, n: i32) -> Self682     pub fn new(e: E, n: i32) -> Self {
683         Self(e.write_i32_bytes(n), PhantomData)
684     }
685 
686     /// Return the value as a native endian value.
get(self, e: E) -> i32687     pub fn get(self, e: E) -> i32 {
688         e.read_i32_bytes(self.0)
689     }
690 
691     /// Set the value given a native endian value.
set(&mut self, e: E, n: i32)692     pub fn set(&mut self, e: E, n: i32) {
693         self.0 = e.write_i32_bytes(n);
694     }
695 }
696 
697 /// An unaligned `i64` value with an externally specified endianness of type `E`.
698 #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
699 #[repr(transparent)]
700 pub struct I64Bytes<E: Endian>([u8; 8], PhantomData<E>);
701 
702 impl<E: Endian> I64Bytes<E> {
703     /// Construct a new value given a native endian value.
new(e: E, n: i64) -> Self704     pub fn new(e: E, n: i64) -> Self {
705         Self(e.write_i64_bytes(n), PhantomData)
706     }
707 
708     /// Return the value as a native endian value.
get(self, e: E) -> i64709     pub fn get(self, e: E) -> i64 {
710         e.read_i64_bytes(self.0)
711     }
712 
713     /// Set the value given a native endian value.
set(&mut self, e: E, n: i64)714     pub fn set(&mut self, e: E, n: i64) {
715         self.0 = e.write_i64_bytes(n);
716     }
717 }
718 
719 impl<E: Endian> fmt::Debug for U16Bytes<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result720     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
721         write!(f, "U16({:x}, {:x})", self.0[0], self.0[1],)
722     }
723 }
724 
725 impl<E: Endian> fmt::Debug for U32Bytes<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result726     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
727         write!(
728             f,
729             "U32({:x}, {:x}, {:x}, {:x})",
730             self.0[0], self.0[1], self.0[2], self.0[3],
731         )
732     }
733 }
734 
735 impl<E: Endian> fmt::Debug for U64Bytes<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result736     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
737         write!(
738             f,
739             "U64({:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x})",
740             self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
741         )
742     }
743 }
744 
745 impl<E: Endian> fmt::Debug for I16Bytes<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result746     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
747         write!(f, "I16({:x}, {:x})", self.0[0], self.0[1],)
748     }
749 }
750 
751 impl<E: Endian> fmt::Debug for I32Bytes<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result752     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
753         write!(
754             f,
755             "I32({:x}, {:x}, {:x}, {:x})",
756             self.0[0], self.0[1], self.0[2], self.0[3],
757         )
758     }
759 }
760 
761 impl<E: Endian> fmt::Debug for I64Bytes<E> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result762     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
763         write!(
764             f,
765             "I64({:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x}, {:x})",
766             self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
767         )
768     }
769 }
770 
771 unsafe_impl_endian_pod!(U16Bytes, U32Bytes, U64Bytes, I16Bytes, I32Bytes, I64Bytes);
772