changed how the tag protocol works and start of struct macro
| -rw-r--r-- | protocols.md | 7 | ||||
| -rw-r--r-- | src/any.rs | 21 | ||||
| -rw-r--r-- | src/build.rs | 8 | ||||
| -rw-r--r-- | src/build/builders.rs | 3 | ||||
| -rw-r--r-- | src/build/builders/core.rs | 3 | ||||
| -rw-r--r-- | src/build/builders/core/bool.rs | 6 | ||||
| -rw-r--r-- | src/build/builders/core/option.rs | 21 | ||||
| -rw-r--r-- | src/build/builders/core/tag_name.rs | 1 | ||||
| -rw-r--r-- | src/build/builders/debug.rs | 101 | ||||
| -rw-r--r-- | src/lib.rs | 268 | ||||
| -rw-r--r-- | src/protocol/visitor.rs | 2 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 12 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs | 14 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 89 | ||||
| -rw-r--r-- | src/protocol/visitor/tagged.rs | 63 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 46 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs | 31 | ||||
| -rw-r--r-- | src/symbol.rs | 4 | ||||
| -rw-r--r-- | src/walk.rs | 80 | ||||
| -rw-r--r-- | src/walk/walkers/core.rs | 2 | ||||
| -rw-r--r-- | src/walk/walkers/core/bool.rs | 2 | ||||
| -rw-r--r-- | src/walk/walkers/core/tag.rs | 89 | ||||
| -rw-r--r-- | tests/hook.rs | 14 |
23 files changed, 695 insertions, 192 deletions
diff --git a/protocols.md b/protocols.md new file mode 100644 index 0000000..f79e1c9 --- /dev/null +++ b/protocols.md @@ -0,0 +1,7 @@ +struct +- name +- type_id +- fields + - name + - index + - type_id @@ -195,6 +195,8 @@ pub struct LtTypeId<'lt> { /// The type ID of the name type of the type. name_id: core::any::TypeId, + + name: &'static str, } impl<'lt> LtTypeId<'lt> { @@ -206,10 +208,17 @@ impl<'lt> LtTypeId<'lt> { LtTypeId { _marker: PhantomData, name_id: core::any::TypeId::of::<T::Name>(), + name: core::any::type_name::<T>(), } } } +impl<'lt> core::fmt::Display for LtTypeId<'lt> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Display::fmt(self.name, f) + } +} + /// [`Any`][core::any::Any] with a lifetime generic `'lt`. /// /// This trait is implemented on all types that implement @@ -400,7 +409,7 @@ impl<'lt> dyn AnyTrait<'lt> + Send + '_ { #[macro_export] macro_rules! any_trait { { - impl[$a:lifetime, $lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?] $(where $($bound:tt)*)? + impl[$a:lifetime, $lt:lifetime $($generic:tt)*] $name:ty = [$($protocol:ty),* $(,)?] $(else $fallback:path)? $(where $($bound:tt)*)? } => { impl<$lt $($generic)*> $crate::any::AnyTrait<$lt> for $name $(where $($bound)*)? @@ -416,7 +425,10 @@ macro_rules! any_trait { 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 + _ => { + $($fallback(id);)? + ::core::option::Option::None + } } } @@ -431,7 +443,10 @@ macro_rules! any_trait { 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 + _ => { + $($fallback(id);)? + ::core::option::Option::None + } } } } diff --git a/src/build.rs b/src/build.rs index 3723392..ab408e8 100644 --- a/src/build.rs +++ b/src/build.rs @@ -8,7 +8,13 @@ use crate::{ /// A buildable type. pub trait Build<'ctx>: BuilderTypes<'ctx, Value = Self> + Send { /// The builder that can be used to build a value of `Self`. - type Builder<E: Effect<'ctx>>: Builder<'ctx, Seed = Self::Seed, Error = Self::Error, Value = Self, Effect = E>; + type Builder<E: Effect<'ctx>>: Builder< + 'ctx, + Seed = Self::Seed, + Error = Self::Error, + Value = Self, + Effect = E, + >; } pub trait BuilderTypes<'ctx> { diff --git a/src/build/builders.rs b/src/build/builders.rs index b5d0e43..1a19319 100644 --- a/src/build/builders.rs +++ b/src/build/builders.rs @@ -2,3 +2,6 @@ pub mod core; // #[cfg(feature = "serde")] // pub mod serde; + +#[cfg(feature = "std")] +pub mod debug; diff --git a/src/build/builders/core.rs b/src/build/builders/core.rs index e1b3383..f983601 100644 --- a/src/build/builders/core.rs +++ b/src/build/builders/core.rs @@ -1,5 +1,6 @@ // pub mod array; pub mod bool; -pub mod option; +// pub mod option; // pub mod variant; +pub mod tag_name; diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs index 64f6876..3dbede2 100644 --- a/src/build/builders/core/bool.rs +++ b/src/build/builders/core/bool.rs @@ -59,11 +59,13 @@ impl<'ctx, E: Effect<'ctx>> crate::Builder<'ctx> for Builder<E> { any_trait! { impl['a, 'ctx, E] Builder<E> = [ - dyn Value<'a, 'ctx, OwnedStatic<bool>, E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<bool>, Effect = E> + 'a, ] where E: Effect<'ctx> } -impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for Builder<E> { +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>> for Builder<E> { + type Effect = E; + #[inline] fn visit( &'a mut self, diff --git a/src/build/builders/core/option.rs b/src/build/builders/core/option.rs index cb2e624..bd563f9 100644 --- a/src/build/builders/core/option.rs +++ b/src/build/builders/core/option.rs @@ -18,7 +18,7 @@ where type Builder<E: Effect<'ctx>> = Builder<'ctx, T::Builder<E>, E>; } -impl<'ctx, T> crate::BuilderTypes<'ctx> for Option<T> +impl<'ctx, T> crate::BuilderTypes<'ctx> for Option<T> where T: crate::Build<'ctx>, <T as crate::BuilderTypes<'ctx>>::Seed: Default, @@ -53,7 +53,7 @@ pub enum Error<'ctx, T> { NoVariantGiven, } -impl<'ctx, B, E: Effect<'ctx>> crate::BuilderTypes<'ctx> for Builder<'ctx, B, E> +impl<'ctx, B, E: Effect<'ctx>> crate::BuilderTypes<'ctx> for Builder<'ctx, B, E> where B: crate::Builder<'ctx, Effect = E>, <B as crate::BuilderTypes<'ctx>>::Seed: Default, @@ -103,7 +103,7 @@ where any_trait! { impl['a, 'ctx, B, E] Builder<'ctx, B, E> = [ dyn Tagged<'ctx, E> + 'a, - ] where B: crate::Builder<'ctx, Effect = E>, E: Effect<'ctx>, + ] where B: crate::Builder<'ctx, Effect = E>, E: Effect<'ctx>, <B as crate::BuilderTypes<'ctx>>::Seed: Default, } @@ -204,8 +204,7 @@ impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, TempBorrowedStatic<'a, st &'a mut self, TempBorrowedStatic(value): TempBorrowedStatic<'a, str>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { - E::wrap(core::future::ready( - match value { + E::wrap(core::future::ready(match value { "None" => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) @@ -229,8 +228,7 @@ impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, BorrowedStatic<'ctx, str> &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, str>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { - E::wrap(core::future::ready( - match value { + E::wrap(core::future::ready(match value { "None" => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) @@ -256,8 +254,7 @@ impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str> &'a mut self, OwnedStatic(value): OwnedStatic<&'static str>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { - E::wrap(core::future::ready( - match value { + E::wrap(core::future::ready(match value { "None" => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) @@ -283,8 +280,7 @@ impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<u8>, E> &'a mut self, OwnedStatic(value): OwnedStatic<u8>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { - E::wrap(core::future::ready( - match value { + E::wrap(core::future::ready(match value { 0 => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) @@ -308,8 +304,7 @@ impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<u16>, E> &'a mut self, OwnedStatic(value): OwnedStatic<u16>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { - E::wrap(core::future::ready( - match value { + E::wrap(core::future::ready(match value { 0 => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) diff --git a/src/build/builders/core/tag_name.rs b/src/build/builders/core/tag_name.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/build/builders/core/tag_name.rs @@ -0,0 +1 @@ + diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs new file mode 100644 index 0000000..7cf0aad --- /dev/null +++ b/src/build/builders/debug.rs @@ -0,0 +1,101 @@ +use core::{any::TypeId, marker::PhantomData, ops::ControlFlow}; + +use crate::{ + any::{static_wrapper::OwnedStatic, LtTypeId}, + any_trait, + effect::{Effect, Future}, + protocol::{visitor::{ + tag::{Dyn, Tag}, + value::Value, request_hint::RequestHint, + }, self}, + DynWalker, +}; + +pub struct Walker<E>(usize, PhantomData<fn() -> E>); + +any_trait! { + impl['a, 'ctx, E] Walker<E> = [ + dyn RequestHint<'ctx, Effect = E> + 'a, + dyn Tag<'ctx, Dyn, Effect = E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<&'static str>, Effect = E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<TypeId>, Effect = E> + 'a, + ] else fallback where E: Effect<'ctx> +} + +fn fallback(id: LtTypeId<'_>) { + println!("Unknown trait: {}", id); +} + +impl<'ctx, E: Effect<'ctx>> Walker<E> { + pub fn new() -> Self { + Self(0, PhantomData) + } + + fn tab(&self) { + for _ in 0..self.0 { + print!(" "); + } + } +} + +impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx> for Walker<E> { + type Effect = E; + + fn request_hint<'a>( + &'a mut self, + _walker: crate::protocol::Walker<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a + { + self.tab(); + println!("Visit request hint (no hint given)"); + E::wrap(async { ControlFlow::Continue(()) }) + } +} + +impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn> for Walker<E> { + type Effect = E; + + fn visit<'a>( + &'a mut self, + kind: Dyn, + walker: &'a mut dyn DynWalker<'ctx, Effect = Self::Effect>, + ) -> Future<'a, 'ctx, ControlFlow<(), protocol::visitor::tag::Status>, Self::Effect> + where + Self: 'a, + { + self.tab(); + println!("Visit tag: {}", kind.0); + + E::wrap(async { + self.0 += 1; + let result = walker.walk(self).await; + self.0 -= 1; + match result { + ControlFlow::Continue(()) => ControlFlow::Continue(protocol::visitor::tag::Status::Walked), + ControlFlow::Break(()) => ControlFlow::Break(()), + } + }) + } +} + +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>> for Walker<E> { + type Effect = E; + + fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<&'static str>) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> where Self: 'a { + self.tab(); + println!("Visit static str: {:?}", value); + E::wrap(async { ControlFlow::Continue(()) }) + } +} + +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<TypeId>> for Walker<E> { + type Effect = E; + + fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<TypeId>) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> where Self: 'a { + self.tab(); + println!("Visit type ID: {:?}", value); + E::wrap(async { ControlFlow::Continue(()) }) + } +} @@ -24,12 +24,42 @@ mod transform; // pub use walk::Walk; // pub use walk::Walker; +use core::ops::ControlFlow; + pub use build::*; +use effect::{Effect, Future}; +use protocol::Visitor; +use symbol::Symbol; pub use transform::*; pub use walk::*; +pub mod never { + mod sealed { + pub trait Extract { + type T; + } + + impl<T> Extract for fn() -> T { + type T = T; + } + } + + #[doc(hidden)] + pub type Never = <fn() -> ! as sealed::Extract>::T; +} + +pub const TAG_TYPE_NAME: Symbol = Symbol::new("Type Name"); +pub const TAG_TYPE_ID: Symbol = Symbol::new("Type ID"); +pub const TAG_TYPE_SIZE: Symbol = Symbol::new("Type Size"); +pub const TAG_FIELD_NAMES: Symbol = Symbol::new("Field Names"); + +#[derive(Debug)] +pub enum StructWalkError { + Tag(Symbol, &'static str), +} + #[macro_export] -macro_rules! Build { +macro_rules! Walk { { $(#[$($attr:tt)*])* $vis:vis struct $name:ident {$( @@ -37,79 +67,201 @@ macro_rules! Build { ),* $(,)?} } => { const _: () = { - impl<'ctx> $crate::Build<'ctx> for $name { - type Builder = StructBuilder; - } - - #[derive(Default)] - $vis struct StructBuilder {$( - $field: Option<$type> - ),*} + impl<'ctx> $crate::Walk<'ctx> for &'ctx $name { + type Walker<E: $crate::effect::Effect<'ctx>> = Walker<'ctx, E>; - impl<'ctx> $crate::Builder<'ctx> for StructBuilder { - type Error = (); - - type Value = $name; - - fn as_visitor(&mut self) -> &mut dyn $crate::protocol::Implementer<'ctx> { - self - } - - fn build(self) -> Result<Self::Value, Self::Error> { - if let StructBuilder {$($field: Some($field)),*} = self { - Ok($name {$($field),*}) - } else { - Err(()) + fn into_walker<E: $crate::effect::Effect<'ctx>>(self) -> Self::Walker<E> { + Walker { + value: self, + _marker: ::core::marker::PhantomData, } } } - $crate::protocol::implementer! { - impl['ctx] StructBuilder = [ - - ]; + impl<'ctx> $crate::WalkerTypes<'ctx> for &'ctx $name { + type Error = $crate::StructWalkError; + type Output = (); } - impl<'ctx> $crate::Walk<'ctx> for $name { - type Walker = StructWalker; + pub struct Walker<'ctx, E> { + value: &'ctx $name, + _marker: ::core::marker::PhantomData<fn() -> E>, } - $vis struct StructWalker { - value: Option<$name>, - hint_given: bool, + impl<'ctx, E> $crate::WalkerTypes<'ctx> for Walker<'ctx, E> { + type Error = $crate::StructWalkError; + type Output = (); } - impl From<$name> for StructWalker { - fn from(value: $name) -> Self { - Self { - value: Some(value), - hint_given: false - } - } - } + impl<'ctx, E: $crate::effect::Effect<'ctx>> $crate::Walker<'ctx> for Walker<'ctx, E> { + type Effect = E; - impl<'ctx> $crate::Walker<'ctx> for StructWalker { - type Error = (); + fn walk<'a>( + mut self, + visitor: $crate::protocol::Visitor<'a, 'ctx>, + ) -> $crate::effect::Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + where + Self: 'a + { + E::wrap(async move { + // We should check if the visitor wants something specific. + if let Some(object) = visitor.upcast_mut::<dyn $crate::protocol::visitor::request_hint::RequestHint<'ctx, Effect = E> + '_>() { + // Allow the visitor to give a hint if it wants. + match object.request_hint(&mut self).await { + ::core::ops::ControlFlow::Continue(()) => { + // The visitor wants the walker to continue to it's normal + // walking. + }, + ::core::ops::ControlFlow::Break(()) => { + // The visitor is done (either because of an error or because + // it already used a hint). + return Ok(()); + }, + } + } - type Output = (); + // Follow the standard set of protocols for a struct. + // - Tagged: struct name + // - Tagged: struct type + // - Tagged: struct field names + // - Sequence: the fields - fn walk( - &mut self, - visitor: &mut dyn $crate::protocol::Implementer<'ctx> - ) -> Result<Self::Output, Self::Error> { - use $crate::protocol::ImplementerExt; - // Want kinds for tags. - if let Some(interface) = visitor.interface_for:: - <$crate::builtins::visitor::request_hint>() { - interface.as_object().visit(&mut self); - } - $( - <$type as $crate::Walk>::Walker::from(self.0.$field) - .walk(visitor); - )* - todo!() + if let Ok((result, flow)) = + $crate::try_visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>( + visitor, + $crate::walkers::core::tag::NameWalker::new(stringify!($name)) + ).await + { + match result { + Ok(()) => {}, + Err($crate::DynWalkerError::Walker($crate::walkers::core::tag::MissingProtocol(msg))) => { + return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_NAME, msg)) + } + Err($crate::DynWalkerError::NeverWalked(_)) => { + return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_NAME, "visitor didn't walk walker")) + }, + Err($crate::DynWalkerError::WalkNeverFinished) => { + return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_NAME, "walk didn't finish")) + }, + } + + if let ::core::ops::ControlFlow::Break(()) = flow { + return Ok(()); + } + } + + if let Ok((result, flow)) = + $crate::try_visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>( + visitor, + $crate::walkers::core::tag::TypeIdWalker::new::<$name>() + ).await + { + match result { + Ok(()) => {}, + Err($crate::DynWalkerError::Walker($crate::walkers::core::tag::MissingProtocol(msg))) => { + return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_ID, msg)) + } + Err($crate::DynWalkerError::NeverWalked(_)) => { + return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_ID, "visitor didn't walk walker")) + }, + Err($crate::DynWalkerError::WalkNeverFinished) => { + return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_ID, "walk didn't finish")) + }, + } + + if let ::core::ops::ControlFlow::Break(()) = flow { + return Ok(()); + } + } + + todo!() + }) } } + + $crate::any::any_trait! { + impl['a, 'ctx, E] Walker<'ctx, E> = [ + // dyn Hint<'a, 'ctx, OwnedStatic<bool>, E> + 'a, + ] where E: $crate::effect::Effect<'ctx> + } + }; }; } + +pub fn try_visit_tag< + 'a, + 'ctx, + const SYMBOL: u64, + E: Effect<'ctx>, + W: Walker<'ctx, Effect = E> + 'a, +>( + visitor: Visitor<'a, 'ctx>, + walker: W, +) -> Future< + 'a, + 'ctx, + Result< + ( + Result<W::Output, DynWalkerError<'ctx, W>>, + ControlFlow<(), protocol::visitor::tag::Status>, + ), + W, + >, + E, +> { + E::wrap(async { + if let Some(object) = visitor.upcast_mut::< + dyn protocol::visitor::tag::Tag< + 'ctx, + protocol::visitor::tag::Const<SYMBOL>, + Effect = E + > + '_ + >() { + let mut name_walker = DynWalkerAdapter::new(walker); + let flow = object.visit(protocol::visitor::tag::Const, &mut name_walker).await; + Ok((name_walker.finish(), match flow { + ControlFlow::Continue(()) => ControlFlow::Continue(protocol::visitor::tag::Status::Walked), + ControlFlow::Break(()) => ControlFlow::Break(()), + })) + } else if let Some(object) = visitor.upcast_mut::< + dyn protocol::visitor::tag::Tag< + 'ctx, + protocol::visitor::tag::Dyn, + Effect = E + > + '_ + >() { + let mut name_walker = DynWalkerAdapter::new(walker); + let flow = object.visit(protocol::visitor::tag::Dyn(Symbol::from_int(SYMBOL)), &mut name_walker).await; + Ok((name_walker.finish(), flow)) + } else { + Err(walker) + } + }) +} + +#[cfg(test)] +mod test { + use crate::effect::{BlockOn, Blocking, Spin}; + + use super::*; + use macro_rules_attribute::derive; + + #[derive(Walk!)] + struct Demo { + a: bool, + b: bool, + } + + #[test] + fn demo() { + let value = Demo { a: true, b: false }; + + let walker = value.into_walker::<Blocking>(); + let mut visitor = builders::debug::Walker::<Blocking>::new(); + + dbg!(Spin::block_on(walker.walk(&mut visitor))); + + todo!(); + } +} diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs index 1f69862..efaa495 100644 --- a/src/protocol/visitor.rs +++ b/src/protocol/visitor.rs @@ -1,4 +1,4 @@ pub mod request_hint; pub mod sequence; -pub mod tagged; +pub mod tag; pub mod value; diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index 8bd8431..f1ab735 100644 --- a/src/protocol/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -7,20 +7,24 @@ use crate::{ }; /// Protocol for requesting a hint from a visitor. -pub trait RequestHint<'a, 'ctx: 'a, E: Effect<'ctx>> { +pub trait RequestHint<'ctx> { + type Effect: Effect<'ctx>; + /// Call this to request a hint. /// /// `walker` is what the visitor (`self`) will call to give a hint using the /// [`Hint`][crate::builtins::walker::Hint] protocol. - fn request_hint( + fn request_hint<'a>( &'a mut self, walker: Walker<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a; } nameable! { pub struct Name['a, 'ctx, E]; - impl [E] for dyn RequestHint<'a, 'ctx, E> + 'a where { + impl [E] for dyn RequestHint<'ctx, Effect = E> + 'a where { E: Effect<'ctx>, 'ctx: 'a } diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs index 46c8e71..e9dd721 100644 --- a/src/protocol/visitor/sequence.rs +++ b/src/protocol/visitor/sequence.rs @@ -8,22 +8,24 @@ use crate::{ protocol::{walker::hint::HintMeta, Visitor}, }; -pub trait Sequence<'ctx, E: Effect<'ctx>> { +pub trait Sequence<'ctx> { + type Effect: Effect<'ctx>; + fn visit<'a>( &'a mut self, - scope: &'a mut dyn SequenceScope<'ctx, E>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; + scope: &'a mut dyn SequenceScope<'ctx, Self::Effect>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>; } nameable! { pub struct Name['a, 'ctx, E]; - impl [E] for dyn Sequence<'ctx, E> + 'a where { + impl [E] for dyn Sequence<'ctx, Effect = E> + 'a where { E: Effect<'ctx>, 'ctx: 'a } - impl [E] where dyn Sequence<'ctx, E> + 'a { + impl [E] where dyn Sequence<'ctx, Effect = E> + 'a { E: Effect<'ctx>, 'ctx: 'a } @@ -58,7 +60,7 @@ pub struct Hint { pub len: (usize, Option<usize>), } -impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for dyn Sequence<'ctx, E> + '_ { +impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for dyn Sequence<'ctx, Effect = E> + '_ { type Known = KnownHkt<'ctx>; type Hint = Hint; diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs new file mode 100644 index 0000000..974c47b --- /dev/null +++ b/src/protocol/visitor/tag.rs @@ -0,0 +1,89 @@ +use core::ops::ControlFlow; + +use crate::{ + any::{TypeName, TypeNameable}, + effect::{Effect, Future}, + higher_ranked_type, + hkt::AnySend, + nameable, + protocol::{walker::hint::HintMeta, Visitor, Walker}, + symbol::Symbol, + DynWalker, +}; + +pub trait Kind: 'static { + type Status: Send; + + fn symbol(&self) -> Symbol; +} + +pub struct Const<const SYMBOL: u64>; +pub struct Dyn(pub Symbol); + +impl<const SYMBOL: u64> Kind for Const<SYMBOL> { + type Status = (); + + fn symbol(&self) -> Symbol { + Symbol::from_int(SYMBOL) + } +} + +impl Kind for Dyn { + type Status = Status; + + fn symbol(&self) -> Symbol { + self.0 + } +} + +pub trait Tag<'ctx, K: Kind> { + type Effect: Effect<'ctx>; + + fn visit<'a>( + &'a mut self, + kind: K, + walker: &'a mut dyn DynWalker<'ctx, Effect = Self::Effect>, + ) -> Future<'a, 'ctx, ControlFlow<(), K::Status>, Self::Effect> + where + Self: 'a; +} + +#[must_use] +pub enum Status { + Walked, + Skiped, +} + +nameable! { + pub struct Name['a, 'ctx, K, E]; + + impl [K, E] for dyn Tag<'ctx, K, Effect = E> + 'a where { + K: Kind, + E: Effect<'ctx>, + 'ctx: 'a + } + + impl [K, E] where dyn Tag<'ctx, K, Effect = E> + 'a { + K: Kind, + E: Effect<'ctx>, + 'ctx: 'a + } +} + +higher_ranked_type! { + pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known +} + +pub struct Known { + pub kind_available: Option<bool>, +} + +pub struct Hint<K> { + pub kind: Option<K>, +} + +impl<'a, 'ctx: 'a, K, E> HintMeta<'ctx> for dyn Tag<'ctx, K, Effect = E> + 'a { + type Known = KnownHkt<'ctx>; + + type Hint = Hint<K>; +} diff --git a/src/protocol/visitor/tagged.rs b/src/protocol/visitor/tagged.rs deleted file mode 100644 index 1622f4d..0000000 --- a/src/protocol/visitor/tagged.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::ops::ControlFlow; - -use crate::{ - effect::{Effect, Future}, - higher_ranked_type, - hkt::AnySend, - nameable, - protocol::{walker::hint::HintMeta, Visitor}, - symbol::Symbol, -}; - -pub trait Tagged<'ctx, E: Effect<'ctx>> { - fn visit<'a>( - &'a mut self, - scope: &'a mut (dyn TaggedScope<'ctx, E> + Send), - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; -} - -nameable! { - pub struct Name['a, 'ctx, E]; - - impl [E] for dyn Tagged<'ctx, E> + 'a where { - E: Effect<'ctx>, - 'ctx: 'a - } - - impl [E] where dyn Tagged<'ctx, E> + 'a { - E: Effect<'ctx>, - 'ctx: 'a - } -} - -pub trait TaggedScope<'ctx, E: Effect<'ctx>> { - fn kind<'a>(&mut self) -> Future<'a, 'ctx, Symbol, E>; - - fn tag<'a>( - &'a mut self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; - - fn value<'a>( - &'a mut self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; -} - -higher_ranked_type! { - pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known -} - -pub struct Known { - pub kind_available: Option<bool>, -} - -pub struct Hint { - pub kind: Option<Symbol>, -} - -impl<'a, 'ctx: 'a, Return> HintMeta<'ctx> for dyn Tagged<'ctx, Return> + 'a { - type Known = KnownHkt<'ctx>; - - type Hint = Hint; -} diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs index 5628eac..a0c435c 100644 --- a/src/protocol/visitor/value.rs +++ b/src/protocol/visitor/value.rs @@ -16,7 +16,9 @@ use crate::{ /// Trait object for the [`Value`] protocol. /// /// Types implementing the [`Value`] protocol will implement this trait. -pub trait Value<'a, 'ctx: 'a, T, E: Effect<'ctx>> { +pub trait Value<'a, 'ctx: 'a, T> { + type Effect: Effect<'ctx>; + /// Visit a value of type `T`. /// /// Use this to give a value to a visitor. Its expected that a walker @@ -26,19 +28,21 @@ pub trait Value<'a, 'ctx: 'a, T, E: Effect<'ctx>> { /// If a [`ControlFlow::Break`] is returned then the walker /// should stop walking as soon as possible as there has likely been /// and error. - fn visit(&'a mut self, value: T) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; + fn visit(&'a mut self, value: T) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a; } nameable! { pub struct Name['a, 'ctx, T, E]; - impl [T::Name, E] for dyn Value<'a, 'ctx, T, E> + 'a where { + impl [T::Name, E] for dyn Value<'a, 'ctx, T, Effect = E> + 'a where { T: TypeNameable<'a, 'ctx> + ?Sized, E: Effect<'ctx>, 'ctx: 'a, } - impl [T, E] where dyn Value<'a, 'ctx, T::Nameable, E> + 'a { + impl [T, E] where dyn Value<'a, 'ctx, T::Nameable, Effect = E> + 'a { T: TypeName<'a, 'ctx> + ?Sized, E: Effect<'ctx>, 'ctx: 'a, @@ -50,7 +54,7 @@ higher_ranked_type! { } // This enrolls the Value protocol into the walker hint system. -impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> HintMeta<'ctx> for dyn Value<'a, 'ctx, T, E> + 'a { +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> HintMeta<'ctx> for dyn Value<'a, 'ctx, T, Effect = E> + 'a { type Known = Known<'ctx>; type Hint = (); @@ -75,10 +79,12 @@ mod test { fn visit() { struct Visitor<E>(Option<i32>, PhantomData<fn() -> E>); - impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, OwnedStatic<i32>, E> for Visitor<E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, OwnedStatic<i32>> for Visitor<E> where E: Effect<'ctx>, { + type Effect = E; + fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<i32>, @@ -90,10 +96,12 @@ mod test { } } - impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, E> for Visitor<E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, i32>> for Visitor<E> where E: Effect<'ctx>, { + type Effect = E; + fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, i32>, @@ -107,8 +115,8 @@ mod test { any_trait! { impl['a, 'ctx, E] Visitor<E> = [ - dyn Value<'a, 'ctx, OwnedStatic<i32>, E> + 'a, - dyn Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<i32>, Effect = E> + 'a, + dyn Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, Effect = E> + 'a, ] where E: Effect<'ctx>, } @@ -116,7 +124,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, OwnedStatic<i32>, Blocking>>() + .upcast_mut::<dyn Value<'_, '_, OwnedStatic<i32>, Effect = Blocking>>() .unwrap() .visit(OwnedStatic(42)), ); @@ -126,7 +134,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, i32>, Blocking>>() + .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, i32>, Effect = Blocking>>() .unwrap() .visit(BorrowedStatic(&101)), ); @@ -138,10 +146,12 @@ mod test { fn visit_borrowed() { struct Visitor<'ctx, E>(Option<&'ctx mut String>, PhantomData<fn() -> E>); - impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, E> for Visitor<'ctx, E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>> for Visitor<'ctx, E> where E: Effect<'ctx>, { + type Effect = E; + fn visit( &'a mut self, BorrowedMutStatic(value): BorrowedMutStatic<'ctx, String>, @@ -156,7 +166,7 @@ mod test { any_trait! { impl['a, 'ctx, E] Visitor<'ctx, E> = [ - dyn Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, E> + 'a, + dyn Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, Effect = E> + 'a, ] where E: Effect<'ctx> } @@ -166,7 +176,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, _, Blocking>>() + .upcast_mut::<dyn Value<'_, '_, _, Effect = Blocking>>() .unwrap() .visit(BorrowedMutStatic(&mut y)), ); @@ -179,10 +189,12 @@ mod test { fn visit_borrowed_unsized() { struct Visitor<'ctx, E>(Option<&'ctx str>, PhantomData<fn() -> E>); - impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> for Visitor<'ctx, E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, str>> for Visitor<'ctx, E> where E: Effect<'ctx>, { + type Effect = E; + fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, str>, @@ -196,7 +208,7 @@ mod test { any_trait! { impl['a, 'ctx, E] Visitor<'ctx, E> = [ - dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> + 'a, + dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, Effect = E> + 'a, ] where E: Effect<'ctx> } @@ -206,7 +218,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, str>, Blocking> + '_>() + .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, str>, Effect = Blocking> + '_>() .unwrap() .visit(BorrowedStatic(&y)), ); diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs index 2d723e4..52da09b 100644 --- a/src/protocol/walker/hint.rs +++ b/src/protocol/walker/hint.rs @@ -31,11 +31,9 @@ pub trait HintMeta<'ctx> { pub type Known<'a, 'ctx, Protocol> = AnySend::T<'a, 'ctx, <Protocol as HintMeta<'ctx>>::Known>; /// Object implementing the [`Hint`] protocol. -pub trait Hint<'ctx, Protocol: ?Sized + HintMeta<'ctx>, E> -where - E: Effect<'ctx>, - E: for<'a> Effect<'ctx>, -{ +pub trait Hint<'ctx, Protocol: ?Sized + HintMeta<'ctx>> { + type Effect: Effect<'ctx>; + /// Hint to the walker to use the `P` protocol. /// /// This should only be called once per [`RequestHint`]. @@ -43,25 +41,25 @@ where &'a mut self, visitor: Visitor<'a, 'ctx>, hint: <Protocol as HintMeta<'ctx>>::Hint, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>; /// Ask the walker for information about it's support of the protocol. fn known<'a>( &'a mut self, hint: &'a <Protocol as HintMeta<'ctx>>::Hint, - ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Protocol>>, E>; + ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Protocol>>, Self::Effect>; } nameable! { pub struct Name['a, 'ctx, Protocol, E]; - impl [Protocol::Name, E] for dyn Hint<'ctx, Protocol, E> + 'a where { + impl [Protocol::Name, E] for dyn Hint<'ctx, Protocol, Effect = E> + 'a where { Protocol: TypeNameable<'a, 'ctx> + ?Sized, E: Effect<'ctx>, 'ctx: 'a, } - impl [Protocol, E] where dyn Hint<'ctx, Protocol::Nameable, E> + 'a { + impl [Protocol, E] where dyn Hint<'ctx, Protocol::Nameable, Effect = E> + 'a { Protocol: TypeName<'a, 'ctx> + ?Sized, E: Effect<'ctx>, 'ctx: 'a, @@ -92,23 +90,22 @@ mod test { impl for Y where {} } - impl<'ctx, E> Hint<'ctx, Y, E> for X<'ctx> - where - E: Effect<'ctx>, - { + impl<'ctx> Hint<'ctx, Y> for X<'ctx> { + type Effect = Blocking; + fn hint<'a>( &'a mut self, _visitor: Visitor<'a, 'ctx>, _hint: <Y as HintMeta<'ctx>>::Hint, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> { todo!() } fn known<'a>( &'a mut self, _hint: &'a <Y as HintMeta<'ctx>>::Hint, - ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Y>>, E> { - E::wrap(async { ControlFlow::Continue(&mut *self.0) }) + ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Y>>, Self::Effect> { + Self::Effect::wrap(async { ControlFlow::Continue(&mut *self.0) }) } } @@ -124,7 +121,7 @@ mod test { let mut z = 42; let mut x = X(&mut z); - let y: &mut dyn Hint<'_, Y, Blocking> = &mut x; + let y: &mut dyn Hint<'_, Y, Effect = Blocking> = &mut x; fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(_x: &T) {} id(y); diff --git a/src/symbol.rs b/src/symbol.rs index 7e1ee46..e5d984f 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -65,6 +65,7 @@ impl Symbol { /// is too complex to store in the symbol then a /// [`EncodeError::TooComplex`] error is returned. If this happens try using /// a shorter tag and/or remove capitals and numbers. + #[inline] pub const fn try_new(tag: &str) -> Result<Self, EncodeError<'_>> { match encode(tag) { Ok(tag) => Ok(Self(tag)), @@ -84,6 +85,7 @@ impl Symbol { /// type OtherType = MyType<{ Symbol::new("OtherType").to_int() }>; /// # let _: OtherType; /// ``` + #[inline] pub const fn to_int(self) -> u64 { self.0 } @@ -97,6 +99,7 @@ impl Symbol { /// [`Self::to_int()`] is provided then the Symbol will likely display /// as a random string when calling [`Display::fmt()`][core::fmt::Display::fmt] /// or [`Debug::fmt()`][core::fmt::Debug::fmt]. + #[inline] pub const fn from_int(value: u64) -> Self { Self(value) } @@ -104,6 +107,7 @@ impl Symbol { /// Const form of [`PartialEq::eq()`]. /// /// Checking for equality via [`Self::to_int()`] is also possible. + #[inline] pub const fn eq(self, other: Self) -> bool { self.0 == other.0 } diff --git a/src/walk.rs b/src/walk.rs index f0c5c65..a119965 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,5 +1,7 @@ pub mod walkers; +use core::ops::ControlFlow; + use crate::{ effect::{Effect, Future}, protocol::Visitor, @@ -8,7 +10,12 @@ use crate::{ /// A type that can be walked. pub trait Walk<'ctx>: WalkerTypes<'ctx> + Sized { /// The walker for the type. - type Walker<E: Effect<'ctx>>: Walker<'ctx, Error = Self::Error, Output = Self::Output, Effect = E>; + type Walker<E: Effect<'ctx>>: Walker< + 'ctx, + Error = Self::Error, + Output = Self::Output, + Effect = E, + >; fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E>; } @@ -44,3 +51,74 @@ pub trait Walker<'ctx>: WalkerTypes<'ctx> + Send { where Self: 'a; } + +pub trait DynWalker<'ctx>: Send { + type Effect: Effect<'ctx>; + + fn walk<'a>( + &'a mut self, + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a; +} + +enum DynWalkerState<'ctx, W: WalkerTypes<'ctx>> { + Walking, + Pending(W), + Done(Result<W::Output, W::Error>), +} + +pub enum DynWalkerError<'ctx, W: WalkerTypes<'ctx>> { + NeverWalked(W), + + /// This can only happen if a panic happens furing the walk and is then caught before calling + /// finish.. + WalkNeverFinished, + + Walker(W::Error), +} + +pub struct DynWalkerAdapter<'ctx, W: WalkerTypes<'ctx>> { + state: DynWalkerState<'ctx, W>, +} + +impl<'ctx, W: WalkerTypes<'ctx>> DynWalkerAdapter<'ctx, W> { + pub fn new(walker: W) -> Self { + Self { + state: DynWalkerState::Pending(walker), + } + } + + pub fn finish(self) -> Result<W::Output, DynWalkerError<'ctx, W>> { + match self.state { + DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished), + DynWalkerState::Pending(walker) => Err(DynWalkerError::NeverWalked(walker)), + DynWalkerState::Done(result) => result.map_err(DynWalkerError::Walker), + } + } +} + +impl<'ctx, W: Walker<'ctx>> DynWalker<'ctx> for DynWalkerAdapter<'ctx, W> { + type Effect = W::Effect; + + fn walk<'a>( + &'a mut self, + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a, + { + Self::Effect::wrap(async { + if let DynWalkerState::Pending(walker) = + core::mem::replace(&mut self.state, DynWalkerState::Walking) + { + // Walk the walker. + self.state = DynWalkerState::Done(walker.walk(visitor).await); + } else { + // Can't do anything if the walker has already been walked. + } + ControlFlow::Continue(()) + }) + } +} diff --git a/src/walk/walkers/core.rs b/src/walk/walkers/core.rs index 6e4822f..734a5c6 100644 --- a/src/walk/walkers/core.rs +++ b/src/walk/walkers/core.rs @@ -1,2 +1,4 @@ // pub mod array; pub mod bool; + +pub mod tag; diff --git a/src/walk/walkers/core/bool.rs b/src/walk/walkers/core/bool.rs index b61f75b..171d016 100644 --- a/src/walk/walkers/core/bool.rs +++ b/src/walk/walkers/core/bool.rs @@ -44,7 +44,7 @@ impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for Walker<E> { { E::wrap(async move { if let Some(object) = - visitor.upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<bool>, E> + '_>() + visitor.upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<bool>, Effect = E> + '_>() { object.visit(OwnedStatic(self.0)).await; } diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs new file mode 100644 index 0000000..5049b86 --- /dev/null +++ b/src/walk/walkers/core/tag.rs @@ -0,0 +1,89 @@ +use core::{any::TypeId, marker::PhantomData}; + +use crate::{ + any::static_wrapper::OwnedStatic, effect::Effect, protocol::visitor::value::Value, WalkerTypes, +}; + +pub struct NameWalker<E>(&'static str, PhantomData<fn() -> E>); + +impl<E> NameWalker<E> { + pub fn new(name: &'static str) -> Self { + Self(name, PhantomData) + } +} + +pub struct MissingProtocol(pub &'static str); + +impl<'ctx, E> WalkerTypes<'ctx> for NameWalker<E> { + type Error = MissingProtocol; + + type Output = (); +} + +impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NameWalker<E> { + type Effect = E; + + fn walk<'a>( + self, + visitor: crate::protocol::Visitor<'a, 'ctx>, + ) -> crate::effect::Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + where + Self: 'a, + { + E::wrap(async { + // We don't need to request a hint because we always just visit a static string. + if let Some(object) = visitor + .upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<&'static str>, Effect = E> + '_>() + { + // Visit with the name. + object.visit(OwnedStatic(self.0)).await; + + Ok(()) + } else { + Err(MissingProtocol( + "visitor missing protocol Value<&'static str>", + )) + } + }) + } +} + +pub struct TypeIdWalker<E>(TypeId, PhantomData<fn() -> E>); + +impl<E> TypeIdWalker<E> { + pub fn new<T: 'static>() -> Self { + Self(TypeId::of::<T>(), PhantomData) + } +} + +impl<'ctx, E> WalkerTypes<'ctx> for TypeIdWalker<E> { + type Error = MissingProtocol; + + type Output = (); +} + +impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for TypeIdWalker<E> { + type Effect = E; + + fn walk<'a>( + self, + visitor: crate::protocol::Visitor<'a, 'ctx>, + ) -> crate::effect::Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + where + Self: 'a, + { + E::wrap(async move { + // We don't need to request a hint because we always just visit a static string. + if let Some(object) = + visitor.upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<TypeId>, Effect = E> + '_>() + { + // Visit with the name. + object.visit(OwnedStatic(self.0)).await; + + Ok(()) + } else { + Err(MissingProtocol("visitor missing protocol Value<TypeId>")) + } + }) + } +} diff --git a/tests/hook.rs b/tests/hook.rs index ebdf728..1cb633a 100644 --- a/tests/hook.rs +++ b/tests/hook.rs @@ -2,10 +2,11 @@ use std::{marker::PhantomData, ops::ControlFlow, pin::Pin, thread::yield_now, ti use treaty::{ any::{any_trait, static_wrapper::OwnedStatic, AnyTrait, IndirectLtAny, LtTypeId}, + builders::core::option::IgnoreMissing, effect::{BlockOn, Blocking, Effect, Future, Spin}, protocol::visitor::value::Value, protocol::Visitor, - transform, Build, Builder, Walk, Walker, builders::core::option::IgnoreMissing, WalkerTypes, + transform, Build, Builder, Walk, Walker, WalkerTypes, }; #[test] @@ -17,7 +18,10 @@ fn demo() { // let x = build_with::<<bool as Build<_>>::Builder, _>(hook).unwrap(); // dbg!(x); // let x = Spin::block_on(transform::<<Option<bool> as Build>::Builder<_>, _, Blocking>(IgnoreMissing::No, hook)); - let x = Spin::block_on(transform::<<bool as Build>::Builder<_>, _, Blocking>((), hook)); + let x = Spin::block_on(transform::<<bool as Build>::Builder<_>, _, Blocking>( + (), + hook, + )); dbg!(x); todo!(); } @@ -110,12 +114,14 @@ impl<'b, 'ctx: 'b, E: Effect<'ctx>> AnyTrait<'ctx> for VisitorHook<'b, 'ctx, E> id => { // println!("fallback: {:?}", id); self.inner.upcast_to_id_mut(id) - }, + } } } } -impl<'a, 'b, 'ctx: 'a + 'b, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for VisitorHook<'b, 'ctx, E> { +impl<'a, 'b, 'ctx: 'a + 'b, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> + for VisitorHook<'b, 'ctx, E> +{ #[inline] fn visit( &'a mut self, |