1 // Copyright 2017 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE-BSD-3-Clause file. 4 // 5 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 6 7 //! Explicit endian types useful for embedding in structs or reinterpreting data. 8 //! 9 //! Each endian type is guaarnteed to have the same size and alignment as a regular unsigned 10 //! primitive of the equal size. 11 //! 12 //! # Examples 13 //! 14 //! ``` 15 //! # use vm_memory::{Be32, Le32}; 16 //! # 17 //! let b: Be32 = From::from(3); 18 //! let l: Le32 = From::from(3); 19 //! 20 //! assert_eq!(b.to_native(), 3); 21 //! assert_eq!(l.to_native(), 3); 22 //! assert!(b == 3); 23 //! assert!(l == 3); 24 //! 25 //! let b_trans: u32 = unsafe { std::mem::transmute(b) }; 26 //! let l_trans: u32 = unsafe { std::mem::transmute(l) }; 27 //! 28 //! #[cfg(target_endian = "little")] 29 //! assert_eq!(l_trans, 3); 30 //! #[cfg(target_endian = "big")] 31 //! assert_eq!(b_trans, 3); 32 //! 33 //! assert_ne!(b_trans, l_trans); 34 //! ``` 35 36 use std::mem::{align_of, size_of}; 37 38 use crate::bytes::ByteValued; 39 40 macro_rules! const_assert { 41 ($condition:expr) => { 42 let _ = [(); 0 - !$condition as usize]; 43 }; 44 } 45 46 macro_rules! endian_type { 47 ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => { 48 /// An unsigned integer type of with an explicit endianness. 49 /// 50 /// See module level documentation for examples. 51 #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] 52 pub struct $new_type($old_type); 53 54 impl $new_type { 55 fn _assert() { 56 const_assert!(align_of::<$new_type>() == align_of::<$old_type>()); 57 const_assert!(size_of::<$new_type>() == size_of::<$old_type>()); 58 } 59 60 /// Converts `self` to the native endianness. 61 pub fn to_native(self) -> $old_type { 62 $old_type::$from_new(self.0) 63 } 64 } 65 66 // SAFETY: Safe because we are using this for implementing ByteValued for endian types 67 // which are POD. 68 unsafe impl ByteValued for $new_type {} 69 70 impl PartialEq<$old_type> for $new_type { 71 fn eq(&self, other: &$old_type) -> bool { 72 self.0 == $old_type::$to_new(*other) 73 } 74 } 75 76 impl PartialEq<$new_type> for $old_type { 77 fn eq(&self, other: &$new_type) -> bool { 78 $old_type::$to_new(other.0) == *self 79 } 80 } 81 82 impl From<$new_type> for $old_type { 83 fn from(v: $new_type) -> $old_type { 84 v.to_native() 85 } 86 } 87 88 impl From<$old_type> for $new_type { 89 fn from(v: $old_type) -> $new_type { 90 $new_type($old_type::$to_new(v)) 91 } 92 } 93 }; 94 } 95 96 endian_type!(u16, Le16, to_le, from_le); 97 endian_type!(u32, Le32, to_le, from_le); 98 endian_type!(u64, Le64, to_le, from_le); 99 endian_type!(usize, LeSize, to_le, from_le); 100 endian_type!(u16, Be16, to_be, from_be); 101 endian_type!(u32, Be32, to_be, from_be); 102 endian_type!(u64, Be64, to_be, from_be); 103 endian_type!(usize, BeSize, to_be, from_be); 104 105 #[cfg(test)] 106 mod tests { 107 #![allow(clippy::undocumented_unsafe_blocks)] 108 use super::*; 109 110 use std::convert::From; 111 use std::mem::transmute; 112 113 #[cfg(target_endian = "little")] 114 const NATIVE_LITTLE: bool = true; 115 #[cfg(target_endian = "big")] 116 const NATIVE_LITTLE: bool = false; 117 const NATIVE_BIG: bool = !NATIVE_LITTLE; 118 119 macro_rules! endian_test { 120 ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => { 121 mod $test_name { 122 use super::*; 123 124 #[allow(overflowing_literals)] 125 #[test] 126 fn test_endian_type() { 127 <$new_type>::_assert(); 128 129 let v = 0x0123_4567_89AB_CDEF as $old_type; 130 let endian_v: $new_type = From::from(v); 131 let endian_into: $old_type = endian_v.into(); 132 let endian_transmute: $old_type = unsafe { transmute(endian_v) }; 133 134 if $native { 135 assert_eq!(endian_v, endian_transmute); 136 } else { 137 assert_eq!(endian_v, endian_transmute.swap_bytes()); 138 } 139 140 assert_eq!(endian_into, v); 141 assert_eq!(endian_v.to_native(), v); 142 143 assert!(v == endian_v); 144 assert!(endian_v == v); 145 } 146 } 147 }; 148 } 149 150 endian_test!(u16, Le16, test_le16, NATIVE_LITTLE); 151 endian_test!(u32, Le32, test_le32, NATIVE_LITTLE); 152 endian_test!(u64, Le64, test_le64, NATIVE_LITTLE); 153 endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE); 154 endian_test!(u16, Be16, test_be16, NATIVE_BIG); 155 endian_test!(u32, Be32, test_be32, NATIVE_BIG); 156 endian_test!(u64, Be64, test_be64, NATIVE_BIG); 157 endian_test!(usize, BeSize, test_be_size, NATIVE_BIG); 158 } 159