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