new AnyTrait impl
Konnor Andrews 2024-02-04
parent 66f5626 · commit 9f45b8a
-rw-r--r--src/any.rs136
-rw-r--r--src/builtins.rs8
-rw-r--r--src/builtins/visitor.rs12
-rw-r--r--src/builtins/visitor/request_hint.rs26
-rw-r--r--src/builtins/walker.rs4
-rw-r--r--src/builtins/walker/hint.rs62
-rw-r--r--src/lib.rs8
-rw-r--r--src/protocol.rs67
8 files changed, 187 insertions, 136 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);
+ }
}
diff --git a/src/builtins.rs b/src/builtins.rs
index 823135f..dba09ab 100644
--- a/src/builtins.rs
+++ b/src/builtins.rs
@@ -1,2 +1,8 @@
-// pub mod visitor;
+use crate::any::AnyTrait;
+
+pub mod visitor;
pub mod walker;
+
+pub type Visitor<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>;
+pub type Walker<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>;
+pub type ControlFlow<B = (), C = ()> = core::ops::ControlFlow<B, C>;
diff --git a/src/builtins/visitor.rs b/src/builtins/visitor.rs
index d36c3a6..4fb5b25 100644
--- a/src/builtins/visitor.rs
+++ b/src/builtins/visitor.rs
@@ -1,5 +1,7 @@
-pub mod request_hint;
-pub mod sequence;
-pub mod tagged;
-pub mod value;
-pub mod borrow;
+mod request_hint;
+// pub mod sequence;
+// pub mod tagged;
+// pub mod value;
+// pub mod borrow;
+
+pub use request_hint::*;
diff --git a/src/builtins/visitor/request_hint.rs b/src/builtins/visitor/request_hint.rs
index 6ab797a..747fa8e 100644
--- a/src/builtins/visitor/request_hint.rs
+++ b/src/builtins/visitor/request_hint.rs
@@ -1,23 +1,17 @@
-//! Protocol for requesting a visitor give a hint to walker.
-///
-/// Some walkers don't know what the data they are walking actually represents.
-/// This protocol allows such walkers to request the visitor to give a hint of what
-/// it is expecting.
-use crate::protocol::{Implementer, Protocol};
+use core::ops::ControlFlow;
-/// Protocol for requesting a visitor give a hint.
-pub enum RequestHint {}
+use crate::{nameable, any::AnyTrait, builtins::Walker};
-/// Object implementing the [`RequestHint`] protocol.
-pub trait RequestHintObject<'ctx> {
+/// Protocol for requesting a hint from a visitor.
+pub trait RequestHint<'ctx> {
/// Call this to request a hint.
///
- /// `hints` is expected to be the walker. This is what the visitor (`Self`)
- /// will call to give a hint using the
- /// [`Hint`][crate::builtins::walker::hint::Hint] protocol.
- fn request_hint(&mut self, hints: &mut dyn Implementer<'ctx>) -> Result<(), ()>;
+ /// `walker` is what the visitor (`self`) will call to give a hint using the
+ /// [`Hint`][crate::builtins::walker::Hint] protocol.
+ fn request_hint(&mut self, walker: Walker<'_, 'ctx>) -> ControlFlow<()>;
}
-impl Protocol for RequestHint {
- type Object<'a, 'ctx: 'a> = &'a mut dyn RequestHintObject<'ctx>;
+nameable! {
+ pub ['a, 'ctx]
+ dyn RequestHint<'ctx> + 'a where {'ctx: 'a}
}
diff --git a/src/builtins/walker.rs b/src/builtins/walker.rs
index a0216be..27ee8c5 100644
--- a/src/builtins/walker.rs
+++ b/src/builtins/walker.rs
@@ -1 +1,3 @@
-pub mod hint;
+mod hint;
+
+pub use hint::*;
diff --git a/src/builtins/walker/hint.rs b/src/builtins/walker/hint.rs
index 4392f73..a386f24 100644
--- a/src/builtins/walker/hint.rs
+++ b/src/builtins/walker/hint.rs
@@ -4,18 +4,16 @@
//! this module gives a protocol by which a visitor can give a hint
//! to the walker about what it is expecting.
-use core::marker::PhantomData;
+use core::{marker::PhantomData};
use crate::{
- any::{TypeName, TypeNameable},
- nameable,
- protocol::Implementer,
+ nameable, any::AnyTrait, builtins::{Visitor, ControlFlow},
};
/// Meta information for the hint.
///
/// This gives the visitor more information to work from when selecting a hint.
-pub trait Meta<'ctx> {
+pub trait HintMeta<'ctx> {
/// Information known by the walker.
///
/// This should be information easy to get without changing the state of the walker
@@ -27,44 +25,25 @@ pub trait Meta<'ctx> {
}
/// Object implementing the [`Hint`] protocol.
-pub trait Hint<'ctx, P: Meta<'ctx>> {
+pub trait Hint<'ctx, Protocol: HintMeta<'ctx>> {
/// Hint to the walker to use the `P` protocol.
///
/// This should only be called once per [`RequestHint`].
- fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>, hint: P::Hint<'_>) -> Result<(), ()>;
+ fn hint(&mut self, visitor: Visitor<'_, 'ctx>, hint: Protocol::Hint<'_>) -> ControlFlow;
/// Ask the walker for information about it's support of the protocol.
- fn known(&mut self, hint: &P::Hint<'_>) -> Result<P::Known<'_>, ()>;
+ fn known(&mut self, hint: &Protocol::Hint<'_>) -> ControlFlow<(), Protocol::Known<'_>>;
}
-// nameable!(['a, 'ctx, P: Meta<'ctx> + TypeNameable<'a, 'ctx>]: dyn Hint<'ctx, P> + 'a => dyn Hint<'static, P::Name>);
-
-const _: () = {
- impl<'a, 'ctx: 'a, P: TypeNameable<'a, 'ctx>>
- crate::any::TypeNameable<'a, 'ctx> for dyn Hint<'ctx, P> + 'a
- where
- P: ?Sized
- // where
- // P: Meta<'ctx>
- {
- type Name = Name<P::Name>;
- }
-
- pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>);
-
- impl<'a, 'ctx: 'a, T: TypeName<'a, 'ctx>> crate::any::TypeName<'a, 'ctx> for Name<T>
- where
- T: ?Sized
- // where
- // T::Nameable: Meta<'ctx>,
- {
- type Nameable = dyn Hint<'ctx, T::Nameable> + 'a;
- }
-};
+nameable! {
+ pub ['a, 'ctx, Protocol]
+ dyn Hint<'ctx, Protocol> + 'a where {'ctx: 'a, Protocol: ?Sized}
+ dyn Hint<'ctx, Protocol::Nameable> + 'a where {'ctx: 'a, Protocol: ?Sized}
+}
#[cfg(test)]
mod test {
- use crate::any::LtTypeId;
+ use crate::any::{LtTypeId, TypeNameable};
use super::*;
@@ -73,26 +52,29 @@ mod test {
struct X;
struct Y;
- nameable!(['a, 'ctx]: Y => Y);
+ nameable! {
+ ['a, 'ctx]
+ Y where {}
+ }
impl<'ctx, X> Hint<'ctx, Y> for X {
fn hint(
&mut self,
- visitor: &mut dyn Implementer<'ctx>,
- hint: <Y as Meta>::Hint<'_>,
- ) -> Result<(), ()> {
+ visitor: &mut dyn AnyTrait<'ctx>,
+ hint: <Y as HintMeta>::Hint<'_>,
+ ) -> ControlFlow<()> {
todo!()
}
fn known(
&mut self,
- hint: &<Y as Meta>::Hint<'_>,
- ) -> Result<<Y as Meta>::Known<'_>, ()> {
+ hint: &<Y as HintMeta>::Hint<'_>,
+ ) -> ControlFlow<(), <Y as HintMeta>::Known<'_>> {
todo!()
}
}
- impl<'ctx> Meta<'ctx> for Y {
+ impl<'ctx> HintMeta<'ctx> for Y {
type Known<'a> = ();
type Hint<'a> = ();
diff --git a/src/lib.rs b/src/lib.rs
index 02c8f9e..1563171 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,11 +7,11 @@
extern crate alloc;
pub mod any;
-mod build;
-// pub mod builtins;
-pub mod protocol;
+// mod build;
+pub mod builtins;
+// pub mod protocol;
pub mod symbol;
-mod walk;
+// mod walk;
// pub mod impls;
// pub mod transform;
diff --git a/src/protocol.rs b/src/protocol.rs
index f411556..ba5826d 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -35,73 +35,6 @@
use crate::any::{IndirectLtAny, LtAny, LtTypeId, Mut, Ref, TypeNameable};
-pub trait Implementer<'ctx> {
- fn interface(&self, id: LtTypeId<'ctx>) -> Option<IndirectLtAny<'_, 'ctx, Ref>>;
-}
-
-pub trait ImplementerMut<'ctx> {
- fn interface_mut<'a>(&'a mut self, id: LtTypeId<'ctx>) -> Option<IndirectLtAny<'a, 'ctx, Mut>> where 'ctx: 'a;
-}
-
-/// Extension trait for getting the implementation of a protocol.
-pub trait ImplementerMutExt<'ctx>: ImplementerMut<'ctx> {
- /// Get an implementation given a protocol type.
- ///
- /// This wraps [`Implementer::interface`] and [`AnyImpl::downcast`].
- /// If [`Implementer::interface`] returns a [`AnyImpl`] for the wrong protocol then a panic is
- /// generated.
- fn interface_mut_for<'a, P: TypeNameable<'a, 'ctx>>(&'a mut self) -> Option<&'a mut P>
- where
- 'ctx: 'a;
-}
-
-impl<'ctx, T: ImplementerMut<'ctx> + ?Sized> ImplementerMutExt<'ctx> for T {
- fn interface_mut_for<'a, P: TypeNameable<'a, 'ctx>>(&'a mut self) -> Option<&'a mut P>
- where
- 'ctx: 'a
- {
- match self.interface_mut(LtTypeId::of::<P>()) {
- Some(interface) => match interface.downcast::<P>() {
- Ok(implementation) => Some(implementation),
- Err(interface) => panic!(
- "unexpected protocol implementation: `{:?}`, expected: `{:?}`",
- interface.id(),
- LtTypeId::of::<P>()
- ),
- },
- None => None,
- }
- }
-}
-
-/// Implement [`Implementer`] and [`Implementation`] for a set of protocols.
-#[doc(hidden)]
-#[macro_export]
-macro_rules! implementer {
- {
- impl[$a:lifetime, $ctx:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?];
- } => {
- impl<$ctx $($generic)*> $crate::protocol::ImplementerMut<$ctx> for $name {
- #[inline]
- fn interface_mut<$a>(
- &$a mut self,
- id: $crate::any::LtTypeId<$ctx>
- ) -> ::core::option::Option<$crate::any::IndirectLtAny<$a, $ctx, $crate::any::Mut>>
- where
- $ctx: $a
- {
- match id {
- $(id if id == $crate::any::LtTypeId::of::<$protocol>()
- => ::core::option::Option::Some($crate::any::IndirectLtAny::<$a, $ctx, _>::new::<$protocol>(self as _)),)*
- _ => ::core::option::Option::None
- }
- }
- }
- };
-}
-#[doc(inline)]
-pub use implementer;
-
#[cfg(test)]
mod test {
use crate::nameable;