#![no_std]
#![forbid(unsafe_code)]
#![warn(clippy::all)]
#![deny(rustdoc::broken_intra_doc_links)]
#![cfg_attr(feature = "docs", feature(doc_cfg))]
#![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)]
#![doc(test(
no_crate_inject,
attr(
deny(warnings, rust_2018_idioms),
allow(unused_extern_crates, unused_variables)
)
))]
macro_rules! cfg_with_docs {
($feature:meta, { $(impl Self { $($code:tt)* })* }) => {
$(
#[cfg($feature)]
#[cfg_attr(feature = "docs", doc(cfg($feature)))]
$($code)*
)*
};
($feature:meta, $({$($code:tt)*}),*) => {
$(
#[cfg($feature)]
#[cfg_attr(feature = "docs", doc(cfg($feature)))]
$($code)*
)*
};
}
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, rc::Rc, sync::Arc};
cfg_with_docs!(
feature = "proc-macros",
{
pub use cast_trait_object_macros::dyn_upcast;
},
{
pub use cast_trait_object_macros::dyn_cast;
}
);
pub trait DynCastConfigTargetTest<C: ?Sized> {}
pub trait GetDynCastConfig<T: ?Sized> {
type Config: DynCastConfig<Target = T, Source = Self>;
}
pub trait DynCastConfig {
type Target: ?Sized;
type Source: ?Sized;
}
#[derive(Debug)]
pub struct ConcreteDynCastConfig<S: ?Sized, T: ?Sized> {
_source: core::marker::PhantomData<S>,
_target: core::marker::PhantomData<T>,
}
impl<S: ?Sized, T: ?Sized> DynCastConfig for ConcreteDynCastConfig<S, T> {
type Target = T;
type Source = S;
}
impl<C, T> DynCast<C> for T
where
C: DynCastConfig,
T: DerivedDynCast<ConcreteDynCastConfig<C::Source, C::Target>, C>,
{
fn dyn_cast_ref(&self) -> Result<&C::Target, &C::Source> {
<T as DerivedDynCast<ConcreteDynCastConfig<C::Source, C::Target>, C>>::derived_dyn_cast_ref(
self,
)
}
fn dyn_cast_mut(&mut self) -> Result<&mut C::Target, &mut C::Source> {
<T as DerivedDynCast<ConcreteDynCastConfig<C::Source, C::Target>, C>>::derived_dyn_cast_mut(
self,
)
}
#[cfg(feature = "alloc")]
fn dyn_cast_boxed(self: Box<Self>) -> Result<Box<C::Target>, Box<C::Source>> {
<T as DerivedDynCast<ConcreteDynCastConfig<C::Source, C::Target>, C>>::derived_dyn_cast_boxed(self)
}
#[cfg(feature = "alloc")]
fn dyn_cast_rc(self: Rc<Self>) -> Result<Rc<C::Target>, Rc<C::Source>> {
<T as DerivedDynCast<ConcreteDynCastConfig<C::Source, C::Target>, C>>::derived_dyn_cast_rc(
self,
)
}
#[cfg(feature = "alloc")]
fn dyn_cast_arc(self: Arc<Self>) -> Result<Arc<C::Target>, Arc<C::Source>> {
<T as DerivedDynCast<ConcreteDynCastConfig<C::Source, C::Target>, C>>::derived_dyn_cast_arc(
self,
)
}
}
mod private {
pub trait Sealed {}
impl<S: ?Sized, T: ?Sized> Sealed for super::ConcreteDynCastConfig<S, T> {}
}
pub trait DerivedDynCast<T: DynCastConfig + private::Sealed, C: DynCastConfig> {
fn derived_dyn_cast_ref(&self) -> Result<&T::Target, &T::Source>;
fn derived_dyn_cast_mut(&mut self) -> Result<&mut T::Target, &mut T::Source>;
cfg_with_docs!(feature = "alloc", {
impl Self {
fn derived_dyn_cast_boxed(self: Box<Self>) -> Result<Box<T::Target>, Box<T::Source>>;
}
impl Self {
fn derived_dyn_cast_rc(self: Rc<Self>) -> Result<Rc<T::Target>, Rc<T::Source>>;
}
impl Self {
fn derived_dyn_cast_arc(self: Arc<Self>) -> Result<Arc<T::Target>, Arc<T::Source>>;
}
});
}
pub trait DynCast<T: DynCastConfig> {
fn dyn_cast_ref(&self) -> Result<&T::Target, &T::Source>;
fn dyn_cast_mut(&mut self) -> Result<&mut T::Target, &mut T::Source>;
cfg_with_docs!(feature = "alloc", {
impl Self {
fn dyn_cast_boxed(self: Box<Self>) -> Result<Box<T::Target>, Box<T::Source>>;
}
impl Self {
fn dyn_cast_rc(self: Rc<Self>) -> Result<Rc<T::Target>, Rc<T::Source>>;
}
impl Self {
fn dyn_cast_arc(self: Arc<Self>) -> Result<Arc<T::Target>, Arc<T::Source>>;
}
});
}
type GetConfig<F, T> = <F as GetDynCastConfig<T>>::Config;
type GetSource<A, T> = <A as DynCastExtHelper<T>>::Source;
type GetTarget<A, T> = <A as DynCastExtHelper<T>>::Target;
pub trait DynCastExt {
fn dyn_cast<T: ?Sized>(self) -> Result<Self::Target, Self::Source>
where
Self: DynCastExtHelper<T>;
fn dyn_upcast<T: ?Sized>(self) -> Self::Target
where
Self: DynCastExtAdvHelper<T, T, Source = GetAdvTarget<Self, T, T>>;
fn dyn_cast_adv<F: ?Sized, T: ?Sized>(self) -> Result<Self::Target, Self::Source>
where
Self: DynCastExtAdvHelper<F, T>;
fn dyn_cast_with_config<C: DynCastConfig>(self) -> Result<Self::Target, Self::Source>
where
Self: DynCastExtAdvHelper<C::Source, C::Target>;
}
impl<A> DynCastExt for A {
fn dyn_cast<T: ?Sized>(self) -> Result<GetTarget<Self, T>, GetSource<Self, T>>
where
Self: DynCastExtHelper<T>,
{
self._dyn_cast()
}
fn dyn_upcast<T: ?Sized>(self) -> GetAdvTarget<Self, T, T>
where
Self: DynCastExtAdvHelper<T, T, Source = GetAdvTarget<Self, T, T>>,
{
match self._dyn_cast() {
Ok(v) => v,
Err(e) => e,
}
}
fn dyn_cast_adv<F: ?Sized, T: ?Sized>(self) -> GetAdvCastResult<Self, F, T>
where
Self: DynCastExtAdvHelper<F, T>,
{
self._dyn_cast()
}
fn dyn_cast_with_config<C: DynCastConfig>(self) -> GetAdvCastResult<Self, C::Source, C::Target>
where
Self: DynCastExtAdvHelper<C::Source, C::Target>,
{
self._dyn_cast()
}
}
pub trait DynCastExtHelper<T: ?Sized> {
type Target;
type Source;
type Config;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source>;
}
impl<'a, T, F> DynCastExtHelper<T> for &'a F
where
T: ?Sized + 'static,
F: ?Sized + 'static + DynCast<GetConfig<F, T>> + GetDynCastConfig<T>,
{
type Target = &'a T;
type Source = &'a F;
type Config = GetConfig<F, T>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_ref(self)
}
}
impl<'a, T, F> DynCastExtHelper<T> for &'a mut F
where
T: ?Sized + 'static,
F: ?Sized + 'static + DynCast<GetConfig<F, T>> + GetDynCastConfig<T>,
{
type Target = &'a mut T;
type Source = &'a mut F;
type Config = GetConfig<F, T>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_mut(self)
}
}
cfg_with_docs!(
feature = "alloc",
{
impl<T, F> DynCastExtHelper<T> for Box<F>
where
T: ?Sized + 'static,
F: ?Sized + 'static + DynCast<GetConfig<F, T>> + GetDynCastConfig<T>,
{
type Target = Box<T>;
type Source = Box<F>;
type Config = GetConfig<F, T>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_boxed(self)
}
}
},
{
impl<T, F> DynCastExtHelper<T> for Rc<F>
where
T: ?Sized + 'static,
F: ?Sized + 'static + DynCast<GetConfig<F, T>> + GetDynCastConfig<T>,
{
type Target = Rc<T>;
type Source = Rc<F>;
type Config = GetConfig<F, T>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_rc(self)
}
}
},
{
impl<T, F> DynCastExtHelper<T> for Arc<F>
where
T: ?Sized + 'static,
F: ?Sized + 'static + DynCast<GetConfig<F, T>> + GetDynCastConfig<T>,
{
type Target = Arc<T>;
type Source = Arc<F>;
type Config = GetConfig<F, T>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_arc(self)
}
}
}
);
type GetAdvSource<A, F, T> = <A as DynCastExtAdvHelper<F, T>>::Source;
type GetAdvTarget<A, F, T> = <A as DynCastExtAdvHelper<F, T>>::Target;
type GetAdvCastResult<A, F, T> = Result<GetAdvTarget<A, F, T>, GetAdvSource<A, F, T>>;
pub trait DynCastExtAdvHelper<F: ?Sized, T: ?Sized> {
type Target;
type Source;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source>;
}
impl<'a, T, F, A> DynCastExtAdvHelper<F, T> for &'a A
where
T: ?Sized + 'static,
F: ?Sized + 'static + GetDynCastConfig<T>,
A: ?Sized + 'static + DynCast<GetConfig<F, T>>,
{
type Target = &'a T;
type Source = &'a F;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_ref(self)
}
}
impl<'a, T, F, A> DynCastExtAdvHelper<F, T> for &'a mut A
where
T: ?Sized + 'static,
F: ?Sized + 'static + GetDynCastConfig<T>,
A: ?Sized + 'static + DynCast<GetConfig<F, T>>,
{
type Target = &'a mut T;
type Source = &'a mut F;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_mut(self)
}
}
cfg_with_docs!(
feature = "alloc",
{
impl<T, F, A> DynCastExtAdvHelper<F, T> for Box<A>
where
T: ?Sized + 'static,
F: ?Sized + 'static + GetDynCastConfig<T>,
A: ?Sized + 'static + DynCast<GetConfig<F, T>>,
{
type Target = Box<T>;
type Source = Box<F>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_boxed(self)
}
}
},
{
impl<T, F, A> DynCastExtAdvHelper<F, T> for Rc<A>
where
T: ?Sized + 'static,
F: ?Sized + 'static + GetDynCastConfig<T>,
A: ?Sized + 'static + DynCast<GetConfig<F, T>>,
{
type Target = Rc<T>;
type Source = Rc<F>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_rc(self)
}
}
},
{
impl<T, F, A> DynCastExtAdvHelper<F, T> for Arc<A>
where
T: ?Sized + 'static,
F: ?Sized + 'static + GetDynCastConfig<T>,
A: ?Sized + 'static + DynCast<GetConfig<F, T>>,
{
type Target = Arc<T>;
type Source = Arc<F>;
fn _dyn_cast(self) -> Result<Self::Target, Self::Source> {
DynCast::dyn_cast_arc(self)
}
}
}
);
#[allow(non_camel_case_types, missing_debug_implementations)]
#[doc(hidden)]
pub struct __impl_dyn_cast_wrapper<D, C, T>
where
C: ?::core::marker::Sized,
{
_deref_id: [D; 0],
config_type: ::core::marker::PhantomData<C>,
self_type: ::core::marker::PhantomData<T>,
}
#[doc(hidden)]
#[allow(missing_docs)]
impl __impl_dyn_cast_wrapper<(), (), ()> {
#[allow(clippy::new_ret_no_self)]
pub fn new<C, T>() -> __impl_dyn_cast_wrapper<[(); 0], C, T> {
__impl_dyn_cast_wrapper {
_deref_id: [],
config_type: ::core::marker::PhantomData,
self_type: ::core::marker::PhantomData,
}
}
}
#[doc(hidden)]
#[allow(missing_docs)]
impl<__ConfigType, __SelfType> __impl_dyn_cast_wrapper<[(); 0], __ConfigType, __SelfType>
where
__ConfigType: DynCastConfigTargetTest<__SelfType> + ?::core::marker::Sized,
{
pub fn __dyn_cast_macro_deref_specialization<T, U, E, F: FnOnce(T) -> U>(
&self,
value: T,
f: F,
) -> Result<U, E> {
Ok(f(value))
}
}
#[doc(hidden)]
impl<C, T> ::core::ops::Deref for __impl_dyn_cast_wrapper<[(); 0], C, T> {
type Target = __impl_dyn_cast_wrapper<[(); 1], C, T>;
fn deref(&self) -> &Self::Target {
&__impl_dyn_cast_wrapper {
_deref_id: [],
config_type: ::core::marker::PhantomData,
self_type: ::core::marker::PhantomData,
}
}
}
#[doc(hidden)]
#[allow(missing_docs)]
impl<C, __SelfType> __impl_dyn_cast_wrapper<[(); 1], C, __SelfType>
where
C: ?::core::marker::Sized,
{
pub fn __dyn_cast_macro_deref_specialization<T, U, E, F: FnOnce(T) -> E>(
&self,
value: T,
f: F,
) -> Result<U, E> {
Err(f(value))
}
}
#[cfg(not(feature = "alloc"))]
#[macro_export]
macro_rules! impl_dyn_cast {
(
// Declare generic lifetimes and type parameters
for<$($lifetime:lifetime),* $($generics:ident),* $(,)?>
// Path to self type:
$self_type:ty
as
// Path to the source trait we are casting from:
$source_trait:path
// Where clause:
$(where { $($where:tt)* })?
=>
$target_trait:path
) => {
const _: () = {
impl< $($lifetime,)* $($generics,)* >
$crate::DerivedDynCast<
$crate::ConcreteDynCastConfig<
dyn $source_trait,
dyn $target_trait
>,
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config
>
for
$self_type
$(
where
$($where)*
)?
{
fn derived_dyn_cast_ref(
&self,
) -> ::core::result::Result<
&(dyn $target_trait + 'static),
&(dyn $source_trait + 'static),
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&dyn $target_trait,
&dyn $source_trait,
_,
>(self, |v| v)
}
fn derived_dyn_cast_mut(
&mut self,
) -> ::core::result::Result<
&mut (dyn $target_trait + 'static),
&mut (dyn $source_trait + 'static),
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&mut dyn $target_trait,
&mut dyn $source_trait,
_,
>(self, |v| v)
}
}
};
};
(
for<$($lifetime:lifetime),* $($generics:ident),* $(,)?>
$self_type:ty
$(where { $($where:tt)* })?
=>
$config_type:ty
) => {
const _: () = {
impl< $($lifetime,)* $($generics,)* >
$crate::DynCast< $config_type >
for
$self_type
$(
where
$($where)*
)?
{
fn dyn_cast_ref(
&self,
) -> ::core::result::Result<
&<$config_type as $crate::DynCastConfig>::Target,
&<$config_type as $crate::DynCastConfig>::Source,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&<$config_type as $crate::DynCastConfig>::Target,
&<$config_type as $crate::DynCastConfig>::Source,
_,
>(self, |v| v)
}
fn dyn_cast_mut(
&mut self,
) -> ::core::result::Result<
&mut <$config_type as $crate::DynCastConfig>::Target,
&mut <$config_type as $crate::DynCastConfig>::Source,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&mut <$config_type as $crate::DynCastConfig>::Target,
&mut <$config_type as $crate::DynCastConfig>::Source,
_,
>(self, |v| v)
}
}
};
};
($self_type:ty as $source_trait:path => $($target_trait:path),*) => {
$crate::impl_dyn_cast! {
$self_type => $(<dyn $source_trait + 'static as $crate::GetDynCastConfig<dyn $target_trait + 'static>>::Config),*
}
};
($self_type:ty => $($config_type:ty),*) => {
$(
const _: () = {
type __SelfType = $self_type;
type __ConfigType = $config_type;
$crate::impl_dyn_cast!(for<> __SelfType => __ConfigType);
};
)*
};
}
#[cfg(feature = "alloc")]
#[macro_export]
macro_rules! impl_dyn_cast {
(
// Declare generic lifetimes and type parameters
for<$($lifetime:lifetime),* $($generics:ident),* $(,)?>
// Path to self type:
$self_type:ty
as
// Path to the source trait we are casting from:
$source_trait:path
// Where clause:
$(where { $($where:tt)* })?
=>
$target_trait:path
) => {
const _: () = {
extern crate alloc;
impl< $($lifetime,)* $($generics,)* >
$crate::DerivedDynCast<
$crate::ConcreteDynCastConfig<
dyn $source_trait,
dyn $target_trait
>,
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config
>
for
$self_type
$(
where
$($where)*
)?
{
fn derived_dyn_cast_ref(
&self,
) -> ::core::result::Result<
&(dyn $target_trait + 'static),
&(dyn $source_trait + 'static),
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&dyn $target_trait,
&dyn $source_trait,
_,
>(self, |v| v)
}
fn derived_dyn_cast_mut(
&mut self,
) -> ::core::result::Result<
&mut (dyn $target_trait + 'static),
&mut (dyn $source_trait + 'static),
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&mut dyn $target_trait,
&mut dyn $source_trait,
_,
>(self, |v| v)
}
fn derived_dyn_cast_boxed(
self: alloc::boxed::Box<Self>,
) -> ::core::result::Result<
alloc::boxed::Box<dyn $target_trait>,
alloc::boxed::Box<dyn $source_trait>,
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
alloc::boxed::Box<dyn $target_trait>,
alloc::boxed::Box<dyn $source_trait>,
_,
>(self, |v| v)
}
fn derived_dyn_cast_rc(
self: alloc::rc::Rc<Self>,
) -> ::core::result::Result<
alloc::rc::Rc<dyn $target_trait>,
alloc::rc::Rc<dyn $source_trait>,
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
alloc::rc::Rc<dyn $target_trait>,
alloc::rc::Rc<dyn $source_trait>,
_,
>(self, |v| v)
}
fn derived_dyn_cast_arc(
self: alloc::sync::Arc<Self>,
) -> ::core::result::Result<
alloc::sync::Arc<dyn $target_trait>,
alloc::sync::Arc<dyn $source_trait>,
> {
$crate::__impl_dyn_cast_wrapper::new::<
<dyn $source_trait as $crate::GetDynCastConfig<dyn $target_trait>>::Config,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
alloc::sync::Arc<dyn $target_trait>,
alloc::sync::Arc<dyn $source_trait>,
_,
>(self, |v| v)
}
}
};
};
(
for<$($lifetime:lifetime),* $($generics:ident),* $(,)?>
$self_type:ty
$(where { $($where:tt)* })?
=>
$config_type:ty
) => {
const _: () = {
extern crate alloc;
impl< $($lifetime,)* $($generics,)* >
$crate::DynCast< $config_type >
for
$self_type
$(
where
$($where)*
)?
{
fn dyn_cast_ref(
&self,
) -> ::core::result::Result<
&<$config_type as $crate::DynCastConfig>::Target,
&<$config_type as $crate::DynCastConfig>::Source,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&<$config_type as $crate::DynCastConfig>::Target,
&<$config_type as $crate::DynCastConfig>::Source,
_,
>(self, |v| v)
}
fn dyn_cast_mut(
&mut self,
) -> ::core::result::Result<
&mut <$config_type as $crate::DynCastConfig>::Target,
&mut <$config_type as $crate::DynCastConfig>::Source,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
&mut <$config_type as $crate::DynCastConfig>::Target,
&mut <$config_type as $crate::DynCastConfig>::Source,
_,
>(self, |v| v)
}
fn dyn_cast_boxed(
self: alloc::boxed::Box<Self>,
) -> ::core::result::Result<
alloc::boxed::Box<<$config_type as $crate::DynCastConfig>::Target>,
alloc::boxed::Box<<$config_type as $crate::DynCastConfig>::Source>,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
alloc::boxed::Box<<$config_type as $crate::DynCastConfig>::Target>,
alloc::boxed::Box<<$config_type as $crate::DynCastConfig>::Source>,
_,
>(self, |v| v)
}
fn dyn_cast_rc(
self: alloc::rc::Rc<Self>,
) -> ::core::result::Result<
alloc::rc::Rc<<$config_type as $crate::DynCastConfig>::Target>,
alloc::rc::Rc<<$config_type as $crate::DynCastConfig>::Source>,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
alloc::rc::Rc<<$config_type as $crate::DynCastConfig>::Target>,
alloc::rc::Rc<<$config_type as $crate::DynCastConfig>::Source>,
_,
>(self, |v| v)
}
fn dyn_cast_arc(
self: alloc::sync::Arc<Self>,
) -> ::core::result::Result<
alloc::sync::Arc<<$config_type as $crate::DynCastConfig>::Target>,
alloc::sync::Arc<<$config_type as $crate::DynCastConfig>::Source>,
> {
$crate::__impl_dyn_cast_wrapper::new::<
$config_type,
$self_type
>()
.__dyn_cast_macro_deref_specialization::<
_,
alloc::sync::Arc<<$config_type as $crate::DynCastConfig>::Target>,
alloc::sync::Arc<<$config_type as $crate::DynCastConfig>::Source>,
_,
>(self, |v| v)
}
}
};
};
($self_type:ty as $source_trait:path => $($target_trait:path),*) => {
$crate::impl_dyn_cast! {
$self_type => $(<dyn $source_trait + 'static as $crate::GetDynCastConfig<dyn $target_trait + 'static>>::Config),*
}
};
($self_type:ty => $($config_type:ty),*) => {
$(
const _: () = {
type __SelfType = $self_type;
type __ConfigType = $config_type;
$crate::impl_dyn_cast!(for<> __SelfType => __ConfigType);
};
)*
};
}
#[macro_export]
macro_rules! create_dyn_cast_config {
(
$(#[$attr:meta])*
$config_vis:vis
$config_name:ident
// Any generic arguments for the config type:
< $($lifetime:lifetime),* $($generics:ident),* $(,)? >
// Where clause:
$(where { $($where:tt)* })?
=
$source_trait:path
=>
$target_trait:path
) => {
$(#[$attr])*
$config_vis struct $config_name< $($lifetime,)* $($generics,)* >(
$(::core::marker::PhantomData<& $lifetime ()>,)*
$(::core::marker::PhantomData<$generics>,)*
) $(where $($where)* )?;
$crate::impl_dyn_cast_config!(
for<$($lifetime,)* $($generics,)*>
$config_name<$($lifetime,)* $($generics,)*>
$(where {$($where)*} )?
=
$source_trait
=>
$target_trait
);
};
($(#[$attr:meta])* $config_vis:vis $config_name:ident = $source_trait:path => $target_trait:path) => {
$(#[$attr])*
$config_vis struct $config_name;
$crate::impl_dyn_cast_config!($config_name = $source_trait => $target_trait);
};
}
#[macro_export]
macro_rules! impl_dyn_cast_config {
(
// Declare generic lifetimes and type parameters
for<$($lifetime:lifetime),* $($generics:ident),* $(,)?>
// Path to config type:
$config_type:path
// Where clause:
$(where { $($where:tt)* })?
=
$source_trait:path
=>
$target_trait:path
) => {
const _: () = {
impl< $($lifetime,)* $($generics,)* >
$crate::DynCastConfig
for
$config_type
$(where $($where)*)?
{
type Target = dyn $target_trait;
type Source = dyn $source_trait;
}
impl< $($lifetime,)* $($generics,)* __T>
$crate::DynCastConfigTargetTest<__T>
for
$config_type
where
__T: ?::core::marker::Sized + $target_trait,
$($($where)*)?
{}
impl< $($lifetime,)* $($generics,)* >
$crate::GetDynCastConfig<dyn $target_trait>
for
dyn $source_trait
$(where $($where)*)?
{
type Config = $config_type;
}
};
};
($config_type:ty = $source_trait:path => $target_trait:path) => {
const _: () = {
type __ConfigType = $config_type;
$crate::impl_dyn_cast_config!(for<> __ConfigType = $source_trait => $target_trait);
};
};
}
#[cfg(test)]
mod tests {
create_dyn_cast_config!(
#[derive(Clone)]
UpcastConfig = Super => Super
);
create_dyn_cast_config!(
#[derive(Clone)]
SuperConfig = Super => Sub
);
trait Super: super::DynCast<SuperConfig> + super::DynCast<UpcastConfig> {}
trait Sub: Super {}
struct TestSuper;
impl Super for TestSuper {}
impl_dyn_cast!(TestSuper => SuperConfig, UpcastConfig);
struct TestSub;
impl Super for TestSub {}
impl Sub for TestSub {}
impl_dyn_cast! {TestSub as Super => Sub, Super}
struct TestSubMixed;
impl Super for TestSubMixed {}
impl Sub for TestSubMixed {}
impl_dyn_cast! {TestSubMixed as Super => Sub}
impl_dyn_cast! {TestSubMixed => UpcastConfig}
#[allow(dead_code)]
fn check_fallback() {
struct T;
impl T {
fn test(self) {}
}
T.test();
}
struct TestGeneric<T>(T);
impl<T: 'static> Super for TestGeneric<T> {}
impl<T: 'static> Sub for TestGeneric<T> {}
impl_dyn_cast!(for<T> TestGeneric<T> as Super where {T: 'static} => Sub);
impl_dyn_cast!(for<T> TestGeneric<T> as Super where {T: 'static} => Super);
struct TestGenericMixed<T>(T);
impl<T: 'static> Super for TestGenericMixed<T> {}
impl<T: 'static> Sub for TestGenericMixed<T> {}
impl_dyn_cast!(for<T> TestGenericMixed<T> as Super where {T: 'static} => Sub);
impl_dyn_cast!(for<T> TestGenericMixed<T> where {T: 'static} => UpcastConfig);
struct OnlyDisplayGeneric<T>(T);
impl<T: 'static> Super for OnlyDisplayGeneric<T> {}
impl<T: core::fmt::Display + 'static> Sub for OnlyDisplayGeneric<T> {}
impl_dyn_cast!(for<T> OnlyDisplayGeneric<T> as Super where {T: 'static} => Sub);
impl_dyn_cast!(for<T> OnlyDisplayGeneric<T> as Super where {T: 'static} => Super);
#[test]
fn generic_impl() {
use super::DynCastExt;
let a: &dyn Super = &TestGeneric(());
assert!(a.dyn_cast::<dyn Sub>().is_ok());
let only_display: &dyn Super = &OnlyDisplayGeneric("");
let _is_display: &dyn core::fmt::Display = &"";
assert!(only_display.dyn_cast::<dyn Sub>().is_err());
let b: &dyn Sub = &OnlyDisplayGeneric("");
let b: &dyn Super = b.dyn_upcast();
assert!(b.dyn_cast::<dyn Sub>().is_err());
}
mod generic_traits {
trait Super<T>: crate::DynCast<SuperConfig<T, T>> {}
trait Sub<T>: Super<T> {}
create_dyn_cast_config!(
#[derive(Clone)]
SuperConfig<T, U> = Super<T> => Sub<U>
);
impl<T> Super<T> for () {}
impl_dyn_cast!(for<T> () => SuperConfig<T, T>);
struct TestSuper;
impl<T> Super<T> for TestSuper {}
impl_dyn_cast!(for<T> TestSuper => SuperConfig<T, T>);
struct TestSub;
impl<T: core::fmt::Display> Super<T> for TestSub {}
impl<T: core::fmt::Display> Sub<T> for TestSub {}
impl_dyn_cast! {for<T> TestSub as Super<T> where {T: core::fmt::Display} => Sub<T>}
}
#[test]
fn cast_to_generic_trait_object() {
trait SourceTrait<T> {
fn cast(&self) -> &dyn TargetTrait<T>;
}
trait TargetTrait<T> {}
impl<T> SourceTrait<T> for () {
fn cast(&self) -> &dyn TargetTrait<T> {
self
}
}
impl<T> TargetTrait<T> for () {}
let a: &dyn SourceTrait<u32> = &();
let _b: &dyn TargetTrait<u32> = a.cast();
}
#[cfg(feature = "proc-macros")]
#[allow(dead_code)]
pub mod with_macros {
use crate::*;
#[dyn_cast(Sub)]
#[dyn_upcast]
trait Super {}
trait Sub: Super {}
#[dyn_cast(Super => Sub)]
#[dyn_upcast(Super)]
struct TestSuper;
impl Super for TestSuper {}
#[dyn_cast(Super => Sub)]
#[dyn_upcast(Super)]
struct TestSub;
impl Super for TestSub {}
impl Sub for TestSub {}
pub mod generic_traits {
use crate::*;
#[dyn_upcast]
#[dyn_cast(Sub<T>)]
trait Super<T> {}
trait Sub<T>: Super<T> {}
#[dyn_cast(Sub<T>)]
#[dyn_upcast]
impl<T> Super<T> for (i32,) {}
impl<T> Sub<T> for (i32,) {}
struct TestSuper;
#[dyn_upcast]
#[dyn_cast(Sub<T>)]
impl<T: Clone> Super<T> for TestSuper where T: core::fmt::Display {}
struct TestSub;
#[dyn_upcast]
#[dyn_cast(Sub<T>)]
impl<T> Super<T> for TestSub {}
impl<T> Sub<T> for TestSub {}
}
}
}