Skip to main content

object/
endian.rs

1//! Types for compile-time and run-time endianness.
2
3use crate::pod::Pod;
4use core::fmt::{self, Debug};
5use 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.
13pub 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.
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.
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.
27    fn is_big_endian(self) -> bool;
28
29    /// Return true for little endian byte order.
30    #[inline]
31    fn is_little_endian(self) -> bool {
32        !self.is_big_endian()
33    }
34
35    /// Converts an unaligned unsigned 16 bit integer to native endian.
36    #[inline]
37    fn read_u16(self, n: [u8; 2]) -> u16 {
38        if self.is_big_endian() {
39            u16::from_be_bytes(n)
40        } else {
41            u16::from_le_bytes(n)
42        }
43    }
44
45    /// Converts an unaligned unsigned 32 bit integer to native endian.
46    #[inline]
47    fn read_u32(self, n: [u8; 4]) -> u32 {
48        if self.is_big_endian() {
49            u32::from_be_bytes(n)
50        } else {
51            u32::from_le_bytes(n)
52        }
53    }
54
55    /// Converts an unaligned unsigned 64 bit integer to native endian.
56    #[inline]
57    fn read_u64(self, n: [u8; 8]) -> u64 {
58        if self.is_big_endian() {
59            u64::from_be_bytes(n)
60        } else {
61            u64::from_le_bytes(n)
62        }
63    }
64
65    /// Converts an unaligned signed 16 bit integer to native endian.
66    #[inline]
67    fn read_i16(self, n: [u8; 2]) -> i16 {
68        if self.is_big_endian() {
69            i16::from_be_bytes(n)
70        } else {
71            i16::from_le_bytes(n)
72        }
73    }
74
75    /// Converts an unaligned signed 32 bit integer to native endian.
76    #[inline]
77    fn read_i32(self, n: [u8; 4]) -> i32 {
78        if self.is_big_endian() {
79            i32::from_be_bytes(n)
80        } else {
81            i32::from_le_bytes(n)
82        }
83    }
84
85    /// Converts an unaligned signed 64 bit integer to native endian.
86    #[inline]
87    fn read_i64(self, n: [u8; 8]) -> i64 {
88        if self.is_big_endian() {
89            i64::from_be_bytes(n)
90        } else {
91            i64::from_le_bytes(n)
92        }
93    }
94
95    /// Converts an unaligned unsigned 16 bit integer from native endian.
96    #[inline]
97    fn write_u16(self, n: u16) -> [u8; 2] {
98        if self.is_big_endian() {
99            u16::to_be_bytes(n)
100        } else {
101            u16::to_le_bytes(n)
102        }
103    }
104
105    /// Converts an unaligned unsigned 32 bit integer from native endian.
106    #[inline]
107    fn write_u32(self, n: u32) -> [u8; 4] {
108        if self.is_big_endian() {
109            u32::to_be_bytes(n)
110        } else {
111            u32::to_le_bytes(n)
112        }
113    }
114
115    /// Converts an unaligned unsigned 64 bit integer from native endian.
116    #[inline]
117    fn write_u64(self, n: u64) -> [u8; 8] {
118        if self.is_big_endian() {
119            u64::to_be_bytes(n)
120        } else {
121            u64::to_le_bytes(n)
122        }
123    }
124
125    /// Converts an unaligned signed 16 bit integer from native endian.
126    #[inline]
127    fn write_i16(self, n: i16) -> [u8; 2] {
128        if self.is_big_endian() {
129            i16::to_be_bytes(n)
130        } else {
131            i16::to_le_bytes(n)
132        }
133    }
134
135    /// Converts an unaligned signed 32 bit integer from native endian.
136    #[inline]
137    fn write_i32(self, n: i32) -> [u8; 4] {
138        if self.is_big_endian() {
139            i32::to_be_bytes(n)
140        } else {
141            i32::to_le_bytes(n)
142        }
143    }
144
145    /// Converts an unaligned signed 64 bit integer from native endian.
146    #[inline]
147    fn write_i64(self, n: i64) -> [u8; 8] {
148        if self.is_big_endian() {
149            i64::to_be_bytes(n)
150        } else {
151            i64::to_le_bytes(n)
152        }
153    }
154}
155
156/// An endianness specification that has a fixed value.
157pub trait FixedEndian: Endian {
158    /// The fixed value.
159    const FIXED: Self;
160}
161
162/// An endianness that is selectable at run-time.
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
164pub enum Endianness {
165    /// Little endian byte order.
166    Little,
167    /// Big endian byte order.
168    Big,
169}
170
171impl Default for Endianness {
172    #[cfg(target_endian = "little")]
173    #[inline]
174    fn default() -> Endianness {
175        Endianness::Little
176    }
177
178    #[cfg(target_endian = "big")]
179    #[inline]
180    fn default() -> Endianness {
181        Endianness::Big
182    }
183}
184
185impl Endian for Endianness {
186    #[inline]
187    fn from_big_endian(big_endian: bool) -> Option<Self> {
188        Some(if big_endian {
189            Endianness::Big
190        } else {
191            Endianness::Little
192        })
193    }
194
195    #[inline]
196    fn is_big_endian(self) -> bool {
197        self != Endianness::Little
198    }
199}
200
201/// Compile-time little endian byte order.
202#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
203pub struct LittleEndian;
204
205impl Default for LittleEndian {
206    #[inline]
207    fn default() -> LittleEndian {
208        LittleEndian
209    }
210}
211
212impl Endian for LittleEndian {
213    #[inline]
214    fn from_big_endian(big_endian: bool) -> Option<Self> {
215        if big_endian {
216            None
217        } else {
218            Some(LittleEndian)
219        }
220    }
221
222    #[inline]
223    fn is_big_endian(self) -> bool {
224        false
225    }
226}
227
228impl FixedEndian for LittleEndian {
229    const FIXED: Self = LittleEndian;
230}
231
232/// Compile-time big endian byte order.
233#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
234pub struct BigEndian;
235
236impl Default for BigEndian {
237    #[inline]
238    fn default() -> BigEndian {
239        BigEndian
240    }
241}
242
243impl Endian for BigEndian {
244    #[inline]
245    fn from_big_endian(big_endian: bool) -> Option<Self> {
246        if big_endian {
247            Some(BigEndian)
248        } else {
249            None
250        }
251    }
252
253    #[inline]
254    fn is_big_endian(self) -> bool {
255        true
256    }
257}
258
259impl FixedEndian for BigEndian {
260    const FIXED: Self = BigEndian;
261}
262
263/// The native endianness for the target platform.
264#[cfg(target_endian = "little")]
265pub type NativeEndian = LittleEndian;
266
267#[cfg(target_endian = "little")]
268#[allow(non_upper_case_globals)]
269#[doc(hidden)]
270pub const NativeEndian: LittleEndian = LittleEndian;
271
272/// The native endianness for the target platform.
273#[cfg(target_endian = "big")]
274pub type NativeEndian = BigEndian;
275
276#[cfg(target_endian = "big")]
277#[allow(non_upper_case_globals)]
278#[doc(hidden)]
279pub const NativeEndian: BigEndian = BigEndian;
280
281macro_rules! unsafe_impl_endian_pod {
282    ($($struct_name:ident),+ $(,)?) => {
283        $(
284            unsafe impl<E: Endian> Pod for $struct_name<E> { }
285        )+
286    }
287}
288
289/// An unaligned `u16` value with an externally specified endianness of type `E`.
290#[deprecated]
291pub type U16Bytes<E> = U16<E>;
292
293/// An unaligned `u32` value with an externally specified endianness of type `E`.
294#[deprecated]
295pub type U32Bytes<E> = U32<E>;
296
297/// An unaligned `u64` value with an externally specified endianness of type `E`.
298#[deprecated]
299pub type U64Bytes<E> = U64<E>;
300
301/// An unaligned `i16` value with an externally specified endianness of type `E`.
302#[deprecated]
303pub type I16Bytes<E> = I16<E>;
304
305/// An unaligned `i32` value with an externally specified endianness of type `E`.
306#[deprecated]
307pub type I32Bytes<E> = I32<E>;
308
309/// An unaligned `i64` value with an externally specified endianness of type `E`.
310#[deprecated]
311pub type I64Bytes<E> = I64<E>;
312
313/// An unaligned `u16` value with an externally specified endianness of type `E`.
314#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
315#[repr(transparent)]
316pub struct U16<E: Endian>([u8; 2], PhantomData<E>);
317
318impl<E: Endian> U16<E> {
319    /// Construct a new value given bytes that already have the required endianness.
320    pub const fn from_bytes(n: [u8; 2]) -> Self {
321        Self(n, PhantomData)
322    }
323
324    /// Construct a new value given a native endian value.
325    pub fn new(e: E, n: u16) -> Self {
326        Self(e.write_u16(n), PhantomData)
327    }
328
329    /// Return the value as a native endian value.
330    pub fn get(self, e: E) -> u16 {
331        e.read_u16(self.0)
332    }
333
334    /// Set the value given a native endian value.
335    pub fn set(&mut self, e: E, n: u16) {
336        self.0 = e.write_u16(n);
337    }
338}
339
340/// An unaligned `u32` value with an externally specified endianness of type `E`.
341#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
342#[repr(transparent)]
343pub struct U32<E: Endian>([u8; 4], PhantomData<E>);
344
345impl<E: Endian> U32<E> {
346    /// Construct a new value given bytes that already have the required endianness.
347    pub const fn from_bytes(n: [u8; 4]) -> Self {
348        Self(n, PhantomData)
349    }
350
351    /// Construct a new value given a native endian value.
352    pub fn new(e: E, n: u32) -> Self {
353        Self(e.write_u32(n), PhantomData)
354    }
355
356    /// Return the value as a native endian value.
357    pub fn get(self, e: E) -> u32 {
358        e.read_u32(self.0)
359    }
360
361    /// Set the value given a native endian value.
362    pub fn set(&mut self, e: E, n: u32) {
363        self.0 = e.write_u32(n);
364    }
365}
366
367/// An unaligned `u64` value with an externally specified endianness of type `E`.
368#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
369#[repr(transparent)]
370pub struct U64<E: Endian>([u8; 8], PhantomData<E>);
371
372impl<E: Endian> U64<E> {
373    /// Construct a new value given bytes that already have the required endianness.
374    pub const fn from_bytes(n: [u8; 8]) -> Self {
375        Self(n, PhantomData)
376    }
377
378    /// Construct a new value given a native endian value.
379    pub fn new(e: E, n: u64) -> Self {
380        Self(e.write_u64(n), PhantomData)
381    }
382
383    /// Return the value as a native endian value.
384    pub fn get(self, e: E) -> u64 {
385        e.read_u64(self.0)
386    }
387
388    /// Set the value given a native endian value.
389    pub fn set(&mut self, e: E, n: u64) {
390        self.0 = e.write_u64(n);
391    }
392}
393
394/// An unaligned `i16` value with an externally specified endianness of type `E`.
395#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
396#[repr(transparent)]
397pub struct I16<E: Endian>([u8; 2], PhantomData<E>);
398
399impl<E: Endian> I16<E> {
400    /// Construct a new value given bytes that already have the required endianness.
401    pub const fn from_bytes(n: [u8; 2]) -> Self {
402        Self(n, PhantomData)
403    }
404
405    /// Construct a new value given a native endian value.
406    pub fn new(e: E, n: i16) -> Self {
407        Self(e.write_i16(n), PhantomData)
408    }
409
410    /// Return the value as a native endian value.
411    pub fn get(self, e: E) -> i16 {
412        e.read_i16(self.0)
413    }
414
415    /// Set the value given a native endian value.
416    pub fn set(&mut self, e: E, n: i16) {
417        self.0 = e.write_i16(n);
418    }
419}
420
421/// An unaligned `i32` value with an externally specified endianness of type `E`.
422#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
423#[repr(transparent)]
424pub struct I32<E: Endian>([u8; 4], PhantomData<E>);
425
426impl<E: Endian> I32<E> {
427    /// Construct a new value given bytes that already have the required endianness.
428    pub const fn from_bytes(n: [u8; 4]) -> Self {
429        Self(n, PhantomData)
430    }
431
432    /// Construct a new value given a native endian value.
433    pub fn new(e: E, n: i32) -> Self {
434        Self(e.write_i32(n), PhantomData)
435    }
436
437    /// Return the value as a native endian value.
438    pub fn get(self, e: E) -> i32 {
439        e.read_i32(self.0)
440    }
441
442    /// Set the value given a native endian value.
443    pub fn set(&mut self, e: E, n: i32) {
444        self.0 = e.write_i32(n);
445    }
446}
447
448/// An unaligned `i64` value with an externally specified endianness of type `E`.
449#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
450#[repr(transparent)]
451pub struct I64<E: Endian>([u8; 8], PhantomData<E>);
452
453impl<E: Endian> I64<E> {
454    /// Construct a new value given bytes that already have the required endianness.
455    pub const fn from_bytes(n: [u8; 8]) -> Self {
456        Self(n, PhantomData)
457    }
458
459    /// Construct a new value given a native endian value.
460    pub fn new(e: E, n: i64) -> Self {
461        Self(e.write_i64(n), PhantomData)
462    }
463
464    /// Return the value as a native endian value.
465    pub fn get(self, e: E) -> i64 {
466        e.read_i64(self.0)
467    }
468
469    /// Set the value given a native endian value.
470    pub fn set(&mut self, e: E, n: i64) {
471        self.0 = e.write_i64(n);
472    }
473}
474
475impl<E: Endian> fmt::Debug for U16<E> {
476    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477        write!(f, "U16({:02x}{:02x})", self.0[0], self.0[1],)
478    }
479}
480
481impl<E: Endian> fmt::Debug for U32<E> {
482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483        write!(
484            f,
485            "U32({:02x}{:02x}{:02x}{:02x})",
486            self.0[0], self.0[1], self.0[2], self.0[3],
487        )
488    }
489}
490
491impl<E: Endian> fmt::Debug for U64<E> {
492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493        write!(
494            f,
495            "U64({:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x})",
496            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
497        )
498    }
499}
500
501impl<E: Endian> fmt::Debug for I16<E> {
502    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503        write!(f, "I16({:02x}{:02x})", self.0[0], self.0[1],)
504    }
505}
506
507impl<E: Endian> fmt::Debug for I32<E> {
508    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509        write!(
510            f,
511            "I32({:02x}{:02x}{:02x}{:02x})",
512            self.0[0], self.0[1], self.0[2], self.0[3],
513        )
514    }
515}
516
517impl<E: Endian> fmt::Debug for I64<E> {
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        write!(
520            f,
521            "I64({:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x})",
522            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
523        )
524    }
525}
526
527impl<E: FixedEndian> From<u16> for U16<E> {
528    fn from(val: u16) -> Self {
529        Self::new(E::FIXED, val)
530    }
531}
532
533impl<E: FixedEndian> From<U16<E>> for u16 {
534    fn from(val: U16<E>) -> Self {
535        val.get(E::FIXED)
536    }
537}
538
539impl<E: FixedEndian> From<u32> for U32<E> {
540    fn from(val: u32) -> Self {
541        Self::new(E::FIXED, val)
542    }
543}
544
545impl<E: FixedEndian> From<U32<E>> for u32 {
546    fn from(val: U32<E>) -> Self {
547        val.get(E::FIXED)
548    }
549}
550
551impl<E: FixedEndian> From<u64> for U64<E> {
552    fn from(val: u64) -> Self {
553        Self::new(E::FIXED, val)
554    }
555}
556
557impl<E: FixedEndian> From<U64<E>> for u64 {
558    fn from(val: U64<E>) -> Self {
559        val.get(E::FIXED)
560    }
561}
562
563impl<E: FixedEndian> From<i16> for I16<E> {
564    fn from(val: i16) -> Self {
565        Self::new(E::FIXED, val)
566    }
567}
568
569impl<E: FixedEndian> From<I16<E>> for i16 {
570    fn from(val: I16<E>) -> Self {
571        val.get(E::FIXED)
572    }
573}
574
575impl<E: FixedEndian> From<i32> for I32<E> {
576    fn from(val: i32) -> Self {
577        Self::new(E::FIXED, val)
578    }
579}
580
581impl<E: FixedEndian> From<I32<E>> for i32 {
582    fn from(val: I32<E>) -> Self {
583        val.get(E::FIXED)
584    }
585}
586
587impl<E: FixedEndian> From<i64> for I64<E> {
588    fn from(val: i64) -> Self {
589        Self::new(E::FIXED, val)
590    }
591}
592
593impl<E: FixedEndian> From<I64<E>> for i64 {
594    fn from(val: I64<E>) -> Self {
595        val.get(E::FIXED)
596    }
597}
598
599unsafe_impl_endian_pod!(U16, U32, U64, I16, I32, I64);