#[macro_export]
macro_rules! transmute {
($e:expr) => {{
let e = $e;
if false {
struct AssertIsIntoBytes<T: $crate::IntoBytes>(T);
let _ = AssertIsIntoBytes(e);
struct AssertIsFromBytes<U: $crate::FromBytes>(U);
#[allow(unused, unreachable_code)]
let u = AssertIsFromBytes(loop {});
u.0
} else {
let u = unsafe {
#[allow(clippy::missing_transmute_annotations)]
$crate::util::macro_util::core_reexport::mem::transmute(e)
};
$crate::util::macro_util::must_use(u)
}
}}
}
#[macro_export]
macro_rules! transmute_ref {
($e:expr) => {{
let e: &_ = $e;
#[allow(unused, clippy::diverging_sub_expression)]
if false {
struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
struct AssertSrcIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);
struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
struct AssertDstIsFromBytes<'a, U: ?::core::marker::Sized + $crate::FromBytes>(&'a U);
struct AssertDstIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);
let _ = AssertSrcIsSized(e);
let _ = AssertSrcIsIntoBytes(e);
let _ = AssertSrcIsImmutable(e);
if true {
#[allow(unused, unreachable_code)]
let u = AssertDstIsSized(loop {});
u.0
} else if true {
#[allow(unused, unreachable_code)]
let u = AssertDstIsFromBytes(loop {});
u.0
} else {
#[allow(unused, unreachable_code)]
let u = AssertDstIsImmutable(loop {});
u.0
}
} else if false {
let mut t = loop {};
e = &t;
let u;
$crate::assert_size_eq!(t, u);
$crate::assert_align_gt_eq!(t, u);
&u
} else {
let u = unsafe { $crate::util::macro_util::transmute_ref(e) };
$crate::util::macro_util::must_use(u)
}
}}
}
#[macro_export]
macro_rules! transmute_mut {
($e:expr) => {{
let e: &mut _ = $e;
#[allow(unused, clippy::diverging_sub_expression)]
if false {
struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
struct AssertSrcIsFromBytes<'a, T: ?::core::marker::Sized + $crate::FromBytes>(&'a T);
struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
struct AssertDstIsFromBytes<'a, T: ?::core::marker::Sized + $crate::FromBytes>(&'a T);
struct AssertDstIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
if true {
let _ = AssertSrcIsSized(&*e);
} else if true {
let _ = AssertSrcIsFromBytes(&*e);
} else {
let _ = AssertSrcIsIntoBytes(&*e);
}
if true {
#[allow(unused, unreachable_code)]
let u = AssertDstIsSized(loop {});
&mut *u.0
} else if true {
#[allow(unused, unreachable_code)]
let u = AssertDstIsFromBytes(loop {});
&mut *u.0
} else {
#[allow(unused, unreachable_code)]
let u = AssertDstIsIntoBytes(loop {});
&mut *u.0
}
} else if false {
let mut t = loop {};
e = &mut t;
let u;
$crate::assert_size_eq!(t, u);
$crate::assert_align_gt_eq!(t, u);
&mut u
} else {
let u = unsafe { $crate::util::macro_util::transmute_mut(e) };
$crate::util::macro_util::must_use(u)
}
}}
}
#[macro_export]
macro_rules! try_transmute {
($e:expr) => {{
let e = $e;
if false {
Ok(unsafe {
#[allow(clippy::missing_transmute_annotations)]
$crate::util::macro_util::core_reexport::mem::transmute(e)
})
} else {
$crate::util::macro_util::try_transmute::<_, _>(e)
}
}}
}
#[macro_export]
macro_rules! try_transmute_ref {
($e:expr) => {{
let e: &_ = $e;
#[allow(unreachable_code, unused, clippy::diverging_sub_expression)]
if false {
let mut t = loop {};
e = &t;
let u;
$crate::assert_size_eq!(t, u);
$crate::assert_align_gt_eq!(t, u);
Ok(&u)
} else {
$crate::util::macro_util::try_transmute_ref::<_, _>(e)
}
}}
}
#[macro_export]
macro_rules! try_transmute_mut {
($e:expr) => {{
let e: &mut _ = $e;
#[allow(unreachable_code, unused, clippy::diverging_sub_expression)]
if false {
let mut t = loop {};
e = &mut t;
let u;
$crate::assert_size_eq!(t, u);
$crate::assert_align_gt_eq!(t, u);
Ok(&mut u)
} else {
$crate::util::macro_util::try_transmute_mut::<_, _>(e)
}
}}
}
#[doc(alias("include_bytes", "include_data", "include_type"))]
#[macro_export]
macro_rules! include_value {
($file:expr $(,)?) => {
$crate::transmute!(*::core::include_bytes!($file))
};
}
#[cfg(test)]
mod tests {
use crate::util::testutil::*;
use crate::*;
#[test]
fn test_transmute() {
let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
let x: [[u8; 2]; 4] = transmute!(array_of_u8s);
assert_eq!(x, array_of_arrays);
let x: [u8; 8] = transmute!(array_of_arrays);
assert_eq!(x, array_of_u8s);
#[derive(IntoBytes)]
#[repr(transparent)]
struct PanicOnDrop(());
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!("PanicOnDrop::drop");
}
}
#[allow(clippy::let_unit_value)]
let _: () = transmute!(PanicOnDrop(()));
const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S);
assert_eq!(X, ARRAY_OF_ARRAYS);
let x: usize = transmute!(UnsafeCell::new(1usize));
assert_eq!(x, 1);
let x: UnsafeCell<usize> = transmute!(1usize);
assert_eq!(x.into_inner(), 1);
let x: UnsafeCell<isize> = transmute!(UnsafeCell::new(1usize));
assert_eq!(x.into_inner(), 1);
}
#[test]
fn test_transmute_ref() {
let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s);
assert_eq!(*x, array_of_arrays);
let x: &[u8; 8] = transmute_ref!(&array_of_arrays);
assert_eq!(*x, array_of_u8s);
const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
#[allow(clippy::redundant_static_lifetimes)]
const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S);
assert_eq!(*X, ARRAY_OF_ARRAYS);
let x: &[u8; 8] = transmute_ref!(X);
assert_eq!(*x, ARRAY_OF_U8S);
let u = AU64(0);
let array = [0, 0, 0, 0, 0, 0, 0, 0];
let x: &[u8; 8] = transmute_ref!(&u);
assert_eq!(*x, array);
let mut x = 0u8;
#[allow(clippy::useless_transmute)]
let y: &u8 = transmute_ref!(&mut x);
assert_eq!(*y, 0);
}
#[test]
fn test_try_transmute() {
let array_of_bools = [false, true, false, true, false, true, false, true];
let array_of_arrays = [[0, 1], [0, 1], [0, 1], [0, 1]];
let x: Result<[[u8; 2]; 4], _> = try_transmute!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
let x: Result<[bool; 8], _> = try_transmute!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
let x: Result<usize, _> = try_transmute!(UnsafeCell::new(1usize));
assert_eq!(x.unwrap(), 1);
let x: Result<UnsafeCell<usize>, _> = try_transmute!(1usize);
assert_eq!(x.unwrap().into_inner(), 1);
let x: Result<UnsafeCell<isize>, _> = try_transmute!(UnsafeCell::new(1usize));
assert_eq!(x.unwrap().into_inner(), 1);
#[derive(FromBytes, IntoBytes, Debug, PartialEq)]
#[repr(transparent)]
struct PanicOnDrop<T>(T);
impl<T> Drop for PanicOnDrop<T> {
fn drop(&mut self) {
panic!("PanicOnDrop dropped");
}
}
let x: Result<usize, _> = try_transmute!(PanicOnDrop(1usize));
assert_eq!(x, Ok(1));
let y: Result<bool, _> = try_transmute!(PanicOnDrop(2u8));
assert_eq!(y.as_ref().map_err(|p| &p.src.0), Err::<&bool, _>(&2u8));
mem::forget(y);
}
#[test]
fn test_try_transmute_ref() {
let array_of_bools = &[false, true, false, true, false, true, false, true];
let array_of_arrays = &[[0, 1], [0, 1], [0, 1], [0, 1]];
let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
let x: Result<&[bool; 8], _> = try_transmute_ref!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
{
let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
}
let u = AU64(0);
let array = [0u8, 0, 0, 0, 0, 0, 0, 0];
let x: Result<&[u8; 8], _> = try_transmute_ref!(&u);
assert_eq!(x, Ok(&array));
let mut x = 0u8;
#[allow(clippy::useless_transmute)]
let y: Result<&u8, _> = try_transmute_ref!(&mut x);
assert_eq!(y, Ok(&0));
}
#[test]
fn test_try_transmute_mut() {
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
{
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
}
let u = &mut AU64(0);
let array = &mut [0u8, 0, 0, 0, 0, 0, 0, 0];
let x: Result<&mut [u8; 8], _> = try_transmute_mut!(u);
assert_eq!(x, Ok(array));
let mut x = 0u8;
#[allow(clippy::useless_transmute)]
let y: Result<&mut u8, _> = try_transmute_mut!(&mut x);
assert_eq!(y, Ok(&mut 0));
}
#[test]
fn test_transmute_mut() {
let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s);
assert_eq!(*x, array_of_arrays);
let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
assert_eq!(*x, array_of_u8s);
{
let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
assert_eq!(*x, array_of_u8s);
}
let mut u = AU64(0);
let array = [0, 0, 0, 0, 0, 0, 0, 0];
let x: &[u8; 8] = transmute_mut!(&mut u);
assert_eq!(*x, array);
let mut x = 0u8;
#[allow(clippy::useless_transmute)]
let y: &u8 = transmute_mut!(&mut x);
assert_eq!(*y, 0);
}
#[test]
fn test_macros_evaluate_args_once() {
let mut ctr = 0;
#[allow(clippy::useless_transmute)]
let _: usize = transmute!({
ctr += 1;
0usize
});
assert_eq!(ctr, 1);
let mut ctr = 0;
let _: &usize = transmute_ref!({
ctr += 1;
&0usize
});
assert_eq!(ctr, 1);
let mut ctr: usize = 0;
let _: &mut usize = transmute_mut!({
ctr += 1;
&mut ctr
});
assert_eq!(ctr, 1);
let mut ctr = 0;
#[allow(clippy::useless_transmute)]
let _: usize = try_transmute!({
ctr += 1;
0usize
})
.unwrap();
assert_eq!(ctr, 1);
}
#[test]
fn test_include_value() {
const AS_U32: u32 = include_value!("../testdata/include_value/data");
assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
const AS_I32: i32 = include_value!("../testdata/include_value/data");
assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
}
}