changed how the tag protocol works and start of struct macro
Konnor Andrews 2024-04-07
parent f250905 · commit 821b0b2
-rw-r--r--protocols.md7
-rw-r--r--src/any.rs21
-rw-r--r--src/build.rs8
-rw-r--r--src/build/builders.rs3
-rw-r--r--src/build/builders/core.rs3
-rw-r--r--src/build/builders/core/bool.rs6
-rw-r--r--src/build/builders/core/option.rs21
-rw-r--r--src/build/builders/core/tag_name.rs1
-rw-r--r--src/build/builders/debug.rs101
-rw-r--r--src/lib.rs268
-rw-r--r--src/protocol/visitor.rs2
-rw-r--r--src/protocol/visitor/request_hint.rs12
-rw-r--r--src/protocol/visitor/sequence.rs14
-rw-r--r--src/protocol/visitor/tag.rs89
-rw-r--r--src/protocol/visitor/tagged.rs63
-rw-r--r--src/protocol/visitor/value.rs46
-rw-r--r--src/protocol/walker/hint.rs31
-rw-r--r--src/symbol.rs4
-rw-r--r--src/walk.rs80
-rw-r--r--src/walk/walkers/core.rs2
-rw-r--r--src/walk/walkers/core/bool.rs2
-rw-r--r--src/walk/walkers/core/tag.rs89
-rw-r--r--tests/hook.rs14
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
diff --git a/src/any.rs b/src/any.rs
index 9bddfda..178438f 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -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(()) })
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index fd458fa..753ac7c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,