| -rw-r--r-- | src/any.rs | 136 | ||||
| -rw-r--r-- | src/builtins.rs | 8 | ||||
| -rw-r--r-- | src/builtins/visitor.rs | 12 | ||||
| -rw-r--r-- | src/builtins/visitor/request_hint.rs | 26 | ||||
| -rw-r--r-- | src/builtins/walker.rs | 4 | ||||
| -rw-r--r-- | src/builtins/walker/hint.rs | 62 | ||||
| -rw-r--r-- | src/lib.rs | 8 | ||||
| -rw-r--r-- | src/protocol.rs | 67 |
8 files changed, 187 insertions, 136 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); + } } 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> = (); @@ -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; |