xref: /aosp_15_r20/external/crosvm/common/data_model/src/endian.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
35 use serde::Deserialize;
36 use serde::Deserializer;
37 use serde::Serialize;
38 use serde::Serializer;
39 use zerocopy::AsBytes;
40 use zerocopy::FromBytes;
41 use zerocopy::FromZeroes;
42 
43 macro_rules! endian_type {
44     ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
45         /// An integer type of with an explicit endianness.
46         ///
47         /// See module level documentation for examples.
48         #[repr(transparent)]
49         #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, FromZeroes, FromBytes, AsBytes)]
50         pub struct $new_type($old_type);
51 
52         impl $new_type {
53             /// Converts `self` to the native endianness.
54             #[inline]
55             pub fn to_native(self) -> $old_type {
56                 $old_type::$from_new(self.0)
57             }
58         }
59 
60         impl PartialEq<$old_type> for $new_type {
61             #[inline]
62             fn eq(&self, other: &$old_type) -> bool {
63                 self.0 == $old_type::$to_new(*other)
64             }
65         }
66 
67         impl PartialEq<$new_type> for $old_type {
68             #[inline]
69             fn eq(&self, other: &$new_type) -> bool {
70                 $old_type::$to_new(other.0) == *self
71             }
72         }
73 
74         impl From<$new_type> for $old_type {
75             #[inline]
76             fn from(v: $new_type) -> $old_type {
77                 $old_type::$from_new(v.0)
78             }
79         }
80 
81         impl From<$old_type> for $new_type {
82             #[inline]
83             fn from(v: $old_type) -> $new_type {
84                 $new_type($old_type::$to_new(v))
85             }
86         }
87 
88         impl Serialize for $new_type {
89             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
90             where
91                 S: Serializer,
92             {
93                 self.to_native().serialize(serializer)
94             }
95         }
96 
97         impl<'de> Deserialize<'de> for $new_type {
98             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99             where
100                 D: Deserializer<'de>,
101             {
102                 Ok($old_type::deserialize(deserializer)?.into())
103             }
104         }
105     };
106 }
107 
108 endian_type!(u16, Le16, to_le, from_le);
109 endian_type!(i16, SLe16, to_le, from_le);
110 endian_type!(u32, Le32, to_le, from_le);
111 endian_type!(i32, SLe32, to_le, from_le);
112 endian_type!(u64, Le64, to_le, from_le);
113 endian_type!(i64, SLe64, to_le, from_le);
114 endian_type!(usize, LeSize, to_le, from_le);
115 endian_type!(isize, SLeSize, to_le, from_le);
116 endian_type!(u16, Be16, to_be, from_be);
117 endian_type!(i16, SBe16, to_be, from_be);
118 endian_type!(u32, Be32, to_be, from_be);
119 endian_type!(i32, SBe32, to_be, from_be);
120 endian_type!(u64, Be64, to_be, from_be);
121 endian_type!(i64, SBe64, to_be, from_be);
122 endian_type!(usize, BeSize, to_be, from_be);
123 endian_type!(isize, SBeSize, to_be, from_be);
124 
125 #[cfg(test)]
126 mod tests {
127     use std::convert::From;
128     use std::mem::align_of;
129     use std::mem::size_of;
130     use std::mem::transmute;
131 
132     use super::*;
133 
134     #[cfg(target_endian = "little")]
135     const NATIVE_LITTLE: bool = true;
136     #[cfg(target_endian = "big")]
137     const NATIVE_LITTLE: bool = false;
138     const NATIVE_BIG: bool = !NATIVE_LITTLE;
139 
140     macro_rules! endian_test {
141         ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
142             mod $test_name {
143                 use super::*;
144 
145                 #[allow(overflowing_literals)]
146                 #[test]
147                 fn equality() {
148                     let v = 0x0123456789ABCDEF as $old_type;
149                     let endian_v: $new_type = From::from(v);
150                     let endian_into: $old_type = endian_v.into();
151                     // SAFETY: trivially safe
152                     let endian_transmute: $old_type = unsafe { transmute(endian_v) };
153 
154                     if $native {
155                         assert_eq!(endian_v, endian_transmute);
156                     } else {
157                         assert_eq!(endian_v, endian_transmute.swap_bytes());
158                     }
159 
160                     assert_eq!(v, endian_into);
161                     assert!(v == endian_v);
162                     assert!(endian_v == v);
163                 }
164 
165                 #[test]
166                 fn alignment() {
167                     assert_eq!(align_of::<$new_type>(), align_of::<$old_type>());
168                 }
169 
170                 #[test]
171                 fn size() {
172                     assert_eq!(size_of::<$new_type>(), size_of::<$old_type>());
173                 }
174             }
175         };
176     }
177 
178     endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
179     endian_test!(i16, SLe16, test_sle16, NATIVE_LITTLE);
180     endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
181     endian_test!(i32, SLe32, test_sle32, NATIVE_LITTLE);
182     endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
183     endian_test!(i64, SLe64, test_sle64, NATIVE_LITTLE);
184     endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
185     endian_test!(isize, SLeSize, test_sle_size, NATIVE_LITTLE);
186     endian_test!(u16, Be16, test_be16, NATIVE_BIG);
187     endian_test!(i16, SBe16, test_sbe16, NATIVE_BIG);
188     endian_test!(u32, Be32, test_be32, NATIVE_BIG);
189     endian_test!(i32, SBe32, test_sbe32, NATIVE_BIG);
190     endian_test!(u64, Be64, test_be64, NATIVE_BIG);
191     endian_test!(i64, SBe64, test_sbe64, NATIVE_BIG);
192     endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
193     endian_test!(isize, SBeSize, test_sbe_size, NATIVE_BIG);
194 }
195