mod test;
use core::mem::ManuallyDrop;
use oct::{
FromOctets,
Immutable,
Init,
IntoOctets,
Outlay,
};
#[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) }
}
#[inline]
#[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 metadata = U::classify_size(size)
.expect("cannot transmute reference with incompatible object size");
transmute_ref_with_metadata(r, metadata)
}
#[inline]
#[must_use]
#[track_caller]
pub fn transmute_ref_with_metadata<T, U>(r: &T, metadata: U::Metadata) -> &U
where
T: ?Sized + IntoOctets + Init + Immutable,
U: ?Sized + FromOctets + Outlay + Immutable,
{
let size = if let Ok(layout) = U::layout_for_metadata(metadata) {
layout.size()
} else {
panic!("cannot construct layout for dst with length `{metadata:?}`");
};
assert!(
size_of_val(r) >= size,
"cannot construct reference from undersized octets",
);
let data = (&raw const *r).cast::<u8>();
let p = U::ptr_from_raw_parts(data, metadata);
assert_eq!(
p.addr() % U::ALIGN,
0,
"cannot construct reference from unaligned octets",
);
unsafe { &*p }
}
#[inline]
#[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 metadata = U::classify_size(size)
.expect("cannot transmute reference with incompatible object size");
transmute_mut_with_metadata(r, metadata)
}
#[inline]
#[must_use]
#[track_caller]
pub fn transmute_mut_with_metadata<T, U>(r: &mut T, metadata: U::Metadata) -> &mut U
where
T: ?Sized + IntoOctets + FromOctets + Init,
U: ?Sized + FromOctets + Outlay + Init,
{
let size = if let Ok(layout) = U::layout_for_metadata(metadata) {
layout.size()
} else {
panic!("cannot construct layout for dst with length `{metadata:?}`");
};
assert!(
size_of_val(r) >= size,
"cannot transmute reference from undersized object",
);
let data = (&raw mut *r).cast::<u8>();
let p = U::ptr_from_raw_parts_mut(data, metadata);
assert_eq!(
p.addr() % U::ALIGN,
0,
"cannot transmute reference with decreasing alignement",
);
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) }
}