mod test;
use crate::{
FromOctets,
Immutable,
Init,
IntoOctets,
Outlay,
};
use core::mem::ManuallyDrop;
#[inline]
#[must_use]
#[track_caller]
pub const fn transmute<T, U>(value: T) -> U
where
T: IntoOctets + Init,
U: FromOctets,
{
const {
assert!(
size_of::<U>() == size_of::<T>(),
"cannot transmute types of different sizes",
);
}
unsafe { transmute_unchecked(value) }
}
#[must_use]
#[track_caller]
pub fn transmute_ref<T, U>(r: &T) -> &U
where
T: ?Sized + IntoOctets + Init + Immutable,
U: ?Sized + FromOctets + Outlay + Immutable,
{
let size = size_of_val(r);
let meta = U::classify_size(size)
.expect("cannot transmute objects of different sizes");
let data = r.as_octets().as_ptr();
assert!(
data.addr().is_multiple_of(U::ALIGN),
"cannot transmute reference to increasing alignement",
);
let p = U::ptr_from_raw_parts(data, meta);
unsafe { &*p }
}
#[must_use]
#[track_caller]
pub fn transmute_mut<T, U>(r: &mut T) -> &mut U
where
T: ?Sized + IntoOctets + FromOctets + Init,
U: ?Sized + FromOctets + Outlay + Init,
{
let size = size_of_val(r);
let meta = U::classify_size(size)
.expect("cannot transmute objects of different sizes");
let data = r.as_octets_mut().as_mut_ptr();
assert!(
data.addr().is_multiple_of(U::ALIGN),
"cannot transmute reference to increasing alignement",
);
let p = U::ptr_from_raw_parts_mut(data, meta);
unsafe { &mut *p }
}
#[inline(always)]
#[must_use]
#[track_caller]
pub const unsafe fn transmute_unchecked<T, U>(value: T) -> U {
debug_assert!(
size_of::<U>() == size_of::<T>(),
"cannot transmute types of different sizes",
);
#[repr(C)]
union Transmute<Src, Dst> {
src: ManuallyDrop<Src>,
dst: ManuallyDrop<Dst>,
}
let transmute = Transmute { src: ManuallyDrop::new(value) };
unsafe { ManuallyDrop::into_inner(transmute.dst) }
}