//! Extended type erasure support.
//!
//! The [`core::any`] module, and [`Any`][core::any::Any] in particular,
//! provide great utilities to perform type erasure. However, there are some
//! limitations. Namely `Any` requires the type be `'static`. This doesn't
//! work for [`treaty`][crate] as it needs the `'ctx` lifetime.
//! Also `Any` doesn't allow type erasing `!Sized` types as this would
//! result in a "double fat pointer"?!, and those don't exist.
//!
//! This module solves both problems. First, [`LtAny`] is a lifetime containing
//! counterpart to [`Any`][core::any::Any]. [`LtAny`] allows one lifetime which
//! [`treaty`][crate] uses for the `'ctx` lifetime shared by walkers and visitors.
//! Second, [`IndirectLtAny`] is able to type erase a pointer like type even
//! if it's a `!Sized` type. This allows for type erasing borrows of trait objects
//! like `&dyn Trait`.
//!
//! For a type to be compatible with this module it needs to implement [`TypeNameable`]
//! to give it a unique [`TypeId`][core::any::TypeId]. This can be done manually
//! without unsafe code. However, its recommended to use the provided [`nameable`]
//! macro when possible.
// pub mod static_wrapper;
use crate::bijective_higher_ranked_trait;
use core::{
marker::{PhantomData, PhantomPinned},
mem::{ManuallyDrop, MaybeUninit},
};
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
bijective_higher_ranked_trait! {
pub type class MaybeSized['lt][]: [for<'a>]
}
bijective_higher_ranked_trait! {
pub type class TypeName[][]: {'static} [for<'lt> MaybeSized::Trait<'lt>]
}
// trait Other<'lt> {}
//
// trait Demo<'lt> {
// fn demo(&self) -> &'lt i32;
// }
//
// bijective_higher_ranked_type! {
// type DynDemo['lt][]: (MaybeSized)['lt][] = for<'a> dyn Demo<'lt> + 'a
// }
//
// bijective_higher_ranked_type! {
// type DemoName[][]: (TypeName)[][] = for<'lt> DynDemo<'lt>
// }
// bijective_higher_ranked_type! {
// pub type MaybeSizedRef['lt][T]: (MaybeSized)['lt][] = for<'a> &'lt T where { T: 'lt }
// }
const _: () = {
pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
pub struct LowerName<'lt, T: ?Sized>(PhantomData<fn() -> (&'lt (), *const T)>);
impl<'a, 'lt, T: ?Sized + MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>>
MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)> for LowerName<'lt, T>
{
type T = &'a <T as MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>>::T;
}
impl<'a, 'lt, T: ?Sized + MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)>>
MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)> for &'a T
{
type HigherRanked =
LowerName<'lt, <T as MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)>>::HigherRanked>;
}
impl<'lt, T: ?Sized + TypeName::LowerForLt<'lt, &'lt ()>> TypeName::LowerForLt<'lt, &'lt ()>
for Name<T>
{
type T = LowerName<'lt, <T as TypeName::LowerForLt<'lt, &'lt ()>>::T>;
}
impl<'lt, T: ?Sized + 'lt + TypeName::RaiseForLt<'lt, &'lt ()>>
TypeName::RaiseForLt<'lt, &'lt ()> for LowerName<'lt, T>
{
type HigherRanked = Name<TypeName::HigherRanked<'lt, T>>;
}
};
const _: () = {
pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
pub struct LowerName<'lt, T: ?Sized>(PhantomData<fn() -> (&'lt (), *const T)>);
impl<'a, 'lt, T: ?Sized + MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>>
MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)> for LowerName<'lt, T>
{
type T = &'a mut <T as MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>>::T;
}
impl<'a, 'lt, T: ?Sized + MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)>>
MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)> for &'a mut T
{
type HigherRanked =
LowerName<'lt, <T as MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)>>::HigherRanked>;
}
impl<'lt, T: ?Sized + TypeName::LowerForLt<'lt, &'lt ()>> TypeName::LowerForLt<'lt, &'lt ()>
for Name<T>
{
type T = LowerName<'lt, <T as TypeName::LowerForLt<'lt, &'lt ()>>::T>;
}
impl<'lt, T: ?Sized + 'lt + TypeName::RaiseForLt<'lt, &'lt ()>>
TypeName::RaiseForLt<'lt, &'lt ()> for LowerName<'lt, T>
{
type HigherRanked = Name<TypeName::HigherRanked<'lt, T>>;
}
};
#[cfg(feature = "alloc")]
const _: () = {
pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
pub struct LowerName<'lt, T: ?Sized>(PhantomData<fn() -> (&'lt (), *const T)>);
impl<'a, 'lt, T: ?Sized + MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>>
MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)> for LowerName<'lt, T>
{
type T = Box<<T as MaybeSized::LowerForLt<'a, 'lt, &'a (&'lt (),)>>::T>;
}
impl<'a, 'lt, T: ?Sized + MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)>>
MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)> for Box<T>
{
type HigherRanked =
LowerName<'lt, <T as MaybeSized::RaiseForLt<'a, 'lt, &'a (&'lt (),)>>::HigherRanked>;
}
impl<'lt, T: ?Sized + TypeName::LowerForLt<'lt, &'lt ()>> TypeName::LowerForLt<'lt, &'lt ()>
for Name<T>
{
type T = LowerName<'lt, <T as TypeName::LowerForLt<'lt, &'lt ()>>::T>;
}
impl<'lt, T: ?Sized + 'lt + TypeName::RaiseForLt<'lt, &'lt ()>>
TypeName::RaiseForLt<'lt, &'lt ()> for LowerName<'lt, T>
{
type HigherRanked = Name<TypeName::HigherRanked<'lt, T>>;
}
};
// nameable! {
// pub struct Name['a, 'lt, T];
// impl [T::ForLtName] for &'lt T where {
// T: TypeNameableForLt<'a, 'lt, &'a &'lt ()> + ?Sized
// }
// impl [T] where &'lt T::ForLtNameable {
// T: TypeNameForLt<'a, 'lt, &'a &'lt ()> + ?Sized, T::ForLtNameable: 'lt
// }
// }
// nameable! {
// pub struct Name['a, 'lt, T];
// impl [<T as TypeNameableHelper<'lt>>::Name] for &'lt mut T where {
// T: TypeNameable<'lt> + ?Sized
// }
// impl [T] where &'lt mut T::Nameable {
// T: TypeNameForLt<'a, 'lt, &'a &'lt ()> + ?Sized, T::Nameable: 'lt
// }
// }
//
// nameable! {
// pub struct Name['a, 'lt, T];
// impl [<T as TypeNameableHelper<'lt>>::Name] for *const T where {
// T: TypeNameable<'lt> + ?Sized
// }
// impl [T] where *const T::Nameable {
// T: TypeNameForLt<'a, 'lt, &'a &'lt ()> + ?Sized
// }
// }
//
// nameable! {
// pub struct Name['a, 'lt, T];
// impl [<T as TypeNameableHelper<'lt>>::Name] for *mut T where {
// T: TypeNameable<'lt> + ?Sized
// }
// impl [T] where *mut T::Nameable {
// T: TypeNameForLt<'a, 'lt, &'a &'lt ()> + ?Sized
// }
// }
//
// #[cfg(feature = "alloc")]
// nameable! {
// pub struct Name['a, 'lt, T];
// impl [<T as TypeNameableHelper<'lt>>::Name] for Box<T> where {
// T: TypeNameable<'lt> + ?Sized
// }
// impl [T] where Box<T::Nameable> {
// T: TypeNameForLt<'a, 'lt, &'a &'lt ()> + ?Sized
// }
// }
/// [`TypeId`][core::any::TypeId] with a lifetime generic `'lt`.
///
/// This allows comparing types that contain zero or one lifetimes.
/// When `LtTypeId::of::<A>() == LtTypeId::of::<B>()` then `A` is `B`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Debug)]
pub struct LtTypeId<'lt> {
/// Invariant over `'lt` for the eq check to be correct.
/// The borrow checker is checking that the lifetimes of the type
/// IDs are the same instead of doing it at runtime, which we can't do.
_marker: PhantomData<fn(&'lt ()) -> &'lt ()>,
/// The type ID of the name type of the type.
name_id: core::any::TypeId,
name: &'static str,
}
impl<'lt> LtTypeId<'lt> {
/// Get the ID of a type.
///
/// The type must implement [`TypeNameable`]. Note, the `'a` lifetime is **not**
/// tracked by the [`LtTypeId`], only the `'lt` lifetime is.
pub fn of<T: ?Sized + TypeName::Member<'lt>>() -> Self {
LtTypeId {
_marker: PhantomData,
name_id: core::any::TypeId::of::<TypeName::HigherRanked<'lt, T>>(),
name: core::any::type_name::<T>(),
}
}
}
impl<'lt> core::fmt::Display for LtTypeId<'lt> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(self.name, f)
}
}
/// [`Any`][core::any::Any] with a lifetime generic `'lt`.
///
/// This trait is implemented on all types that implement
/// [`TypeNameable`]. It is not possible to implement this trait manually.
///
/// Like [`Any`][core::any::Any] this trait can be used as a trait object with
/// downcasting.
pub trait LtAny<'lt>: sealed::Sealed<'lt> {
/// Get the [`LtTypeId`] of the type of `self`.
fn type_id(&self) -> LtTypeId<'lt>;
}
// Prevent any impls except the following.
mod sealed {
use super::*;
pub trait Sealed<'lt> {}
impl<'lt, T: ?Sized + TypeName::Member<'lt>> Sealed<'lt> for T {}
}
impl<'lt, T: ?Sized + TypeName::Member<'lt>> LtAny<'lt> for T {
fn type_id(&self) -> LtTypeId<'lt> {
LtTypeId::of::<T>()
}
}
impl<'a, 'lt> dyn LtAny<'lt> + 'a {
/// Check if `self` is of type `T`.
pub fn is<T: ?Sized + TypeName::Member<'lt>>(&self) -> bool {
LtTypeId::of::<T>() == self.type_id()
}
/// Downcast a `&dyn LtAny<'lt>` into a `&T`.
pub fn downcast_ref<T: TypeName::Member<'lt>>(&self) -> Option<&T> {
if self.is::<T>() {
Some(unsafe { &*(self as *const dyn LtAny<'lt> as *const T) })
} else {
None
}
}
/// Downcast a `&mut dyn LtAny<'lt>` into a `&mut T`.
pub fn downcast_mut<T: TypeName::Member<'lt>>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
Some(unsafe { &mut *(self as *mut dyn LtAny<'lt> as *mut T) })
} else {
None
}
}
/// Downcast a `Box<dyn LtAny<'lt>>` into a `Box<T>`.
#[cfg(feature = "alloc")]
pub fn downcast_box<T: TypeName::Member<'lt>>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if self.is::<T>() {
Ok(unsafe {
let raw: *mut dyn LtAny<'lt> = Box::into_raw(self);
Box::from_raw(raw as *mut T)
})
} else {
Err(self)
}
}
}
/// Dynamic trait lookup.
///
/// This trait allows looking up the trait object form of `self` for a
/// given trait object `id`. This is similar to upcasting to the trait given
/// by `id` if [`AnyTrait`] had every trait as a super bound.
///
/// ```
/// use treaty::any::{AnyTrait, any_trait, nameable};
///
/// // Create a test value.
/// let my_num = MyNum(42);
///
/// // Cast to be a AnyTrait trait object.
/// // Now we don't know the type.
/// let anything: &dyn AnyTrait<'_> = &my_num;
///
/// // We can still upcast to an impl of ToNum.
/// let to_num_object: &dyn ToNum = anything.upcast().unwrap();
///
/// assert_eq!(to_num_object.num(), 42);
///
/// // === Type Setup ===
///
/// // An example trait.
/// trait ToNum {
/// fn num(&self) -> i32;
/// }
///
/// // Make the trait object nameable.
/// nameable! {
/// struct Name['a, 'ctx];
/// impl for dyn ToNum + 'a where { }
/// }
///
/// // An example struct.
/// struct MyNum(i32);
///
/// // The example struct impls the example trait.
/// impl ToNum for MyNum {
/// fn num(&self) -> i32 {
/// self.0
/// }
/// }
///
/// // Allow the example struct's trait impls to be looked up at runtime.
/// // Here the only trait that can be looked up is ToNum as its the only
/// // one in the list.
/// any_trait! {
/// impl['a, 'ctx] MyNum = [dyn ToNum + 'a];
/// }
/// ```
pub trait AnyTrait<'lt> {
/// Upcast a borrow to the given trait object.
///
/// Use the `<dyn AnyTrait>::upcast()` helper method instead, if possible.
///
/// If `self` doesn't support upcasting to the requested type
/// then `None` is returned. The returned trait object is type erased so this trait
/// is object safe.
fn upcast_to_id<'a>(&'a self, id: LtTypeId<'lt>) -> Option<IndirectLtAny<'a, 'lt, Ref>>
where
'lt: 'a;
/// Upcast a mutable borrow to the given trait object.
///
/// Use the `<dyn AnyTrait>::upcast_mut()` helper method instead, if possible.
///
/// If `self` doesn't support upcasting to the requested type
/// then `None` is returned. The returned trait object is type erased so this trait
/// is object safe.
fn upcast_to_id_mut<'a>(&'a mut self, id: LtTypeId<'lt>) -> Option<IndirectLtAny<'a, 'lt, Mut>>
where
'lt: 'a;
}
impl<'lt> dyn AnyTrait<'lt> + Send + '_ {
/// Upcast a borrow to the given trait object type.
///
/// This should be used instead of [`upcast_to_id`][AnyTrait::upcast_to_id]
/// as it automatically downcasts the returned [`IndirectLtAny`].
///
/// If the returned [`IndirectLtAny`] is the wrong type, then a panic happens.
pub fn upcast<'a, Trait: ?Sized + TypeName::Member<'lt>>(
&'a self,
) -> Option<&'a MaybeSized::T<'a, 'lt, Trait>> {
self.upcast_to_id(LtTypeId::of::<Trait>())
.map(|object| match object.downcast::<Trait>() {
Ok(object) => object,
Err(object) => panic!(
"Unexpected trait object. This means a bad impl of \
`upcast_to_id`. Expected: {:?}, Got {:?}",
LtTypeId::of::<Trait>(),
object.id()
),
})
}
/// Upcast a mutable borrow to the given trait object type.
///
/// This should be used instead of [`upcast_to_id_mut`][AnyTrait::upcast_to_id]
/// as it automatically downcasts the returned [`IndirectLtAny`].
///
/// If the returned [`IndirectLtAny`] is the wrong type, then a panic happens.
pub fn upcast_mut<'a, Trait: ?Sized + TypeName::Member<'lt>>(
&'a mut self,
) -> Option<&'a mut MaybeSized::T<'a, 'lt, Trait>> {
self.upcast_to_id_mut(LtTypeId::of::<Trait>())
.map(|object| match object.downcast::<Trait>() {
Ok(object) => object,
Err(object) => panic!(
"Unexpected trait object. This means a bad impl of \
`upcast_to_id_mut`. Expected: {:?}, Got {:?}",
LtTypeId::of::<Trait>(),
object.id()
),
})
}
}
/// Implement [`AnyTrait`] for a type.
///
/// This allows looking up trait objects from the provided list.
/// See [`AnyTrait`] for an example.
#[doc(hidden)]
#[macro_export]
macro_rules! any_trait {
{
impl[$a:lifetime, $lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?] $(else $fallback:path)? $(where $($bound:tt)*)?
} => {
impl<$lt $($generic)*> $crate::any::AnyTrait<$lt> for $name
$(where $($bound)*)?
{
#[inline]
fn upcast_to_id<$a>(
&$a self,
id: $crate::any::LtTypeId<$lt>
) -> ::core::option::Option<$crate::any::IndirectLtAny<$a, $lt, $crate::any::Ref>>
where
$lt: $a
{
match id {
$(id if id == $crate::any::LtTypeId::of::<$protocol>()
=> ::core::option::Option::Some($crate::any::IndirectLtAny::<$a, $lt, _>::new::<$protocol>(self as _)),)*
_ => {
$($fallback(id);)?
::core::option::Option::None
}
}
}
#[inline]
fn upcast_to_id_mut<$a>(
&$a mut self,
id: $crate::any::LtTypeId<$lt>
) -> ::core::option::Option<$crate::any::IndirectLtAny<$a, $lt, $crate::any::Mut>>
where
$lt: $a
{
match id {
$(id if id == $crate::any::LtTypeId::of::<$protocol>()
=> ::core::option::Option::Some($crate::any::IndirectLtAny::<$a, $lt, _>::new::<$protocol>(self as _)),)*
_ => {
$($fallback(id);)?
::core::option::Option::None
}
}
}
}
};
}
#[doc(inline)]
pub use any_trait;
/// A type erased pointer like.
///
/// This acts like a `&dyn LtAny` except it is able to type erase another fat pointer.
/// This allows type erasing pointers to trait objects. A [`IndirectLtAny`] cannot
/// store an instance of itself.
///
/// The `I` generic is the flavor if pointer being used. It can be [`Ref`], [`Mut`], [`Boxed`], or
/// a custom pointer type.
#[must_use]
pub struct IndirectLtAny<'a, 'lt: 'a, I: Indirect<'a>> {
info: fn() -> (LtTypeId<'lt>, unsafe fn(RawIndirect)),
indirect: RawIndirect,
_marker: PhantomData<(I::ForT<fn(&'lt ()) -> &'lt ()>, PhantomPinned, *const ())>,
}
impl<'a, 'lt, I: Indirect<'a>> Drop for IndirectLtAny<'a, 'lt, I> {
fn drop(&mut self) {
// We need to drop the stored value.
// Lookup drop function.
let (_, drop_fn) = (self.info)();
// SAFETY: self.indirect is never touched again.
// Additionally, we know that drop_fn is for this self.indirect because it was
// made by Self::new.
unsafe { drop_fn(self.indirect) };
}
}
impl<'a, 'lt, I: Indirect<'a>> IndirectLtAny<'a, 'lt, I> {
/// Wrap an indirection.
///
/// The inner type `T` of the indirection is erased.
pub fn new<T: ?Sized + TypeName::Member<'lt>>(
indirect: I::ForT<MaybeSized::T<'a, 'lt, T>>,
) -> Self {
Self {
info: || {
(LtTypeId::of::<T>(), |raw| {
// SAFETY: This is only called in the drop impl.
unsafe { drop(I::from_raw::<MaybeSized::T<'a, 'lt, T>>(raw)) }
})
},
indirect: I::into_raw(indirect),
_marker: PhantomData,
}
}
/// Downcast to an indirection with a given `T` type.
///
/// If the type of the stored value is different, then `self` is
/// returned as is.
pub fn downcast<T: ?Sized + TypeName::Member<'lt>>(
self,
) -> Result<I::ForT<MaybeSized::T<'a, 'lt, T>>, Self> {
let (id, _) = (self.info)();
if id == LtTypeId::of::<T>() {
Ok(unsafe { I::from_raw::<MaybeSized::T<'a, 'lt, T>>(self.indirect) })
} else {
Err(self)
}
}
/// Type ID of the stored value's `T`.
pub fn id(&self) -> LtTypeId<'lt> {
(self.info)().0
}
}
/// A pointer like type.
///
/// For this trait the pointer like type must have the same size as a pointer.
pub unsafe trait Indirect<'a> {
/// Get the full type for a given `T`.
type ForT<T: ?Sized + 'a>: 'a;
/// Convert the pointer into a raw indirection.
fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> RawIndirect;
/// Convert a raw indirection back into the pointer.
unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Self::ForT<T>;
}
/// An opaque set of bytes the size of a fat pointer.
///
/// Repr wise this is exactly `MaybeUninit<[u8; { size of a fat pointer }]>`.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct RawIndirect(MaybeUninit<[u8; INDIRECT_SIZE]>);
const INDIRECT_SIZE: usize = core::mem::size_of::<usize>() * 2;
trait Helper {}
/// Marker type for [`IndirectLtAny`] for a borrow indirection (`&T`).
pub enum Ref {}
const _: () = assert!(core::mem::size_of::<&dyn Helper>() <= core::mem::size_of::<RawIndirect>());
unsafe impl<'a> Indirect<'a> for Ref {
type ForT<T: ?Sized + 'a> = &'a T;
fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> RawIndirect {
unsafe { transmute::<&'a T, RawIndirect>(value) }
}
unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Self::ForT<T> {
unsafe { transmute::<RawIndirect, &'a T>(any) }
}
}
/// Marker type for [`IndirectLtAny`] for a mutable borrow indirection (`&mut T`).
pub enum Mut {}
const _: () =
assert!(core::mem::size_of::<&mut dyn Helper>() <= core::mem::size_of::<RawIndirect>());
unsafe impl<'a> Indirect<'a> for Mut {
type ForT<T: ?Sized + 'a> = &'a mut T;
fn into_raw<T: ?Sized + 'a>(value: Self::ForT<T>) -> RawIndirect {
unsafe { transmute::<&'a mut T, RawIndirect>(value) }
}
unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Self::ForT<T> {
unsafe { transmute::<RawIndirect, &'a mut T>(any) }
}
}
#[cfg(feature = "alloc")]
pub use boxed::*;
#[cfg(feature = "alloc")]
mod boxed {
use super::*;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
/// Marker type for [`IndirectLtAny`] for a box indirection (`Box<T>`).
pub enum Boxed {}
const _: () =
assert!(core::mem::size_of::<Box<dyn Helper>>() <= core::mem::size_of::<RawIndirect>());
unsafe impl<'a> Indirect<'a> for Boxed {
type ForT<T: ?Sized + 'a> = Box<T>;
fn into_raw<T: ?Sized + 'a>(value: Box<T>) -> RawIndirect {
unsafe { transmute::<Box<T>, RawIndirect>(value) }
}
unsafe fn from_raw<T: ?Sized + 'a>(any: RawIndirect) -> Box<T> {
unsafe { transmute::<RawIndirect, Box<T>>(any) }
}
}
}
/// # Safety
/// Same rules as [`core::mem::transmute()`].
unsafe fn transmute<T, U>(value: T) -> U {
// Create union type that can store a `T` or a `U`.
// We can then use this to convert between them.
//
// The repr(C) layout forces no offset between `t` and `u` as talked about here
// https://rust-lang.github.io/unsafe-code-guidelines/layout/unions.html#c-compatible-layout-repr-c
#[repr(C)]
union Transmute<T, U> {
t: ManuallyDrop<T>,
u: ManuallyDrop<U>,
}
// Create the union in the `T` state.
let value = Transmute {
t: ManuallyDrop::new(value),
};
// Read from the union in the `U` state.
// SAFETY: This is safe because the caller has promised that `T` can be transmuted to `U`.
// The following reference link talks about repr(C) unions being used this way.
// https://doc.rust-lang.org/reference/items/unions.html#reading-and-writing-union-fields
ManuallyDrop::into_inner(unsafe { value.u })
}
#[cfg(test)]
mod test {
use crate::bijective_higher_ranked_type;
use super::*;
#[test]
fn implementer_macro() {
trait Z<'ctx> {
fn get(&self) -> i32;
}
bijective_higher_ranked_type! {
type DynZ['ctx][]: (MaybeSized)['ctx][] = for<'a> dyn Z<'ctx> + 'a
}
bijective_higher_ranked_type! {
type [][]: (TypeName)[][] = for<'lt> DynZ<'lt>
}
struct X<'ctx>(&'ctx i32);
impl<'ctx> Z<'ctx> for X<'ctx> {
fn get(&self) -> i32 {
*self.0
}
}
any_trait! {
impl['a, 'ctx] X<'ctx> = [
DynZ<'ctx>
]
}
let z = 42;
let x = X(&z);
let y = (&x as &(dyn AnyTrait<'_> + Send))
.upcast::<DynZ<'_>>()
.unwrap();
assert_eq!(y.get(), 42);
}
}