//! Extended type erasure support.
//!
//! The `AnyTrait` trait provides dynamic upcasting to trait objects.
mod erased;
mod mut_any_unsized;
mod ref_any_unsized;
mod static_wrapper;
pub mod type_name;
mod type_name_id;
use crate::hkt::Marker;
pub use mut_any_unsized::*;
pub use ref_any_unsized::*;
pub use static_wrapper::*;
pub use type_name_id::*;
pub trait AnyTrait<'lt> {
fn upcast_by_id(
&self,
id: WithLtTypeId<'lt>,
) -> Option<RefAnyUnsized<'_, 'lt>> {
let _id = id;
None
}
fn upcast_by_id_mut(
&mut self,
id: WithLtTypeId<'lt>,
) -> Option<MutAnyUnsized<'_, 'lt>> {
let _id = id;
None
}
}
impl<'u, 'lt: 'u> dyn AnyTrait<'lt> + 'u {
#[track_caller]
pub fn upcast<'r, T: ?Sized + type_name::WithLt<'r, 'lt>>(&'r self) -> Option<&'r T> {
self.upcast_by_id(WithLtTypeId::of::<T>())
.map(|value| match value.downcast::<T>() {
Ok(value) => value,
Err(_) => panic!("wrong type returned by upcast_by_id"),
})
}
#[track_caller]
pub fn upcast_mut<'r, T: ?Sized + type_name::WithLt<'r, 'lt>>(
&'r mut self,
) -> Option<&'r mut T> {
self.upcast_by_id_mut(WithLtTypeId::of::<T>())
.map(|value| match value.downcast::<T>() {
Ok(value) => value,
Err(_) => panic!("wrong type returned by upcast_by_id_mut"),
})
}
}
const _: () = {
pub struct Ref<T: ?Sized>(Marker<T>);
impl<'lt, 'ctx, T: ?Sized> type_name::Lower<'lt, 'ctx, &'lt &'ctx ()> for Ref<T>
where
T: type_name::Lower<'lt, 'ctx, &'lt &'ctx ()>,
{
type Lowered = &'lt type_name::Lowered<'lt, 'ctx, T>;
}
impl<'lt, 'ctx, T: ?Sized> type_name::Raise<'lt, 'ctx, &'lt &'ctx ()> for &'lt T
where
T: type_name::Raise<'lt, 'ctx, &'lt &'ctx ()>,
{
type Raised = Ref<type_name::Raised<'lt, 'ctx, T>>;
}
};
const _: () = {
pub struct Mut<T: ?Sized>(Marker<T>);
impl<'lt, 'ctx, T: ?Sized> type_name::Lower<'lt, 'ctx, &'lt &'ctx ()> for Mut<T>
where
T: type_name::Lower<'lt, 'ctx, &'lt &'ctx ()>,
{
type Lowered = &'lt mut type_name::Lowered<'lt, 'ctx, T>;
}
impl<'lt, 'ctx, T: ?Sized> type_name::Raise<'lt, 'ctx, &'lt &'ctx ()> for &'lt mut T
where
T: type_name::Raise<'lt, 'ctx, &'lt &'ctx ()>,
{
type Raised = Mut<type_name::Raised<'lt, 'ctx, T>>;
}
};
#[doc(hidden)]
#[macro_export]
macro_rules! trait_by_id {
{
&
$this:ident,
$id:ident,
{
type Impls = ($($trait:ty),* $(,)?);
}
} => {{
match $id {
$(
$id if $id == $crate::any::WithLtTypeId::of::<$trait>() => {
return Some($crate::any::RefAnyUnsized::new($this as &$trait))
}
)*
_ => {}
}
}};
{
&mut
$this:ident,
$id:ident,
{
type Impls = ($($trait:ty),* $(,)?);
}
} => {{
match $id {
$(
$id if {
eprintln!("a: {:?}\nb: {:?}", &$id, $crate::any::WithLtTypeId::of::<$trait>());
$id == $crate::any::WithLtTypeId::of::<$trait>()
}=> {
return Some($crate::any::MutAnyUnsized::new($this as &mut $trait))
}
)*
_ => {}
}
}};
}
#[doc(inline)]
pub use trait_by_id;