Diffstat (limited to 'src/any.rs')
-rw-r--r--src/any.rs136
1 files changed, 134 insertions, 2 deletions
diff --git a/src/any.rs b/src/any.rs
index 36905f6..ed7d1f7 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -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);
+ }
}