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