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