updated how the tag walkers are setup
Konnor Andrews 2024-04-08
parent 821b0b2 · commit b8a516e
-rw-r--r--src/build.rs6
-rw-r--r--src/build/builders/core/bool.rs4
-rw-r--r--src/build/builders/debug.rs107
-rw-r--r--src/effect.rs37
-rw-r--r--src/lib.rs153
-rw-r--r--src/macros.rs120
-rw-r--r--src/protocol/visitor/sequence.rs32
-rw-r--r--src/protocol/visitor/tag.rs25
-rw-r--r--src/walk.rs34
-rw-r--r--src/walk/walkers/core/bool.rs4
-rw-r--r--src/walk/walkers/core/tag.rs234
11 files changed, 561 insertions, 195 deletions
diff --git a/src/build.rs b/src/build.rs
index ab408e8..5a6b526 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -6,7 +6,7 @@ use crate::{
};
/// A buildable type.
-pub trait Build<'ctx>: BuilderTypes<'ctx, Value = Self> + Send {
+pub trait Build<'ctx>: BuilderTypes<Value = Self> + Send {
/// The builder that can be used to build a value of `Self`.
type Builder<E: Effect<'ctx>>: Builder<
'ctx,
@@ -17,7 +17,7 @@ pub trait Build<'ctx>: BuilderTypes<'ctx, Value = Self> + Send {
>;
}
-pub trait BuilderTypes<'ctx> {
+pub trait BuilderTypes {
type Seed: Send;
/// Error that can happen during filling the builder with data.
@@ -40,7 +40,7 @@ pub trait BuilderTypes<'ctx> {
/// the builder with data from it's walk.
/// - Call [`Self::build()`] to finish building the value and get any errors
/// that happened during filling it with data.
-pub trait Builder<'ctx>: BuilderTypes<'ctx> + Sized + Send {
+pub trait Builder<'ctx>: BuilderTypes + Sized + Send {
type Effect: Effect<'ctx>;
fn from_seed<'a>(seed: Self::Seed) -> Future<'a, 'ctx, Self, Self::Effect>
diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs
index 3dbede2..241f1e4 100644
--- a/src/build/builders/core/bool.rs
+++ b/src/build/builders/core/bool.rs
@@ -18,7 +18,7 @@ pub enum Error {
pub struct Builder<E>(Option<bool>, PhantomData<fn() -> E>);
-impl<'ctx> crate::BuilderTypes<'ctx> for bool {
+impl crate::BuilderTypes for bool {
type Seed = ();
type Error = Error;
@@ -26,7 +26,7 @@ impl<'ctx> crate::BuilderTypes<'ctx> for bool {
type Value = bool;
}
-impl<'ctx, E: Effect<'ctx>> crate::BuilderTypes<'ctx> for Builder<E> {
+impl<E> crate::BuilderTypes for Builder<E> {
type Error = Error;
type Value = bool;
diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs
index 7cf0aad..3bc9e94 100644
--- a/src/build/builders/debug.rs
+++ b/src/build/builders/debug.rs
@@ -4,21 +4,28 @@ use crate::{
any::{static_wrapper::OwnedStatic, LtTypeId},
any_trait,
effect::{Effect, Future},
- protocol::{visitor::{
- tag::{Dyn, Tag},
- value::Value, request_hint::RequestHint,
- }, self},
- DynWalker,
+ never::Never,
+ protocol::{
+ self,
+ visitor::{
+ request_hint::RequestHint,
+ tag::{Dyn, Tag, DynTag},
+ value::Value, sequence::{DynSequence, Sequence, SequenceFlow},
+ },
+ },
+ DynWalker, Flow,
};
-pub struct Walker<E>(usize, PhantomData<fn() -> E>);
+pub struct Visitor<E>(usize, PhantomData<fn() -> E>);
any_trait! {
- impl['a, 'ctx, E] Walker<E> = [
+ impl['a, 'ctx, E] Visitor<E> = [
dyn RequestHint<'ctx, Effect = E> + 'a,
- dyn Tag<'ctx, Dyn, Effect = E> + 'a,
+ DynTag<'a, 'ctx, Dyn, E>,
dyn Value<'a, 'ctx, OwnedStatic<&'static str>, Effect = E> + 'a,
dyn Value<'a, 'ctx, OwnedStatic<TypeId>, Effect = E> + 'a,
+ dyn Value<'a, 'ctx, OwnedStatic<usize>, Effect = E> + 'a,
+ DynSequence<'a, 'ctx, E>,
] else fallback where E: Effect<'ctx>
}
@@ -26,7 +33,7 @@ fn fallback(id: LtTypeId<'_>) {
println!("Unknown trait: {}", id);
}
-impl<'ctx, E: Effect<'ctx>> Walker<E> {
+impl<'ctx, E: Effect<'ctx>> Visitor<E> {
pub fn new() -> Self {
Self(0, PhantomData)
}
@@ -38,7 +45,7 @@ impl<'ctx, E: Effect<'ctx>> Walker<E> {
}
}
-impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx> for Walker<E> {
+impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx> for Visitor<E> {
type Effect = E;
fn request_hint<'a>(
@@ -46,7 +53,7 @@ impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx> for Walker<E> {
_walker: crate::protocol::Walker<'a, 'ctx>,
) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>
where
- Self: 'a
+ Self: 'a,
{
self.tab();
println!("Visit request hint (no hint given)");
@@ -54,14 +61,14 @@ impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx> for Walker<E> {
}
}
-impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn> for Walker<E> {
+impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn> for Visitor<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>
+ walker: DynWalker<'a, 'ctx, Self::Effect>,
+ ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect>
where
Self: 'a,
{
@@ -73,29 +80,89 @@ impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn> for Walker<E> {
let result = walker.walk(self).await;
self.0 -= 1;
match result {
- ControlFlow::Continue(()) => ControlFlow::Continue(protocol::visitor::tag::Status::Walked),
- ControlFlow::Break(()) => ControlFlow::Break(()),
+ ControlFlow::Continue(()) => Flow::Continue,
+ ControlFlow::Break(()) => Flow::Break,
}
})
}
}
-impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>> for Walker<E> {
+impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>> for Visitor<E> {
type Effect = E;
- fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<&'static str>) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> where Self: 'a {
+ 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> {
+impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<usize>> for Visitor<E> {
+ type Effect = E;
+
+ fn visit(
+ &'a mut self,
+ OwnedStatic(value): OwnedStatic<usize>,
+ ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>
+ where
+ Self: 'a,
+ {
+ self.tab();
+ println!("Visit usize: {}", value);
+ E::wrap(async { ControlFlow::Continue(()) })
+ }
+}
+
+impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<TypeId>> for Visitor<E> {
type Effect = E;
- fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<TypeId>) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> where Self: 'a {
+ 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(()) })
}
}
+
+impl<'ctx, E: Effect<'ctx>> Sequence<'ctx> for Visitor<E> {
+ type Effect = E;
+
+ fn visit<'a>(
+ &'a mut self,
+ scope: protocol::visitor::sequence::DynSequenceScope<'a, 'ctx, Self::Effect>,
+ ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect> {
+ self.tab();
+ E::wrap(async {
+ println!("Visit sequence, size hint: {:?}", scope.size_hint().await);
+ self.0 += 1;
+ let flow = loop {
+ self.tab();
+ println!("Calling next");
+ self.0 += 1;
+ match scope.next(self).await {
+ SequenceFlow::Done => {
+ self.tab();
+ println!("Sequence done");
+ break Flow::Continue
+ },
+ SequenceFlow::Continue => {},
+ SequenceFlow::Break => break Flow::Break,
+ }
+ self.0 -= 1;
+ };
+ self.0 -= 2;
+ flow
+ })
+ }
+}
diff --git a/src/effect.rs b/src/effect.rs
index bb54166..ebf082e 100644
--- a/src/effect.rs
+++ b/src/effect.rs
@@ -26,6 +26,8 @@ pub trait Effect<'ctx>: 'static {
F: core::future::Future + Send + 'a,
<F as core::future::Future>::Output: Send;
+ fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, 'ctx, Self::Future<T>, T>;
+
#[cfg(feature = "alloc")]
#[inline]
fn wrap_boxed<'a, F>(
@@ -108,6 +110,31 @@ impl<'ctx, B: BlockOn> Effect<'ctx> for Blocking<B> {
{
core::future::ready(B::block_on(future))
}
+
+ fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, 'ctx, Self::Future<T>, T> {
+ core::future::ready(value)
+ }
+}
+
+mod sealed {
+ pub enum BoxedFuture<'lt, Output> {
+ Box(core::pin::Pin<Box<dyn core::future::Future<Output = Output> + Send + 'lt>>),
+ Ready(core::future::Ready<Output>),
+ }
+
+ impl<'lt, Output> core::future::Future for BoxedFuture<'lt, Output> {
+ type Output = Output;
+
+ fn poll(
+ mut self: core::pin::Pin<&mut Self>,
+ cx: &mut core::task::Context<'_>,
+ ) -> core::task::Poll<Self::Output> {
+ match &mut *self {
+ BoxedFuture::Box(future) => future.as_mut().poll(cx),
+ BoxedFuture::Ready(future) => core::pin::Pin::new(future).poll(cx),
+ }
+ }
+ }
}
#[cfg(feature = "alloc")]
@@ -115,7 +142,7 @@ higher_ranked_type! {
pub type BoxFuture['ctx, Output]: (SendFuture)[Output]
where {
Output: Send,
- } = for<'lt> core::pin::Pin<Box<dyn core::future::Future<Output = Output> + Send + 'lt>>
+ } = for<'lt> sealed::BoxedFuture<'lt, Output>
}
#[cfg(feature = "alloc")]
@@ -130,7 +157,7 @@ impl<'ctx> Effect<'ctx> for Async {
F: core::future::Future + Send + 'a,
<F as core::future::Future>::Output: Send,
{
- Box::pin(future)
+ sealed::BoxedFuture::Box(Box::pin(future))
}
fn wrap_boxed<'a, F>(
@@ -140,6 +167,10 @@ impl<'ctx> Effect<'ctx> for Async {
F: core::future::Future + Send + 'a,
<F as core::future::Future>::Output: Send,
{
- future
+ sealed::BoxedFuture::Box(future)
+ }
+
+ fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, 'ctx, Self::Future<T>, T> {
+ sealed::BoxedFuture::Ready(core::future::ready(value))
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 753ac7c..03b2e0d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,11 +28,15 @@ use core::ops::ControlFlow;
pub use build::*;
use effect::{Effect, Future};
+use macros::TagError;
use protocol::Visitor;
use symbol::Symbol;
pub use transform::*;
pub use walk::*;
+// #[doc(hidden)]
+pub mod macros;
+
pub mod never {
mod sealed {
pub trait Extract {
@@ -52,10 +56,26 @@ 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");
+pub const TAG_SEQ_INDEX: Symbol = Symbol::new("Seq Index");
+pub const TAG_SEQ_LEN: Symbol = Symbol::new("Seq Length");
+pub const TAG_STRUCT: Symbol = Symbol::new("Struct");
+pub const TAG_ENUM: Symbol = Symbol::new("Enum");
#[derive(Debug)]
pub enum StructWalkError {
- Tag(Symbol, &'static str),
+ Tag(TagError),
+}
+
+#[must_use]
+pub enum Flow<Error> {
+ /// Processing should continue as normal.
+ Continue,
+
+ /// Processing should stop, but there is no direct error to report.
+ Break,
+
+ /// Processing should stop with this error.
+ Err(Error),
}
#[macro_export]
@@ -78,7 +98,7 @@ macro_rules! Walk {
}
}
- impl<'ctx> $crate::WalkerTypes<'ctx> for &'ctx $name {
+ impl<'ctx> $crate::WalkerTypes for &'ctx $name {
type Error = $crate::StructWalkError;
type Output = ();
}
@@ -88,7 +108,7 @@ macro_rules! Walk {
_marker: ::core::marker::PhantomData<fn() -> E>,
}
- impl<'ctx, E> $crate::WalkerTypes<'ctx> for Walker<'ctx, E> {
+ impl<'ctx, E> $crate::WalkerTypes for Walker<'ctx, E> {
type Error = $crate::StructWalkError;
type Output = ();
}
@@ -126,52 +146,42 @@ macro_rules! Walk {
// - Tagged: struct field names
// - Sequence: the fields
- 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"))
- },
- }
+ match $crate::macros::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>(
+ visitor,
+ $crate::walkers::core::tag::NoopWalker::new()
+ ).await {
+ $crate::Flow::Continue => {},
+ $crate::Flow::Break => return Ok(()),
+ $crate::Flow::Err(_) => unreachable!(),
+ }
- if let ::core::ops::ControlFlow::Break(()) = flow {
- return Ok(());
- }
+ match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>(
+ visitor,
+ $crate::walkers::core::tag::ValueWalker::new(stringify!($name))
+ ).await {
+ $crate::Flow::Continue => {},
+ $crate::Flow::Break => return Ok(()),
+ $crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)),
}
- 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"))
- },
- }
+ match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>(
+ visitor,
+ $crate::walkers::core::tag::ValueWalker::new(::core::any::TypeId::of::<$name>())
+ ).await {
+ $crate::Flow::Continue => {},
+ $crate::Flow::Break => return Ok(()),
+ $crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)),
+ }
- if let ::core::ops::ControlFlow::Break(()) = flow {
- return Ok(());
- }
+ match $crate::macros::visit_tag::<{ $crate::TAG_FIELD_NAMES.to_int() }, E, _>(
+ visitor,
+ $crate::walkers::core::tag::NamesWalker::new(&[$(
+ stringify!($field)
+ ),*])
+ ).await {
+ $crate::Flow::Continue => {},
+ $crate::Flow::Break => return Ok(()),
+ $crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)),
}
todo!()
@@ -189,57 +199,6 @@ macro_rules! Walk {
};
}
-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};
@@ -258,7 +217,7 @@ mod test {
let value = Demo { a: true, b: false };
let walker = value.into_walker::<Blocking>();
- let mut visitor = builders::debug::Walker::<Blocking>::new();
+ let mut visitor = builders::debug::Visitor::<Blocking>::new();
dbg!(Spin::block_on(walker.walk(&mut visitor)));
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..a946257
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,120 @@
+use crate::{
+ effect::{Effect, Future},
+ protocol::{
+ visitor::tag::{self, DynTag},
+ Visitor,
+ },
+ symbol::Symbol,
+ DynWalkerAdapter, DynWalkerError, Flow, Walker, WalkerTypes,
+};
+
+#[derive(Debug)]
+pub struct TagError {
+ symbol: Symbol,
+ msg: &'static str,
+}
+
+impl From<TagError> for &'static str {
+ fn from(value: TagError) -> Self {
+ value.msg
+ }
+}
+
+impl TagError {
+ fn new<const SYMBOL: u64>(msg: &'static str) -> Self {
+ Self {
+ symbol: Symbol::from_int(SYMBOL),
+ msg,
+ }
+ }
+
+ fn never_walked<const SYMBOL: u64>() -> Self {
+ Self::new::<SYMBOL>("visitor did not walk the walker")
+ }
+
+ fn walk_never_finished<const SYMBOL: u64>() -> Self {
+ Self::new::<SYMBOL>("walk did not finish")
+ }
+}
+
+pub fn visit_tag<
+ 'a,
+ 'ctx: 'a,
+ const SYMBOL: u64,
+ E: Effect<'ctx>,
+ W: Walker<'ctx, Effect = E> + 'a,
+>(
+ visitor: Visitor<'a, 'ctx>,
+ walker: W,
+) -> Future<'a, 'ctx, Flow<TagError>, E>
+where
+ W: WalkerTypes<Output = ()>,
+ <W as WalkerTypes>::Error: Into<&'static str>,
+{
+ E::wrap(async {
+ let result =
+ if let Some(object) = visitor.upcast_mut::<DynTag<'_, 'ctx, tag::Const<SYMBOL>, E>>() {
+ // The visitor knows about this tag at compile time.
+
+ // Wrap the walker to allow it to be passed to a dyn walker argument.
+ let mut name_walker = DynWalkerAdapter::new(walker);
+
+ // Visit the tag.
+ let flow = object.visit(tag::Const, &mut name_walker).await;
+
+ // Finish the dynamic walker to get any errors from it.
+ let result = name_walker.finish();
+
+ Some((flow, result))
+ } else if let Some(object) = visitor.upcast_mut::<DynTag<'_, 'ctx, tag::Dyn, E>>() {
+ // The visitor can handle dynamic tags.
+ // If the visitor can't handle the tag kind then it can call .skip on the walker
+ // to disable the error for not walking it.
+
+ // Wrap the walker to allow it to be passed to a dyn walker argument.
+ let mut name_walker = DynWalkerAdapter::new(walker);
+
+ // Visit the tag.
+ let flow = object
+ .visit(tag::Dyn(Symbol::from_int(SYMBOL)), &mut name_walker)
+ .await;
+
+ // Finish the dynamic walker to get any errors from it.
+ let result = name_walker.finish();
+
+ Some((flow, result))
+ } else {
+ None
+ };
+
+ let Some(result) = result else {
+ // The visitor doesn't know about this tag protocol so just continue as normal.
+ return Flow::Continue;
+ };
+
+ match result {
+ // The happy path.
+ (Flow::Continue, Ok(_)) => Flow::Continue,
+
+ // The visitor wants to stop the control flow for some reason.
+ (Flow::Break, Ok(_)) => Flow::Break,
+
+ // The walker had an error.
+ (_, Err(DynWalkerError::Walker(err))) => Flow::Err(TagError::new::<SYMBOL>(err.into())),
+
+ // The visitor never walked the dynamic walker. Aka it didn't call walk.
+ (_, Err(DynWalkerError::NeverWalked(_))) => {
+ Flow::Err(TagError::never_walked::<SYMBOL>())
+ }
+
+ // This is very hard to cause. The visitor must panic inside of .walk but then
+ // catch it in .visit.
+ (_, Err(DynWalkerError::WalkNeverFinished)) => {
+ Flow::Err(TagError::walk_never_finished::<SYMBOL>())
+ }
+
+ // This isn't possible because Err(!).
+ (Flow::Err(_), _) => unreachable!(),
+ }
+ })
+}
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index e9dd721..a3ca785 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -5,7 +5,7 @@ use crate::{
higher_ranked_type,
hkt::AnySend,
nameable,
- protocol::{walker::hint::HintMeta, Visitor},
+ protocol::{walker::hint::HintMeta, Visitor}, Flow, never::Never,
};
pub trait Sequence<'ctx> {
@@ -13,38 +13,46 @@ pub trait Sequence<'ctx> {
fn visit<'a>(
&'a mut self,
- scope: &'a mut dyn SequenceScope<'ctx, Self::Effect>,
- ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>;
+ scope: DynSequenceScope<'a, 'ctx, Self::Effect>,
+ ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect>;
}
+pub type DynSequence<'a, 'ctx, E> = dyn Sequence<'ctx, Effect = E> + Send + 'a;
+
nameable! {
pub struct Name['a, 'ctx, E];
- impl [E] for dyn Sequence<'ctx, Effect = E> + 'a where {
+ impl [E] for DynSequence<'a, 'ctx, E> where {
E: Effect<'ctx>,
'ctx: 'a
}
- impl [E] where dyn Sequence<'ctx, Effect = E> + 'a {
+ impl [E] where DynSequence<'a, 'ctx, E> {
E: Effect<'ctx>,
'ctx: 'a
}
}
-pub trait SequenceScope<'ctx, E>
-where
- E: Effect<'ctx>,
-{
+pub trait SequenceScope<'ctx> {
+ type Effect: Effect<'ctx>;
+
+ fn size_hint<'a>(
+ &'a mut self,
+ ) -> Future<'a, 'ctx, (usize, Option<usize>), Self::Effect>;
+
fn next<'a>(
&'a mut self,
visitor: Visitor<'a, 'ctx>,
- ) -> Future<'a, 'ctx, ControlFlow<(), Status>, E>;
+ ) -> Future<'a, 'ctx, SequenceFlow, Self::Effect>;
}
+pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, Effect = E> + Send + 'a);
+
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
-pub enum Status {
+pub enum SequenceFlow {
Done,
Continue,
+ Break,
}
higher_ranked_type! {
@@ -60,7 +68,7 @@ pub struct Hint {
pub len: (usize, Option<usize>),
}
-impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for dyn Sequence<'ctx, Effect = E> + '_ {
+impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for DynSequence<'a, 'ctx, E> {
type Known = KnownHkt<'ctx>;
type Hint = Hint;
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index 974c47b..0ac6e5b 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -6,14 +6,13 @@ use crate::{
higher_ranked_type,
hkt::AnySend,
nameable,
+ never::Never,
protocol::{walker::hint::HintMeta, Visitor, Walker},
symbol::Symbol,
- DynWalker,
+ DynWalker, Flow,
};
pub trait Kind: 'static {
- type Status: Send;
-
fn symbol(&self) -> Symbol;
}
@@ -21,16 +20,12 @@ 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
}
@@ -42,28 +37,24 @@ pub trait Tag<'ctx, K: Kind> {
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>
+ walker: DynWalker<'a, 'ctx, Self::Effect>,
+ ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect>
where
Self: 'a;
}
-#[must_use]
-pub enum Status {
- Walked,
- Skiped,
-}
+pub type DynTag<'a, 'ctx, K, E> = dyn Tag<'ctx, K, Effect = E> + Send + 'a;
nameable! {
pub struct Name['a, 'ctx, K, E];
- impl [K, E] for dyn Tag<'ctx, K, Effect = E> + 'a where {
+ impl [K, E] for DynTag<'a, 'ctx, K, E> where {
K: Kind,
E: Effect<'ctx>,
'ctx: 'a
}
- impl [K, E] where dyn Tag<'ctx, K, Effect = E> + 'a {
+ impl [K, E] where DynTag<'a, 'ctx, K, E> {
K: Kind,
E: Effect<'ctx>,
'ctx: 'a
@@ -82,7 +73,7 @@ pub struct Hint<K> {
pub kind: Option<K>,
}
-impl<'a, 'ctx: 'a, K, E> HintMeta<'ctx> for dyn Tag<'ctx, K, Effect = E> + 'a {
+impl<'a, 'ctx: 'a, K, E> HintMeta<'ctx> for DynTag<'a, 'ctx, K, E> {
type Known = KnownHkt<'ctx>;
type Hint = Hint<K>;
diff --git a/src/walk.rs b/src/walk.rs
index a119965..32232fd 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -8,7 +8,7 @@ use crate::{
};
/// A type that can be walked.
-pub trait Walk<'ctx>: WalkerTypes<'ctx> + Sized {
+pub trait Walk<'ctx>: WalkerTypes + Sized {
/// The walker for the type.
type Walker<E: Effect<'ctx>>: Walker<
'ctx,
@@ -20,7 +20,7 @@ pub trait Walk<'ctx>: WalkerTypes<'ctx> + Sized {
fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E>;
}
-pub trait WalkerTypes<'ctx> {
+pub trait WalkerTypes {
type Error: Send;
/// An arbitrary type the walker is left with after walking.
@@ -38,7 +38,7 @@ pub trait WalkerTypes<'ctx> {
/// - Call [From::from()] with a value to be walked to make a walker.
/// - Call [Self::walk()] to walk the value. Data will be sent to the provided
/// visitor.
-pub trait Walker<'ctx>: WalkerTypes<'ctx> + Send {
+pub trait Walker<'ctx>: WalkerTypes + Send {
type Effect: Effect<'ctx>;
/// Walk the value.
@@ -52,7 +52,7 @@ pub trait Walker<'ctx>: WalkerTypes<'ctx> + Send {
Self: 'a;
}
-pub trait DynWalker<'ctx>: Send {
+pub trait WalkerObjSafe<'ctx>: Send {
type Effect: Effect<'ctx>;
fn walk<'a>(
@@ -61,15 +61,20 @@ pub trait DynWalker<'ctx>: Send {
) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>
where
Self: 'a;
+
+ fn skip(&mut self);
}
-enum DynWalkerState<'ctx, W: WalkerTypes<'ctx>> {
+pub type DynWalker<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, Effect = E> + Send + 'a);
+
+enum DynWalkerState<W: WalkerTypes> {
+ Skipped,
Walking,
Pending(W),
Done(Result<W::Output, W::Error>),
}
-pub enum DynWalkerError<'ctx, W: WalkerTypes<'ctx>> {
+pub enum DynWalkerError<W: WalkerTypes> {
NeverWalked(W),
/// This can only happen if a panic happens furing the walk and is then caught before calling
@@ -79,27 +84,28 @@ pub enum DynWalkerError<'ctx, W: WalkerTypes<'ctx>> {
Walker(W::Error),
}
-pub struct DynWalkerAdapter<'ctx, W: WalkerTypes<'ctx>> {
- state: DynWalkerState<'ctx, W>,
+pub struct DynWalkerAdapter<W: WalkerTypes> {
+ state: DynWalkerState<W>,
}
-impl<'ctx, W: WalkerTypes<'ctx>> DynWalkerAdapter<'ctx, W> {
+impl<W: WalkerTypes> DynWalkerAdapter<W> {
pub fn new(walker: W) -> Self {
Self {
state: DynWalkerState::Pending(walker),
}
}
- pub fn finish(self) -> Result<W::Output, DynWalkerError<'ctx, W>> {
+ pub fn finish(self) -> Result<Option<W::Output>, DynWalkerError<W>> {
match self.state {
+ DynWalkerState::Skipped => Ok(None),
DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished),
DynWalkerState::Pending(walker) => Err(DynWalkerError::NeverWalked(walker)),
- DynWalkerState::Done(result) => result.map_err(DynWalkerError::Walker),
+ DynWalkerState::Done(result) => result.map(Some).map_err(DynWalkerError::Walker),
}
}
}
-impl<'ctx, W: Walker<'ctx>> DynWalker<'ctx> for DynWalkerAdapter<'ctx, W> {
+impl<'ctx, W: Walker<'ctx>> WalkerObjSafe<'ctx> for DynWalkerAdapter<W> {
type Effect = W::Effect;
fn walk<'a>(
@@ -121,4 +127,8 @@ impl<'ctx, W: Walker<'ctx>> DynWalker<'ctx> for DynWalkerAdapter<'ctx, W> {
ControlFlow::Continue(())
})
}
+
+ fn skip(&mut self) {
+ self.state = DynWalkerState::Skipped;
+ }
}
diff --git a/src/walk/walkers/core/bool.rs b/src/walk/walkers/core/bool.rs
index 171d016..24bb421 100644
--- a/src/walk/walkers/core/bool.rs
+++ b/src/walk/walkers/core/bool.rs
@@ -20,13 +20,13 @@ impl<'ctx> crate::Walk<'ctx> for bool {
pub struct Walker<E>(bool, PhantomData<fn() -> E>);
-impl<'ctx> crate::WalkerTypes<'ctx> for bool {
+impl crate::WalkerTypes for bool {
type Error = ();
type Output = ();
}
-impl<'ctx, E: Effect<'ctx>> crate::WalkerTypes<'ctx> for Walker<E> {
+impl<E> crate::WalkerTypes for Walker<E> {
type Error = ();
type Output = ();
diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs
index 5049b86..8c40f2d 100644
--- a/src/walk/walkers/core/tag.rs
+++ b/src/walk/walkers/core/tag.rs
@@ -1,26 +1,38 @@
use core::{any::TypeId, marker::PhantomData};
use crate::{
- any::static_wrapper::OwnedStatic, effect::Effect, protocol::visitor::value::Value, WalkerTypes,
+ any::static_wrapper::OwnedStatic,
+ effect::{Effect, Future},
+ protocol::{
+ visitor::{sequence::{DynSequence, SequenceScope, SequenceFlow}, value::Value, tag::DynTag},
+ Visitor,
+ },
+ WalkerTypes, Flow, macros::{visit_tag, TagError}, TAG_FIELD_NAMES, TAG_SEQ_INDEX, never::Never, TAG_SEQ_LEN,
};
-pub struct NameWalker<E>(&'static str, PhantomData<fn() -> E>);
+pub struct ValueWalker<T, E>(T, PhantomData<fn() -> E>);
-impl<E> NameWalker<E> {
- pub fn new(name: &'static str) -> Self {
- Self(name, PhantomData)
+impl<T, E> ValueWalker<T, E> {
+ pub fn new(value: T) -> Self {
+ Self(value, PhantomData)
}
}
pub struct MissingProtocol(pub &'static str);
-impl<'ctx, E> WalkerTypes<'ctx> for NameWalker<E> {
+impl From<MissingProtocol> for &'static str {
+ fn from(value: MissingProtocol) -> Self {
+ value.0
+ }
+}
+
+impl<T: Send, E> WalkerTypes for ValueWalker<T, E> {
type Error = MissingProtocol;
type Output = ();
}
-impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NameWalker<E> {
+impl<'ctx, T: Send + 'static, E: Effect<'ctx>> crate::Walker<'ctx> for ValueWalker<T, E> {
type Effect = E;
fn walk<'a>(
@@ -33,7 +45,7 @@ impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NameWalker<E> {
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> + '_>()
+ .upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<T>, Effect = E> + '_>()
{
// Visit with the name.
object.visit(OwnedStatic(self.0)).await;
@@ -41,49 +53,217 @@ impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NameWalker<E> {
Ok(())
} else {
Err(MissingProtocol(
- "visitor missing protocol Value<&'static str>",
+ "visitor missing protocol Value<?>",
))
}
})
}
}
-pub struct TypeIdWalker<E>(TypeId, PhantomData<fn() -> E>);
+pub struct NamesWalker<E> {
+ names: &'static [&'static str],
+ current: usize,
+ error: Option<(usize, WithTagError<MissingProtocol>)>,
+ _marker: PhantomData<fn() -> E>,
+}
-impl<E> TypeIdWalker<E> {
- pub fn new<T: 'static>() -> Self {
- Self(TypeId::of::<T>(), PhantomData)
+impl<E> NamesWalker<E> {
+ pub fn new(names: &'static [&'static str]) -> Self {
+ Self {
+ names,
+ current: 0,
+ error: None,
+ _marker: PhantomData,
+ }
}
}
-impl<'ctx, E> WalkerTypes<'ctx> for TypeIdWalker<E> {
- type Error = MissingProtocol;
+pub enum SequenceError<E, I> {
+ Err(E),
+ Tag(TagError),
+ Item(usize, I),
+}
+
+impl<E: Into<&'static str>, I: Into<&'static str>> From<SequenceError<E, I>> for &'static str {
+ fn from(value: SequenceError<E, I>) -> Self {
+ match value {
+ SequenceError::Err(err) => err.into(),
+ SequenceError::Item(_, err) => err.into(),
+ SequenceError::Tag(err) => err.into(),
+ }
+ }
+}
+
+impl<E> WalkerTypes for NamesWalker<E> {
+ type Error = SequenceError<MissingProtocol, WithTagError<MissingProtocol>>;
type Output = ();
}
-impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for TypeIdWalker<E> {
+impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NamesWalker<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>
+ mut self,
+ visitor: Visitor<'a, 'ctx>,
+ ) -> 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;
+ match visit_tag::<{ TAG_SEQ_LEN.to_int() }, Self::Effect, _>(
+ visitor,
+ ValueWalker::new(self.names.len())
+ ).await {
+ Flow::Continue => {},
+ Flow::Break => return Ok(()),
+ Flow::Err(err) => return Err(SequenceError::Tag(err)),
+ }
- Ok(())
+ // We don't need to request a hint because we always just visit a sequence.
+ if let Some(object) = visitor.upcast_mut::<DynSequence<'_, 'ctx, E>>() {
+ // Visit with the name. Ignore the flow because we return a result not a flow.
+ let _ = object.visit(&mut self).await;
+
+ // Check if any items had errors.
+ match self.error {
+ Some((index, err)) => Err(SequenceError::Item(index, err)),
+ None => Ok(()),
+ }
} else {
- Err(MissingProtocol("visitor missing protocol Value<TypeId>"))
+ Err(SequenceError::Err(MissingProtocol("visitor missing protocol Sequence")))
+ }
+ })
+ }
+}
+
+impl<'ctx, E: Effect<'ctx>> SequenceScope<'ctx> for NamesWalker<E> {
+ type Effect = E;
+
+ fn next<'a>(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ ) -> Future<'a, 'ctx, SequenceFlow, Self::Effect> {
+ if let Some(name) = self.names.get(self.current) {
+ let current = self.current;
+ self.current += 1;
+ E::wrap(async move {
+ match crate::Walker::walk(SeqItemWalker::new(current, ValueWalker::<_, E>::new(*name)), visitor).await {
+ Ok(()) => SequenceFlow::Continue,
+ Err(err) => {
+ self.error = Some((self.current, err));
+ SequenceFlow::Break
+ },
+ }
+ })
+ } else {
+ E::ready(SequenceFlow::Done)
+ }
+ }
+
+ fn size_hint<'a>(
+ &'a mut self,
+ ) -> Future<'a, 'ctx, (usize, Option<usize>), Self::Effect> {
+ E::ready((self.names.len(), Some(self.names.len())))
+ }
+
+}
+
+pub struct SeqItemWalker<W> {
+ walker: W,
+ index: usize,
+}
+
+impl<W> SeqItemWalker<W> {
+ pub fn new(index: usize, walker: W) -> Self {
+ Self {
+ walker,
+ index,
+ }
+ }
+}
+
+pub enum WithTagError<E> {
+ Tag(TagError),
+ Err(E),
+}
+
+impl<E: Into<&'static str>> From<WithTagError<E>> for &'static str {
+ fn from(value: WithTagError<E>) -> Self {
+ match value {
+ WithTagError::Tag(value) => value.into(),
+ WithTagError::Err(value) => value.into(),
+ }
+ }
+}
+
+impl<W: WalkerTypes> WalkerTypes for SeqItemWalker<W> {
+ type Error = WithTagError<W::Error>;
+
+ type Output = ();
+}
+
+impl<'ctx, W: crate::Walker<'ctx> + WalkerTypes<Output = ()>> crate::Walker<'ctx> for SeqItemWalker<W> {
+ type Effect = W::Effect;
+
+ fn walk<'a>(
+ self,
+ visitor: Visitor<'a, 'ctx>,
+ ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect>
+ where
+ Self: 'a,
+ {
+ Self::Effect::wrap(async move {
+ match visit_tag::<{ TAG_SEQ_INDEX.to_int() }, Self::Effect, _>(
+ visitor,
+ ValueWalker::new(self.index)
+ ).await {
+ Flow::Continue => {},
+ Flow::Break => return Ok(()),
+ Flow::Err(err) => return Err(WithTagError::Tag(err)),
}
+
+ self.walker.walk(visitor).await.map_err(WithTagError::Err)
})
}
}
+
+pub struct NoopWalker<E> {
+ _marker: PhantomData<fn() -> E>
+}
+
+impl<E> NoopWalker<E> {
+ pub fn new() -> Self {
+ Self {
+ _marker: PhantomData
+ }
+ }
+}
+
+pub enum NoopError {}
+
+impl From<NoopError> for &'static str {
+ fn from(value: NoopError) -> Self {
+ match value {}
+ }
+}
+
+impl<E> WalkerTypes for NoopWalker<E> {
+ type Error = NoopError;
+
+ type Output = ();
+}
+
+impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NoopWalker<E> {
+ type Effect = E;
+
+ fn walk<'a>(
+ self,
+ _visitor: Visitor<'a, 'ctx>,
+ ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect>
+ where
+ Self: 'a,
+ {
+ E::ready(Ok(()))
+ }
+}