#![no_std]
#[doc(hidden)]
pub use core::marker::PhantomData;
#[doc(hidden)]
pub use const_panic;
use bytemuck::TransparentWrapper;
#[macro_export]
macro_rules! wrapper_inner {
(
$ArgsTy:ident,
$reff:expr,
$( $Outer:ty, [$Inner:ty, $($__0:tt)*] )?
) => {
match $reff {
inner => unsafe {
let inner: &_ = inner;
$crate::$ArgsTy $(::<$Outer, $Inner>)? {
reff: inner,
ptr: inner as *const _ as _,
}.__call()
}
}
}
}
#[macro_export]
macro_rules! wrapper_wrap_ref {
($reff:expr $(, $Outer:ty $(, $Inner:ty)?)? $(,)?) => {
$crate::wrapper_inner!(
__WrapRefArgs,
$reff,
$($Outer, [$($Inner,)? _,])?
)
}
}
#[macro_export]
macro_rules! wrapper_peel_ref {
($reff:expr $(, $Outer:ty $(, $Inner:ty)?)? $(,)?) => {
$crate::wrapper_inner!(
__PeelRefArgs,
$reff,
$($Outer, [$($Inner,)? _,])?
)
};
}
#[doc(hidden)]
pub struct __PeelRefArgs<'a, Outer: ?Sized, Inner: ?Sized> {
pub reff: &'a Outer,
pub ptr: *const Inner,
}
impl<'a, Outer: ?Sized, Inner: ?Sized> __PeelRefArgs<'a, Outer, Inner> {
#[track_caller]
#[doc(hidden)]
pub const unsafe fn __call(self) -> &'a Inner
where
Outer: TransparentWrapper<Inner>
{
#[cfg(feature = "debug_checks")]
if TWHelper::<Outer, Inner>::NOT_SAME_SIZE {
unequal_ptr_size_panic(
core::mem::size_of::<*const Outer>(),
core::mem::size_of::<*const Inner>(),
)
}
&*self.ptr
}
}
#[doc(hidden)]
pub struct __WrapRefArgs<'a, Outer: ?Sized, Inner: ?Sized> {
pub reff: &'a Inner,
pub ptr: *const Outer,
}
impl<'a, Outer: ?Sized, Inner: ?Sized> __WrapRefArgs<'a, Outer, Inner> {
#[track_caller]
#[doc(hidden)]
pub const unsafe fn __call(self) -> &'a Outer
where
Outer: TransparentWrapper<Inner>
{
#[cfg(feature = "debug_checks")]
if TWHelper::<Outer, Inner>::NOT_SAME_SIZE {
unequal_ptr_size_panic(
core::mem::size_of::<*const Inner>(),
core::mem::size_of::<*const Outer>(),
)
}
&*self.ptr
}
}
#[cfg(feature = "debug_checks")]
struct TWHelper<Outer: ?Sized, Inner: ?Sized>(PhantomData<Outer>, PhantomData<Inner>);
#[cfg(feature = "debug_checks")]
impl<Outer: ?Sized, Inner: ?Sized> TWHelper<Outer, Inner>
where
Outer: TransparentWrapper<Inner>
{
const NOT_SAME_SIZE: bool =
core::mem::size_of::<*const Outer>() != core::mem::size_of::<*const Inner>();
}
#[track_caller]
#[cold]
#[inline(never)]
#[cfg(feature = "debug_checks")]
const fn unequal_ptr_size_panic(size_of_from: usize, size_of_to: usize) -> ! {
use crate::const_panic::{FmtArg as FA, PanicVal as PV};
crate::const_panic::concat_panic(&[&[
PV::write_str("\nexpected transmute not to change the pointer size,"),
PV::write_str(" size goes from: "), PV::from_usize(size_of_from, FA::DEBUG),
PV::write_str(" to: "), PV::from_usize(size_of_to, FA::DEBUG),
]])
}