data_model/
endian.rs

1// Copyright 2017 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Explicit endian types useful for embedding in structs or reinterpreting data.
6//!
7//! Each endian type is guarnteed to have the same size and alignment as a regular unsigned primiive
8//! of the equal size.
9//!
10//! # Examples
11//!
12//! ```
13//! # use  data_model::*;
14//!   let b: Be32 = From::from(3);
15//!   let l: Le32 = From::from(3);
16//!
17//!   assert_eq!(b.to_native(), 3);
18//!   assert_eq!(l.to_native(), 3);
19//!   assert!(b == 3);
20//!   assert!(l == 3);
21//!
22//!   // SAFETY: trivially safe
23//!   let b_trans: u32 = unsafe { std::mem::transmute(b) };
24//!   // SAFETY: trivially safe
25//!   let l_trans: u32 = unsafe { std::mem::transmute(l) };
26//!
27//!   #[cfg(target_endian = "little")]
28//!   assert_eq!(l_trans, 3);
29//!   #[cfg(target_endian = "big")]
30//!   assert_eq!(b_trans, 3);
31//!
32//!   assert_ne!(b_trans, l_trans);
33//! ```
34
35use serde::Deserialize;
36use serde::Deserializer;
37use serde::Serialize;
38use serde::Serializer;
39use zerocopy::FromBytes;
40use zerocopy::Immutable;
41use zerocopy::IntoBytes;
42use zerocopy::KnownLayout;
43
44macro_rules! endian_type {
45    ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
46        /// An integer type of with an explicit endianness.
47        ///
48        /// See module level documentation for examples.
49        #[repr(transparent)]
50        #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
51        pub struct $new_type($old_type);
52
53        impl $new_type {
54            /// Converts `self` to the native endianness.
55            #[inline]
56            pub fn to_native(self) -> $old_type {
57                $old_type::$from_new(self.0)
58            }
59        }
60
61        impl PartialEq<$old_type> for $new_type {
62            #[inline]
63            fn eq(&self, other: &$old_type) -> bool {
64                self.0 == $old_type::$to_new(*other)
65            }
66        }
67
68        impl PartialEq<$new_type> for $old_type {
69            #[inline]
70            fn eq(&self, other: &$new_type) -> bool {
71                $old_type::$to_new(other.0) == *self
72            }
73        }
74
75        impl From<$new_type> for $old_type {
76            #[inline]
77            fn from(v: $new_type) -> $old_type {
78                $old_type::$from_new(v.0)
79            }
80        }
81
82        impl From<$old_type> for $new_type {
83            #[inline]
84            fn from(v: $old_type) -> $new_type {
85                $new_type($old_type::$to_new(v))
86            }
87        }
88
89        impl Serialize for $new_type {
90            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91            where
92                S: Serializer,
93            {
94                self.to_native().serialize(serializer)
95            }
96        }
97
98        impl<'de> Deserialize<'de> for $new_type {
99            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100            where
101                D: Deserializer<'de>,
102            {
103                Ok($old_type::deserialize(deserializer)?.into())
104            }
105        }
106    };
107}
108
109endian_type!(u16, Le16, to_le, from_le);
110endian_type!(i16, SLe16, to_le, from_le);
111endian_type!(u32, Le32, to_le, from_le);
112endian_type!(i32, SLe32, to_le, from_le);
113endian_type!(u64, Le64, to_le, from_le);
114endian_type!(i64, SLe64, to_le, from_le);
115endian_type!(usize, LeSize, to_le, from_le);
116endian_type!(isize, SLeSize, to_le, from_le);
117endian_type!(u16, Be16, to_be, from_be);
118endian_type!(i16, SBe16, to_be, from_be);
119endian_type!(u32, Be32, to_be, from_be);
120endian_type!(i32, SBe32, to_be, from_be);
121endian_type!(u64, Be64, to_be, from_be);
122endian_type!(i64, SBe64, to_be, from_be);
123endian_type!(usize, BeSize, to_be, from_be);
124endian_type!(isize, SBeSize, to_be, from_be);
125
126#[cfg(test)]
127mod tests {
128    use std::convert::From;
129    use std::mem::align_of;
130    use std::mem::size_of;
131    use std::mem::transmute;
132
133    use super::*;
134
135    #[cfg(target_endian = "little")]
136    const NATIVE_LITTLE: bool = true;
137    #[cfg(target_endian = "big")]
138    const NATIVE_LITTLE: bool = false;
139    const NATIVE_BIG: bool = !NATIVE_LITTLE;
140
141    macro_rules! endian_test {
142        ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
143            mod $test_name {
144                use super::*;
145
146                #[allow(overflowing_literals)]
147                #[test]
148                fn equality() {
149                    let v = 0x0123456789ABCDEF as $old_type;
150                    let endian_v: $new_type = From::from(v);
151                    let endian_into: $old_type = endian_v.into();
152                    // SAFETY: trivially safe
153                    let endian_transmute: $old_type = unsafe { transmute(endian_v) };
154
155                    if $native {
156                        assert_eq!(endian_v, endian_transmute);
157                    } else {
158                        assert_eq!(endian_v, endian_transmute.swap_bytes());
159                    }
160
161                    assert_eq!(v, endian_into);
162                    assert!(v == endian_v);
163                    assert!(endian_v == v);
164                }
165
166                #[test]
167                fn alignment() {
168                    assert_eq!(align_of::<$new_type>(), align_of::<$old_type>());
169                }
170
171                #[test]
172                fn size() {
173                    assert_eq!(size_of::<$new_type>(), size_of::<$old_type>());
174                }
175            }
176        };
177    }
178
179    endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
180    endian_test!(i16, SLe16, test_sle16, NATIVE_LITTLE);
181    endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
182    endian_test!(i32, SLe32, test_sle32, NATIVE_LITTLE);
183    endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
184    endian_test!(i64, SLe64, test_sle64, NATIVE_LITTLE);
185    endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
186    endian_test!(isize, SLeSize, test_sle_size, NATIVE_LITTLE);
187    endian_test!(u16, Be16, test_be16, NATIVE_BIG);
188    endian_test!(i16, SBe16, test_sbe16, NATIVE_BIG);
189    endian_test!(u32, Be32, test_be32, NATIVE_BIG);
190    endian_test!(i32, SBe32, test_sbe32, NATIVE_BIG);
191    endian_test!(u64, Be64, test_be64, NATIVE_BIG);
192    endian_test!(i64, SBe64, test_sbe64, NATIVE_BIG);
193    endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
194    endian_test!(isize, SBeSize, test_sbe_size, NATIVE_BIG);
195}