Diffstat (limited to 'src/any.rs')
| -rw-r--r-- | src/any.rs | 136 |
1 files changed, 134 insertions, 2 deletions
@@ -52,7 +52,7 @@ macro_rules! nameable { ::core::marker::PhantomData<fn() -> ($( $(*const $generic,)* )?)> ); - impl<$a, $lt $(, $($generic: $crate::any::TypeName<$a, $lt>)*)?> + impl<$a, $lt $(, $($generic: $crate::any::TypeName<$a, $lt>)*)?> $crate::any::TypeName<$a, $lt> for Name$(<$($generic),*>)? where $($bound2)* @@ -67,7 +67,7 @@ pub use nameable; pub struct Owned<T: ?Sized>(pub T); nameable! { - pub ['a, 'lt, T] + pub ['a, 'lt, T] Owned<T> where {T: ?Sized} Owned<T::Nameable> where {T: ?Sized} } @@ -139,6 +139,87 @@ impl<'a, 'lt> dyn LtAny<'lt> + 'a { } } +pub trait AnyTrait<'lt> { + fn upcast_to_id<'a>(&'a self, id: LtTypeId<'lt>) -> Option<IndirectLtAny<'a, 'lt, Ref>> + where + 'lt: 'a; + + 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> { + pub fn upcast<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>(&'a self) -> Option<&'a 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() + ), + }) + } + + pub fn upcast_mut<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>(&'a mut self) -> Option<&'a mut 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`. Expected: {:?}, Got {:?}", + LtTypeId::of::<Trait>(), + object.id() + ), + }) + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! any_trait { + { + impl[$a:lifetime, $lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?]; + } => { + impl<$lt $($generic)*> $crate::any::AnyTrait<$lt> for $name { + #[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 _)),)* + _ => ::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 _)),)* + _ => ::core::option::Option::None + } + } + } + }; +} +#[doc(inline)] +pub use any_trait; + + #[must_use] pub struct IndirectLtAny<'a, 'lt: 'a, I: Indirect<'a>> { info: fn() -> (LtTypeId<'lt>, unsafe fn(RawIndirect)), @@ -312,4 +393,55 @@ mod test { X<'lt> where {'lt: 'a} X<'lt> where {'lt: 'a} } + + #[test] + fn implementer_macro() { + trait Z {} + + nameable! { + ['a, 'ctx] + dyn Z + 'a where {'ctx: 'a} + } + + struct X<T>(T); + + impl<T: Clone> Z for X<T> {} + + any_trait! { + impl['a, 'ctx, T: Clone] X<T> = [ + dyn Z + 'a + ]; + } + } + + #[test] + fn any_trait_macro() { + trait Z { + fn num(&self) -> i32; + } + + nameable! { + ['a, 'ctx] + dyn Z + 'a where {'ctx: 'a} + } + + struct X(i32); + + impl Z for X { + fn num(&self) -> i32 { + self.0 + } + } + + any_trait! { + impl['a, 'ctx] X = [ + dyn Z + 'a + ]; + } + + let x = X(42); + let y: &dyn AnyTrait = &x; + let z: &dyn Z = y.upcast().unwrap(); + assert_eq!(z.num(), 42); + } } |