| //! Macros implementing `FromBits` |
| |
| macro_rules! impl_from_bits_ { |
| ($id:ident[$test_tt:tt]: $from_ty:ident) => { |
| impl crate::api::into_bits::FromBits<$from_ty> for $id { |
| #[inline] |
| fn from_bits(x: $from_ty) -> Self { |
| unsafe { crate::mem::transmute(x) } |
| } |
| } |
| |
| test_if! { |
| $test_tt: |
| paste::item! { |
| pub mod [<$id _from_bits_ $from_ty>] { |
| use super::*; |
| #[cfg_attr(not(target_arch = "wasm32"), test)] |
| #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] |
| fn test() { |
| use crate::{ |
| ptr::{read_unaligned}, |
| mem::{size_of, zeroed} |
| }; |
| use crate::IntoBits; |
| assert_eq!(size_of::<$id>(), |
| size_of::<$from_ty>()); |
| // This is safe because we never create a reference to |
| // uninitialized memory: |
| let a: $from_ty = unsafe { zeroed() }; |
| |
| let b_0: $id = crate::FromBits::from_bits(a); |
| let b_1: $id = a.into_bits(); |
| |
| // Check that these are byte-wise equal, that is, |
| // that the bit patterns are identical: |
| for i in 0..size_of::<$id>() { |
| // This is safe because we only read initialized |
| // memory in bounds. Also, taking a reference to |
| // `b_i` is ok because the fields are initialized. |
| unsafe { |
| let b_0_v: u8 = read_unaligned( |
| (&b_0 as *const $id as *const u8) |
| .wrapping_add(i) |
| ); |
| let b_1_v: u8 = read_unaligned( |
| (&b_1 as *const $id as *const u8) |
| .wrapping_add(i) |
| ); |
| assert_eq!(b_0_v, b_1_v); |
| } |
| } |
| } |
| } |
| } |
| } |
| }; |
| } |
| |
| macro_rules! impl_from_bits { |
| ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { |
| $( |
| impl_from_bits_!($id[$test_tt]: $from_ty); |
| )* |
| } |
| } |
| |
| #[allow(unused)] |
| macro_rules! impl_into_bits { |
| ($id:ident[$test_tt:tt]: $($from_ty:ident),*) => { |
| $( |
| impl_from_bits_!($from_ty[$test_tt]: $id); |
| )* |
| } |
| } |