#![deny(unsafe_code)]
use alloc::{boxed::Box, rc::Rc, sync::Arc};
use core::any::Any;
pub trait Downcast: Any {
fn into_any(self: Box<Self>) -> Box<dyn Any>;
fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T: Any> Downcast for T {
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
pub trait DowncastSync: Downcast + Send + Sync {
fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
}
impl<T: Any + Send + Sync> DowncastSync for T {
fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self
}
}
#[macro_export(local_inner_macros)]
macro_rules! impl_downcast {
(@impl_full
$trait_:ident [$($param_types:tt)*]
for [$($forall_types:ident),*]
where [$($preds:tt)*]
) => {
impl_downcast! {
@inject_where
[impl<$($forall_types),*> $trait_<$($param_types)*>]
types [$($forall_types),*]
where [$($preds)*]
[{
impl_downcast! { @impl_body $trait_ [$($param_types)*] }
}]
}
};
(@impl_full_sync
$trait_:ident [$($param_types:tt)*]
for [$($forall_types:ident),*]
where [$($preds:tt)*]
) => {
impl_downcast! {
@inject_where
[impl<$($forall_types),*> $trait_<$($param_types)*>]
types [$($forall_types),*]
where [$($preds)*]
[{
impl_downcast! { @impl_body $trait_ [$($param_types)*] }
impl_downcast! { @impl_body_sync $trait_ [$($param_types)*] }
}]
}
};
(@impl_body $trait_:ident [$($types:tt)*]) => {
#[inline]
pub fn is<__T: $trait_<$($types)*>>(&self) -> bool {
$crate::downcast::Downcast::as_any(self).is::<__T>()
}
#[inline]
pub fn downcast<__T: $trait_<$($types)*>>(
self: $crate::alloc_reexport::boxed::Box<Self>
) -> Result<$crate::alloc_reexport::boxed::Box<__T>, $crate::alloc_reexport::boxed::Box<Self>> {
if self.is::<__T>() {
Ok($crate::downcast::Downcast::into_any(self).downcast::<__T>().unwrap())
} else {
Err(self)
}
}
#[inline]
pub fn downcast_rc<__T: $trait_<$($types)*>>(
self: $crate::alloc_reexport::rc::Rc<Self>
) -> Result<$crate::alloc_reexport::rc::Rc<__T>, $crate::alloc_reexport::rc::Rc<Self>> {
if self.is::<__T>() {
Ok($crate::downcast::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
} else {
Err(self)
}
}
#[inline]
pub fn downcast_ref<__T: $trait_<$($types)*>>(&self) -> Option<&__T> {
$crate::downcast::Downcast::as_any(self).downcast_ref::<__T>()
}
#[inline]
pub fn downcast_mut<__T: $trait_<$($types)*>>(&mut self) -> Option<&mut __T> {
$crate::downcast::Downcast::as_any_mut(self).downcast_mut::<__T>()
}
};
(@impl_body_sync $trait_:ident [$($types:tt)*]) => {
#[inline]
pub fn downcast_arc<__T: $trait_<$($types)*>>(
self: $crate::alloc_reexport::sync::Arc<Self>,
) -> Result<$crate::alloc_reexport::sync::Arc<__T>, $crate::alloc_reexport::sync::Arc<Self>>
where __T: core::any::Any + Send + Sync
{
if self.is::<__T>() {
Ok($crate::downcast::DowncastSync::into_any_arc(self).downcast::<__T>().unwrap())
} else {
Err(self)
}
}
};
(@inject_where [$($before:tt)*] types [] where [] [$($after:tt)*]) => {
impl_downcast! { @as_item $($before)* $($after)* }
};
(@inject_where [$($before:tt)*] types [$($types:ident),*] where [] [$($after:tt)*]) => {
impl_downcast! {
@as_item
$($before)*
where $( $types: core::any::Any + 'static ),*
$($after)*
}
};
(@inject_where [$($before:tt)*] types [$($types:ident),*] where [$($preds:tt)+] [$($after:tt)*]) => {
impl_downcast! {
@as_item
$($before)*
where
$( $types: core::any::Any + 'static, )*
$($preds)*
$($after)*
}
};
(@as_item $i:item) => { $i };
($trait_:ident ) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } };
($trait_:ident <>) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } };
(sync $trait_:ident ) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } };
(sync $trait_:ident <>) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } };
($trait_:ident < $($types:ident),* >) => {
impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [] }
};
(sync $trait_:ident < $($types:ident),* >) => {
impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [] }
};
($trait_:ident < $($types:ident),* > where $($preds:tt)+) => {
impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [$($preds)*] }
};
(sync $trait_:ident < $($types:ident),* > where $($preds:tt)+) => {
impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [$($preds)*] }
};
($trait_:ident assoc $($atypes:ident),*) => {
impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] }
};
(sync $trait_:ident assoc $($atypes:ident),*) => {
impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] }
};
($trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => {
impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] }
};
(sync $trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => {
impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] }
};
($trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => {
impl_downcast! {
@impl_full
$trait_ [$($types),*, $($atypes = $atypes),*]
for [$($types),*, $($atypes),*]
where []
}
};
(sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => {
impl_downcast! {
@impl_full_sync
$trait_ [$($types),*, $($atypes = $atypes),*]
for [$($types),*, $($atypes),*]
where []
}
};
($trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => {
impl_downcast! {
@impl_full
$trait_ [$($types),*, $($atypes = $atypes),*]
for [$($types),*, $($atypes),*]
where [$($preds)*]
}
};
(sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => {
impl_downcast! {
@impl_full_sync
$trait_ [$($types),*, $($atypes = $atypes),*]
for [$($types),*, $($atypes),*]
where [$($preds)*]
}
};
(concrete $trait_:ident < $($types:ident),* >) => {
impl_downcast! { @impl_full $trait_ [$($types),*] for [] where [] }
};
(sync concrete $trait_:ident < $($types:ident),* >) => {
impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [] where [] }
};
(concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => {
impl_downcast! { @impl_full $trait_ [$($atypes = $aty),*] for [] where [] }
};
(sync concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => {
impl_downcast! { @impl_full_sync $trait_ [$($atypes = $aty),*] for [] where [] }
};
(concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => {
impl_downcast! { @impl_full $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] }
};
(sync concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => {
impl_downcast! { @impl_full_sync $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] }
};
}