nesting structs works in the Walk derive macro
| -rw-r--r-- | src/build.rs | 18 | ||||
| -rw-r--r-- | src/build/builders/core/bool.rs | 27 | ||||
| -rw-r--r-- | src/build/builders/debug.rs | 120 | ||||
| -rw-r--r-- | src/effect.rs | 48 | ||||
| -rw-r--r-- | src/lib.rs | 170 | ||||
| -rw-r--r-- | src/macros.rs | 64 | ||||
| -rw-r--r-- | src/protocol/visitor.rs | 11 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 49 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs | 62 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 12 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 96 | ||||
| -rw-r--r-- | src/transform.rs | 8 | ||||
| -rw-r--r-- | src/walk.rs | 66 | ||||
| -rw-r--r-- | src/walk/walkers/core.rs | 2 | ||||
| -rw-r--r-- | src/walk/walkers/core/array.rs | 6 | ||||
| -rw-r--r-- | src/walk/walkers/core/bool.rs | 60 | ||||
| -rw-r--r-- | src/walk/walkers/core/noop.rs | 36 | ||||
| -rw-r--r-- | src/walk/walkers/core/tag.rs | 268 | ||||
| -rw-r--r-- | src/walk/walkers/core/value.rs | 89 |
19 files changed, 651 insertions, 561 deletions
diff --git a/src/build.rs b/src/build.rs index 5a6b526..24232a0 100644 --- a/src/build.rs +++ b/src/build.rs @@ -6,15 +6,9 @@ use crate::{ }; /// A buildable type. -pub trait Build<'ctx>: BuilderTypes<Value = Self> + Send { +pub trait Build<'ctx, M, E: Effect<'ctx>>: BuilderTypes<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: Builder<'ctx, E, Seed = Self::Seed, Error = Self::Error, Value = Self>; } pub trait BuilderTypes { @@ -40,10 +34,8 @@ pub trait BuilderTypes { /// 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 + Sized + Send { - type Effect: Effect<'ctx>; - - fn from_seed<'a>(seed: Self::Seed) -> Future<'a, 'ctx, Self, Self::Effect> +pub trait Builder<'ctx, E: Effect<'ctx>>: BuilderTypes + Sized + Send { + fn from_seed<'a>(seed: Self::Seed) -> Future<'a, 'ctx, Self, E> where Self: 'a; @@ -51,7 +43,7 @@ pub trait Builder<'ctx>: BuilderTypes + Sized + Send { /// /// If an error happened with the builder during the walk /// it will be reported here. - fn build<'a>(self) -> Future<'a, 'ctx, Result<Self::Value, Self::Error>, Self::Effect> + fn build<'a>(self) -> Future<'a, 'ctx, Result<Self::Value, Self::Error>, E> where Self: 'a; diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs index 241f1e4..7a95820 100644 --- a/src/build/builders/core/bool.rs +++ b/src/build/builders/core/bool.rs @@ -4,11 +4,15 @@ use crate::{ any::static_wrapper::OwnedStatic, any_trait, effect::{Effect, Future}, - protocol::{visitor::value::Value, Visitor}, + protocol::{ + visitor::value::{DynValue, Value}, + Visitor, + }, + Flow, }; -impl<'ctx> crate::Build<'ctx> for bool { - type Builder<E: Effect<'ctx>> = Builder<E>; +impl<'ctx, M, E: Effect<'ctx>> crate::Build<'ctx, M, E> for bool { + type Builder = Builder<E>; } #[derive(Debug)] @@ -34,9 +38,7 @@ impl<E> crate::BuilderTypes for Builder<E> { type Seed = (); } -impl<'ctx, E: Effect<'ctx>> crate::Builder<'ctx> for Builder<E> { - type Effect = E; - +impl<'ctx, E: Effect<'ctx>> crate::Builder<'ctx, E> for Builder<E> { #[inline] fn build<'a>(self) -> Future<'a, 'ctx, Result<Self::Value, Self::Error>, E> where @@ -59,19 +61,14 @@ 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>, Effect = E> + 'a, + DynValue<'a, 'ctx, OwnedStatic<bool>, E>, ] where E: Effect<'ctx> } -impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>> for Builder<E> { - type Effect = E; - +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for Builder<E> { #[inline] - fn visit( - &'a mut self, - OwnedStatic(value): OwnedStatic<bool>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<bool>) -> Future<'a, 'ctx, Flow, E> { self.0 = Some(value); - E::wrap(core::future::ready(ControlFlow::Continue(()))) + E::ready(Flow::Continue) } } diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs index 3bc9e94..c8f9324 100644 --- a/src/build/builders/debug.rs +++ b/src/build/builders/debug.rs @@ -8,9 +8,10 @@ use crate::{ protocol::{ self, visitor::{ - request_hint::RequestHint, - tag::{Dyn, Tag, DynTag}, - value::Value, sequence::{DynSequence, Sequence, SequenceFlow}, + request_hint::{DynRequestHint, RequestHint}, + sequence::{DynSequence, Sequence}, + tag::{Dyn, DynTag, Tag}, + value::{DynValue, Value}, }, }, DynWalker, Flow, @@ -20,17 +21,19 @@ pub struct Visitor<E>(usize, PhantomData<fn() -> E>); any_trait! { impl['a, 'ctx, E] Visitor<E> = [ - dyn RequestHint<'ctx, Effect = E> + 'a, + DynRequestHint<'a, 'ctx, E>, 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, + DynValue<'a, 'ctx, OwnedStatic<&'static str>, E>, + DynValue<'a, 'ctx, OwnedStatic<TypeId>, E>, + DynValue<'a, 'ctx, OwnedStatic<usize>, E>, + DynValue<'a, 'ctx, OwnedStatic<bool>, E>, + // DynValue<'a, 'ctx, OwnedStatic<&'static [&'static str]>, E>, DynSequence<'a, 'ctx, E>, ] else fallback where E: Effect<'ctx> } fn fallback(id: LtTypeId<'_>) { - println!("Unknown trait: {}", id); + // println!("Unknown trait: {}", id); } impl<'ctx, E: Effect<'ctx>> Visitor<E> { @@ -45,33 +48,23 @@ impl<'ctx, E: Effect<'ctx>> Visitor<E> { } } -impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx> for Visitor<E> { - type Effect = E; - +impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx, E> for Visitor<E> { fn request_hint<'a>( &'a mut self, _walker: crate::protocol::Walker<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> - where - Self: 'a, - { + ) -> Future<'a, 'ctx, Flow, E> { self.tab(); println!("Visit request hint (no hint given)"); - E::wrap(async { ControlFlow::Continue(()) }) + E::ready(Flow::Continue) } } -impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn> for Visitor<E> { - type Effect = E; - +impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn, E> for Visitor<E> { fn visit<'a>( &'a mut self, kind: Dyn, - walker: DynWalker<'a, 'ctx, Self::Effect>, - ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect> - where - Self: 'a, - { + walker: DynWalker<'a, 'ctx, E>, + ) -> Future<'a, 'ctx, Flow, E> { self.tab(); println!("Visit tag: {}", kind.0); @@ -79,86 +72,99 @@ impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn> for Visitor<E> { self.0 += 1; let result = walker.walk(self).await; self.0 -= 1; - match result { - ControlFlow::Continue(()) => Flow::Continue, - ControlFlow::Break(()) => Flow::Break, - } + result }) } } -impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>> for Visitor<E> { - type Effect = E; - +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>, E> for Visitor<E> { fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<&'static str>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + ) -> Future<'a, 'ctx, Flow, E> where Self: 'a, { self.tab(); println!("Visit static str: {:?}", value); - E::wrap(async { ControlFlow::Continue(()) }) + E::ready(Flow::Continue) } } -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> +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<usize>, E> for Visitor<E> { + fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<usize>) -> Future<'a, 'ctx, Flow, E> where Self: 'a, { self.tab(); println!("Visit usize: {}", value); - E::wrap(async { ControlFlow::Continue(()) }) + E::ready(Flow::Continue) } } -impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<TypeId>> for Visitor<E> { - type Effect = E; +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for Visitor<E> { + fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<bool>) -> Future<'a, 'ctx, Flow, E> + where + Self: 'a, + { + self.tab(); + println!("Visit bool: {}", value); + E::ready(Flow::Continue) + } +} +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static [&'static str]>, E> + for Visitor<E> +{ fn visit( &'a mut self, - OwnedStatic(value): OwnedStatic<TypeId>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + OwnedStatic(value): OwnedStatic<&'static [&'static str]>, + ) -> Future<'a, 'ctx, Flow, E> where Self: 'a, { self.tab(); - println!("Visit type ID: {:?}", value); - E::wrap(async { ControlFlow::Continue(()) }) + println!("Visit static slice of static str: {:?}", value); + E::ready(Flow::Continue) } } -impl<'ctx, E: Effect<'ctx>> Sequence<'ctx> for Visitor<E> { - type Effect = E; +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<TypeId>, E> for Visitor<E> { + fn visit(&'a mut self, OwnedStatic(value): OwnedStatic<TypeId>) -> Future<'a, 'ctx, Flow, E> + where + Self: 'a, + { + self.tab(); + println!("Visit type ID: {:?}", value); + E::ready(Flow::Continue) + } +} +impl<'ctx, E: Effect<'ctx>> Sequence<'ctx, E> for Visitor<E> { fn visit<'a>( &'a mut self, - scope: protocol::visitor::sequence::DynSequenceScope<'a, 'ctx, Self::Effect>, - ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect> { + scope: protocol::visitor::sequence::DynSequenceScope<'a, 'ctx, E>, + ) -> Future<'a, 'ctx, Flow, E> { self.tab(); E::wrap(async { println!("Visit sequence, size hint: {:?}", scope.size_hint().await); self.0 += 1; + + let mut index = 0; let flow = loop { self.tab(); - println!("Calling next"); + println!("Calling next: {}", index); self.0 += 1; match scope.next(self).await { - SequenceFlow::Done => { + Flow::Done => { self.tab(); println!("Sequence done"); - break Flow::Continue - }, - SequenceFlow::Continue => {}, - SequenceFlow::Break => break Flow::Break, + break Flow::Continue; + } + Flow::Continue => {} + Flow::Break => break Flow::Break, } + index += 1; self.0 -= 1; }; self.0 -= 2; diff --git a/src/effect.rs b/src/effect.rs index ebf082e..3ce7a07 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -28,6 +28,15 @@ pub trait Effect<'ctx>: 'static { fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, 'ctx, Self::Future<T>, T>; + fn map<'a, T, U, F>( + future: SendFuture::T<'a, 'ctx, Self::Future<T>, T>, + func: F, + ) -> SendFuture::T<'a, 'ctx, Self::Future<U>, U> + where + T: Send, + U: Send, + F: FnOnce(T) -> U + Send + 'a; + #[cfg(feature = "alloc")] #[inline] fn wrap_boxed<'a, F>( @@ -114,6 +123,19 @@ impl<'ctx, B: BlockOn> Effect<'ctx> for Blocking<B> { fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, 'ctx, Self::Future<T>, T> { core::future::ready(value) } + + fn map<'a, T, U, F>( + future: SendFuture::T<'a, 'ctx, Self::Future<T>, T>, + func: F, + ) -> SendFuture::T<'a, 'ctx, Self::Future<U>, U> + where + T: Send, + U: Send, + F: FnOnce(T) -> U + Send + 'a, + { + let value = B::block_on(future); + core::future::ready(func(value)) + } } mod sealed { @@ -160,6 +182,28 @@ impl<'ctx> Effect<'ctx> for Async { sealed::BoxedFuture::Box(Box::pin(future)) } + fn ready<'a, T: Send>(value: T) -> SendFuture::T<'a, 'ctx, Self::Future<T>, T> { + sealed::BoxedFuture::Ready(core::future::ready(value)) + } + + fn map<'a, T, U, F>( + future: SendFuture::T<'a, 'ctx, Self::Future<T>, T>, + func: F, + ) -> SendFuture::T<'a, 'ctx, Self::Future<U>, U> + where + T: Send, + U: Send, + F: FnOnce(T) -> U + Send + 'a, + { + match future { + sealed::BoxedFuture::Box(future) => Self::wrap(async { func(future.await) }), + sealed::BoxedFuture::Ready(future) => { + let value = Spin::block_on(future); + Self::ready(func(value)) + } + } + } + fn wrap_boxed<'a, F>( future: core::pin::Pin<Box<F>>, ) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> @@ -169,8 +213,4 @@ impl<'ctx> Effect<'ctx> for Async { { 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)) - } } @@ -40,42 +40,48 @@ pub mod macros; pub mod never { mod sealed { pub trait Extract { - type T; + type Never; } impl<T> Extract for fn() -> T { - type T = T; + type Never = T; } } - #[doc(hidden)] - pub type Never = <fn() -> ! as sealed::Extract>::T; + /// Test + pub type Never = <fn() -> ! as sealed::Extract>::Never; } 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_KEY: Symbol = Symbol::new("Key"); 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_FIELD: Symbol = Symbol::new("Field"); pub const TAG_ENUM: Symbol = Symbol::new("Enum"); +pub enum DefaultMode {} + #[derive(Debug)] pub enum StructWalkError { - Tag(TagError), + Tag(TagError<never::Never>), } #[must_use] -pub enum Flow<Error> { +pub enum Flow { /// Processing should continue as normal. Continue, - /// Processing should stop, but there is no direct error to report. + /// Processing should stop. + /// + /// This state signals some error happened. Break, - /// Processing should stop with this error. - Err(Error), + /// Processing should stop. + Done, } #[macro_export] @@ -87,12 +93,13 @@ macro_rules! Walk { ),* $(,)?} } => { const _: () = { - impl<'ctx> $crate::Walk<'ctx> for &'ctx $name { - type Walker<E: $crate::effect::Effect<'ctx>> = Walker<'ctx, E>; + impl<'ctx, M, E: $crate::effect::Effect<'ctx>> $crate::Walk<'ctx, M, E> for &'ctx $name { + type Walker = Walker<'ctx, M>; - fn into_walker<E: $crate::effect::Effect<'ctx>>(self) -> Self::Walker<E> { + fn into_walker(self) -> Self::Walker { Walker { value: self, + field: 0, _marker: ::core::marker::PhantomData, } } @@ -103,36 +110,35 @@ macro_rules! Walk { type Output = (); } - pub struct Walker<'ctx, E> { + pub struct Walker<'ctx, M> { value: &'ctx $name, - _marker: ::core::marker::PhantomData<fn() -> E>, + field: usize, + _marker: ::core::marker::PhantomData<fn() -> M>, } - impl<'ctx, E> $crate::WalkerTypes for Walker<'ctx, E> { + impl<'ctx, M> $crate::WalkerTypes for Walker<'ctx, M> { type Error = $crate::StructWalkError; type Output = (); } - impl<'ctx, E: $crate::effect::Effect<'ctx>> $crate::Walker<'ctx> for Walker<'ctx, E> { - type Effect = E; - + impl<'ctx, E: $crate::effect::Effect<'ctx>, M> $crate::Walker<'ctx, E> for Walker<'ctx, M> { fn walk<'a>( mut self, visitor: $crate::protocol::Visitor<'a, 'ctx>, - ) -> $crate::effect::Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + ) -> $crate::effect::Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> 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> + '_>() { + if let Some(object) = visitor.upcast_mut::<$crate::protocol::visitor::request_hint::DynRequestHint<'_, 'ctx, E>>() { // Allow the visitor to give a hint if it wants. match object.request_hint(&mut self).await { - ::core::ops::ControlFlow::Continue(()) => { + $crate::Flow::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(()); @@ -146,53 +152,114 @@ macro_rules! Walk { // - Tagged: struct field names // - Sequence: the fields - match $crate::macros::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>( + // Attempt to visit the value directly. + if !matches!($crate::protocol::visitor::value::visit_value::<_, E>( visitor, - $crate::walkers::core::tag::NoopWalker::new() + $crate::any::static_wrapper::BorrowedStatic(self.value) + ).await, $crate::protocol::visitor::Status::Skipped) { + return Ok(()); + } + + // Describe the struct in a general way: + + // Give the type ID + match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>( + visitor, + $crate::walkers::core::value::ValueWalker::new(::core::any::TypeId::of::<$name>()) ).await { - $crate::Flow::Continue => {}, - $crate::Flow::Break => return Ok(()), - $crate::Flow::Err(_) => unreachable!(), + Ok($crate::Flow::Continue) => {}, + Ok(_) => return Ok(()), + Err(_) => unreachable!(), } - match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>( + // Signal this is a struct. + match $crate::macros::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>( visitor, - $crate::walkers::core::tag::ValueWalker::new(stringify!($name)) + $crate::walkers::core::noop::NoopWalker::new() ).await { - $crate::Flow::Continue => {}, - $crate::Flow::Break => return Ok(()), - $crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)), + Ok($crate::Flow::Continue) => {}, + _ => return Ok(()), } - match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>( + // Give the type name. + match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>( visitor, - $crate::walkers::core::tag::ValueWalker::new(::core::any::TypeId::of::<$name>()) + $crate::walkers::core::value::ValueWalker::new(stringify!($name)) ).await { - $crate::Flow::Continue => {}, - $crate::Flow::Break => return Ok(()), - $crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)), + Ok($crate::Flow::Continue) => {}, + Ok(_) => return Ok(()), + Err(_) => unreachable!(), } + // Give the field names before hand. match $crate::macros::visit_tag::<{ $crate::TAG_FIELD_NAMES.to_int() }, E, _>( visitor, - $crate::walkers::core::tag::NamesWalker::new(&[$( + $crate::walkers::core::tag::StaticSliceWalker::<_, $crate::walkers::core::value::ValueWalker<&str>>::new(&[$( stringify!($field) ),*]) ).await { - $crate::Flow::Continue => {}, - $crate::Flow::Break => return Ok(()), - $crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)), + Ok($crate::Flow::Continue) => {}, + Ok(_) => return Ok(()), + // Err(err) => return Err(StructWalkError::Tag(err)), + Err(err) => todo!(), + } + + if !matches!($crate::protocol::visitor::sequence::visit_sequence::<E>( + visitor, + &mut self, + ).await, $crate::protocol::visitor::Status::Skipped) { + return Ok(()); } - todo!() + Ok(()) }) } } + impl<'ctx, E: $crate::effect::Effect<'ctx>, M> $crate::protocol::visitor::sequence::SequenceScope<'ctx, E> for Walker<'ctx, M> { + fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E> { + E::wrap(async { + let mut index = 0; + match self.field {$( + field if { index += 1; field == index - 1 } => { + match $crate::macros::visit_tag::<{ $crate::TAG_FIELD.to_int() }, E, _>( + visitor, + $crate::walkers::core::noop::NoopWalker::new() + ).await { + Ok($crate::Flow::Continue) => {}, + _ => return Flow::Done, + } + + match $crate::macros::visit_tag::<{ $crate::TAG_KEY.to_int() }, E, _>( + visitor, + $crate::walkers::core::value::ValueWalker::new(stringify!($field)) + ).await { + Ok($crate::Flow::Continue) => {}, + Ok(_) => return Flow::Done, + Err(_) => unreachable!(), + } + + let walker = $crate::Walk::<M, E>::into_walker(&self.value.$field); + $crate::Walker::<E>::walk(walker, visitor).await; + self.field += 1; + Flow::Continue + } + )* + _ => Flow::Done + } + }) + } + + fn size_hint<'a>(&'a mut self) -> Future<'a, 'ctx, (usize, Option<usize>), E> { + const X: &[&str] = &[$(stringify!($field)),*]; + E::ready((X.len(), Some(X.len()))) + } + } + $crate::any::any_trait! { - impl['a, 'ctx, E] Walker<'ctx, E> = [ + impl['a, 'ctx, M] Walker<'ctx, M> = [ // dyn Hint<'a, 'ctx, OwnedStatic<bool>, E> + 'a, - ] where E: $crate::effect::Effect<'ctx> + ] } }; @@ -210,16 +277,25 @@ mod test { struct Demo { a: bool, b: bool, + other: Other, + } + + #[derive(Walk!)] + struct Other { + value: bool, } #[test] fn demo() { - let value = Demo { a: true, b: false }; + let value = Demo { a: true, b: false, other: Other { value: true } }; - let walker = value.into_walker::<Blocking>(); + let walker = Walk::<DefaultMode, Blocking>::into_walker(&value); let mut visitor = builders::debug::Visitor::<Blocking>::new(); - dbg!(Spin::block_on(walker.walk(&mut visitor))); + dbg!(Spin::block_on(Walker::<Blocking>::walk( + walker, + &mut visitor + ))); todo!(); } diff --git a/src/macros.rs b/src/macros.rs index a946257..ffb52b1 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -9,47 +9,51 @@ use crate::{ }; #[derive(Debug)] -pub struct TagError { - symbol: Symbol, - msg: &'static str, +pub enum TagErrorKind<E> { + NeverWalked, + + /// This can only happen if a panic happens furing the walk and is then caught before calling + /// finish.. + WalkNeverFinished, + + Walker(E), } -impl From<TagError> for &'static str { - fn from(value: TagError) -> Self { - value.msg - } +#[derive(Debug)] +pub struct TagError<E> { + symbol: Symbol, + err: TagErrorKind<E>, } -impl TagError { - fn new<const SYMBOL: u64>(msg: &'static str) -> Self { +impl<E> TagError<E> { + fn new<const SYMBOL: u64>(err: E) -> Self { Self { symbol: Symbol::from_int(SYMBOL), - msg, + err: TagErrorKind::Walker(err), } } fn never_walked<const SYMBOL: u64>() -> Self { - Self::new::<SYMBOL>("visitor did not walk the walker") + Self { + symbol: Symbol::from_int(SYMBOL), + err: TagErrorKind::NeverWalked, + } } fn walk_never_finished<const SYMBOL: u64>() -> Self { - Self::new::<SYMBOL>("walk did not finish") + Self { + symbol: Symbol::from_int(SYMBOL), + err: TagErrorKind::WalkNeverFinished, + } } } -pub fn visit_tag< - 'a, - 'ctx: 'a, - const SYMBOL: u64, - E: Effect<'ctx>, - W: Walker<'ctx, Effect = E> + 'a, ->( +pub fn visit_tag<'a, 'ctx: 'a, const SYMBOL: u64, E: Effect<'ctx>, W: Walker<'ctx, E> + 'a>( visitor: Visitor<'a, 'ctx>, walker: W, -) -> Future<'a, 'ctx, Flow<TagError>, E> +) -> Future<'a, 'ctx, Result<Flow, TagError<W::Error>>, E> where W: WalkerTypes<Output = ()>, - <W as WalkerTypes>::Error: Into<&'static str>, { E::wrap(async { let result = @@ -89,32 +93,28 @@ where let Some(result) = result else { // The visitor doesn't know about this tag protocol so just continue as normal. - return Flow::Continue; + return Ok(Flow::Continue); }; match result { // The happy path. - (Flow::Continue, Ok(_)) => Flow::Continue, + (Flow::Continue, Ok(_)) => Ok(Flow::Continue), // The visitor wants to stop the control flow for some reason. - (Flow::Break, Ok(_)) => Flow::Break, + (Flow::Break, Ok(_)) => Ok(Flow::Break), + (Flow::Done, Ok(_)) => Ok(Flow::Done), // The walker had an error. - (_, Err(DynWalkerError::Walker(err))) => Flow::Err(TagError::new::<SYMBOL>(err.into())), + (_, Err(DynWalkerError::Walker(err))) => Err(TagError::new::<SYMBOL>(err)), // The visitor never walked the dynamic walker. Aka it didn't call walk. - (_, Err(DynWalkerError::NeverWalked(_))) => { - Flow::Err(TagError::never_walked::<SYMBOL>()) - } + (_, Err(DynWalkerError::NeverWalked(_))) => 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>()) + Err(TagError::walk_never_finished::<SYMBOL>()) } - - // This isn't possible because Err(!). - (Flow::Err(_), _) => unreachable!(), } }) } diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs index efaa495..aad879d 100644 --- a/src/protocol/visitor.rs +++ b/src/protocol/visitor.rs @@ -2,3 +2,14 @@ pub mod request_hint; pub mod sequence; pub mod tag; pub mod value; + +pub enum Status { + /// The protocol was used. + Continue, + + /// The protocol was not used. + Skipped, + + /// Should stop processing. + Break, +} diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index f1ab735..50ae76d 100644 --- a/src/protocol/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -1,31 +1,54 @@ -use core::ops::ControlFlow; - use crate::{ effect::{Effect, Future}, nameable, - protocol::Walker, + never::Never, + protocol::{Visitor, Walker}, + Flow, }; /// Protocol for requesting a hint from a visitor. -pub trait RequestHint<'ctx> { - type Effect: Effect<'ctx>; - +pub trait RequestHint<'ctx, E: 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<'a>( - &'a mut self, - walker: Walker<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> - where - Self: 'a; + fn request_hint<'a>(&'a mut self, walker: Walker<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>; } +pub type DynRequestHint<'a, 'ctx, E> = dyn RequestHint<'ctx, E> + Send + 'a; + nameable! { pub struct Name['a, 'ctx, E]; - impl [E] for dyn RequestHint<'ctx, Effect = E> + 'a where { + impl [E] for DynRequestHint<'a, 'ctx, E> where { E: Effect<'ctx>, 'ctx: 'a } } + +/// Visit using the [`RequestHint`] protocol. +/// +/// If `true` is returned then the walker should stop. +/// This is either because of an error or the visitor is done. +pub fn visit_request_hint<'a, 'ctx, E: Effect<'ctx>>( + visitor: Visitor<'a, 'ctx>, + walker: Walker<'a, 'ctx>, +) -> Future<'a, 'ctx, bool, E> { + if let Some(object) = visitor.upcast_mut::<DynRequestHint<'_, 'ctx, E>>() { + // Allow the visitor to give a hint if it wants. + E::map(object.request_hint(walker), |flow| match flow { + Flow::Continue => { + // The visitor wants the walker to continue to it's normal + // walking. + false + } + _ => { + // The visitor is done (either because of an error or because + // it already used a hint). + true + } + }) + } else { + // If the visitor doesn't support request hint then we continue. + E::ready(false) + } +} diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs index a3ca785..8c7b2e4 100644 --- a/src/protocol/visitor/sequence.rs +++ b/src/protocol/visitor/sequence.rs @@ -1,23 +1,19 @@ -use core::ops::ControlFlow; - use crate::{ effect::{Effect, Future}, higher_ranked_type, hkt::AnySend, nameable, - protocol::{walker::hint::HintMeta, Visitor}, Flow, never::Never, + protocol::{walker::hint::HintMeta, Visitor}, + Flow, }; -pub trait Sequence<'ctx> { - type Effect: Effect<'ctx>; +use super::Status; - fn visit<'a>( - &'a mut self, - scope: DynSequenceScope<'a, 'ctx, Self::Effect>, - ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect>; +pub trait Sequence<'ctx, E: Effect<'ctx>> { + fn visit<'a>(&'a mut self, scope: DynSequenceScope<'a, 'ctx, E>) -> Future<'a, 'ctx, Flow, E>; } -pub type DynSequence<'a, 'ctx, E> = dyn Sequence<'ctx, Effect = E> + Send + 'a; +pub type DynSequence<'a, 'ctx, E> = dyn Sequence<'ctx, E> + Send + 'a; nameable! { pub struct Name['a, 'ctx, E]; @@ -33,27 +29,13 @@ nameable! { } } -pub trait SequenceScope<'ctx> { - type Effect: Effect<'ctx>; - - fn size_hint<'a>( - &'a mut self, - ) -> Future<'a, 'ctx, (usize, Option<usize>), Self::Effect>; +pub trait SequenceScope<'ctx, E: Effect<'ctx>> { + fn size_hint<'a>(&'a mut self) -> Future<'a, 'ctx, (usize, Option<usize>), E>; - fn next<'a>( - &'a mut self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, SequenceFlow, Self::Effect>; + fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>; } -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 SequenceFlow { - Done, - Continue, - Break, -} +pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + 'a); higher_ranked_type! { pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known @@ -73,3 +55,27 @@ impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for DynSequence<'a, 'ctx, E> type Hint = Hint; } + +pub fn visit_sequence<'a, 'ctx, E: Effect<'ctx>>( + visitor: Visitor<'a, 'ctx>, + scope: DynSequenceScope<'a, 'ctx, E>, +) -> Future<'a, 'ctx, Status, E> { + if let Some(object) = visitor.upcast_mut::<DynSequence<'_, 'ctx, E>>() { + // Allow the visitor to give a hint if it wants. + E::map(object.visit(scope), |flow| match flow { + Flow::Continue => { + // The visitor wants the walker to continue to it's normal + // walking. + Status::Continue + } + Flow::Break | Flow::Done => { + // The visitor is done (either because of an error or because + // it already used a hint). + Status::Break + } + }) + } else { + // If the visitor doesn't support request hint then we continue. + E::ready(Status::Skipped) + } +} diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs index 0ac6e5b..1be53ae 100644 --- a/src/protocol/visitor/tag.rs +++ b/src/protocol/visitor/tag.rs @@ -31,19 +31,15 @@ impl Kind for Dyn { } } -pub trait Tag<'ctx, K: Kind> { - type Effect: Effect<'ctx>; - +pub trait Tag<'ctx, K: Kind, E: Effect<'ctx>> { fn visit<'a>( &'a mut self, kind: K, - walker: DynWalker<'a, 'ctx, Self::Effect>, - ) -> Future<'a, 'ctx, Flow<Never>, Self::Effect> - where - Self: 'a; + walker: DynWalker<'a, 'ctx, E>, + ) -> Future<'a, 'ctx, Flow, E>; } -pub type DynTag<'a, 'ctx, K, E> = dyn Tag<'ctx, K, Effect = E> + Send + 'a; +pub type DynTag<'a, 'ctx, K, E> = dyn Tag<'ctx, K, E> + Send + 'a; nameable! { pub struct Name['a, 'ctx, K, E]; diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs index a0c435c..8e7902c 100644 --- a/src/protocol/visitor/value.rs +++ b/src/protocol/visitor/value.rs @@ -2,23 +2,23 @@ //! //! In some sense, this is the most basic protocol. -use core::ops::ControlFlow; - use crate::{ any::{TypeName, TypeNameable}, effect::{Effect, Future}, higher_ranked_type, hkt::AnySend, nameable, - protocol::walker::hint::HintMeta, + never::Never, + protocol::{walker::hint::HintMeta, Visitor}, + Flow, }; +use super::Status; + /// Trait object for the [`Value`] protocol. /// /// Types implementing the [`Value`] protocol will implement this trait. -pub trait Value<'a, 'ctx: 'a, T> { - type Effect: Effect<'ctx>; - +pub trait Value<'a, 'ctx: 'a, T, E: Effect<'ctx>> { /// Visit a value of type `T`. /// /// Use this to give a value to a visitor. Its expected that a walker @@ -28,21 +28,21 @@ pub trait Value<'a, 'ctx: 'a, T> { /// 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<(), ()>, Self::Effect> - where - Self: 'a; + fn visit(&'a mut self, value: T) -> Future<'a, 'ctx, Flow, E>; } +pub type DynValue<'a, 'ctx, T, E> = dyn Value<'a, 'ctx, T, E> + Send + 'a; + nameable! { pub struct Name['a, 'ctx, T, E]; - impl [T::Name, E] for dyn Value<'a, 'ctx, T, Effect = E> + 'a where { + impl [T::Name, E] for DynValue<'a, 'ctx, T, E> where { T: TypeNameable<'a, 'ctx> + ?Sized, E: Effect<'ctx>, 'ctx: 'a, } - impl [T, E] where dyn Value<'a, 'ctx, T::Nameable, Effect = E> + 'a { + impl [T, E] where DynValue<'a, 'ctx, T::Nameable, E> { T: TypeName<'a, 'ctx> + ?Sized, E: Effect<'ctx>, 'ctx: 'a, @@ -54,12 +54,36 @@ 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, Effect = E> + 'a { +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> HintMeta<'ctx> for DynValue<'a, 'ctx, T, E> { type Known = Known<'ctx>; type Hint = (); } +pub fn visit_value<'a, 'ctx, T: TypeNameable<'a, 'ctx>, E: Effect<'ctx>>( + visitor: Visitor<'a, 'ctx>, + value: T, +) -> Future<'a, 'ctx, Status, E> { + if let Some(object) = visitor.upcast_mut::<DynValue<'_, 'ctx, T, E>>() { + // Allow the visitor to give a hint if it wants. + E::map(object.visit(value), |flow| match flow { + Flow::Continue => { + // The visitor wants the walker to continue to it's normal + // walking. + Status::Continue + } + Flow::Break | Flow::Done => { + // The visitor is done (either because of an error or because + // it already used a hint). + Status::Break + } + }) + } else { + // If the visitor doesn't support request hint then we continue. + E::ready(Status::Skipped) + } +} + #[cfg(test)] mod test { use core::{marker::PhantomData, ops::ControlFlow}; @@ -79,44 +103,40 @@ mod test { fn visit() { struct Visitor<E>(Option<i32>, PhantomData<fn() -> E>); - impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, OwnedStatic<i32>> for Visitor<E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, OwnedStatic<i32>, E> for Visitor<E> where E: Effect<'ctx>, { - type Effect = E; - fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<i32>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + ) -> Future<'a, 'ctx, Flow, E> { E::wrap(async move { self.0 = Some(value); - ControlFlow::Continue(()) + Flow::Continue }) } } - impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, i32>> for Visitor<E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, E> for Visitor<E> where E: Effect<'ctx>, { - type Effect = E; - fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, i32>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + ) -> Future<'a, 'ctx, Flow, E> { E::wrap(async { self.0 = Some(*value); - ControlFlow::Continue(()) + Flow::Continue }) } } any_trait! { impl['a, 'ctx, E] Visitor<E> = [ - dyn Value<'a, 'ctx, OwnedStatic<i32>, Effect = E> + 'a, - dyn Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, Effect = E> + 'a, + DynValue<'a, 'ctx, OwnedStatic<i32>, E>, + DynValue<'a, 'ctx, BorrowedStatic<'ctx, i32>, E>, ] where E: Effect<'ctx>, } @@ -124,7 +144,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, OwnedStatic<i32>, Effect = Blocking>>() + .upcast_mut::<DynValue<'_, '_, OwnedStatic<i32>, Blocking>>() .unwrap() .visit(OwnedStatic(42)), ); @@ -134,7 +154,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, i32>, Effect = Blocking>>() + .upcast_mut::<DynValue<'_, '_, BorrowedStatic<'_, i32>, Blocking>>() .unwrap() .visit(BorrowedStatic(&101)), ); @@ -146,27 +166,25 @@ 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>> for Visitor<'ctx, E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, E> for Visitor<'ctx, E> where E: Effect<'ctx>, { - type Effect = E; - fn visit( &'a mut self, BorrowedMutStatic(value): BorrowedMutStatic<'ctx, String>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + ) -> Future<'a, 'ctx, Flow, E> { E::wrap(async { self.0 = Some(value); - ControlFlow::Continue(()) + Flow::Continue }) } } any_trait! { impl['a, 'ctx, E] Visitor<'ctx, E> = [ - dyn Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, Effect = E> + 'a, + DynValue<'a, 'ctx, BorrowedMutStatic<'ctx, String>, E>, ] where E: Effect<'ctx> } @@ -176,7 +194,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, _, Effect = Blocking>>() + .upcast_mut::<DynValue<'_, '_, _, Blocking>>() .unwrap() .visit(BorrowedMutStatic(&mut y)), ); @@ -189,26 +207,24 @@ 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>> for Visitor<'ctx, E> + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> for Visitor<'ctx, E> where E: Effect<'ctx>, { - type Effect = E; - fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, str>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + ) -> Future<'a, 'ctx, Flow, E> { E::wrap(async { self.0 = Some(value); - ControlFlow::Continue(()) + Flow::Continue }) } } any_trait! { impl['a, 'ctx, E] Visitor<'ctx, E> = [ - dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, Effect = E> + 'a, + DynValue<'a, 'ctx, BorrowedStatic<'ctx, str>, E>, ] where E: Effect<'ctx> } @@ -218,7 +234,7 @@ mod test { let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; Spin::block_on( object - .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, str>, Effect = Blocking> + '_>() + .upcast_mut::<DynValue<'_, '_, BorrowedStatic<'_, str>, Blocking>>() .unwrap() .visit(BorrowedStatic(&y)), ); diff --git a/src/transform.rs b/src/transform.rs index 2e3d14b..9d696be 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -5,13 +5,7 @@ use crate::{ }; #[inline] -pub fn transform< - 'a, - 'ctx, - B: Builder<'ctx, Effect = E> + 'a, - W: Walker<'ctx, Effect = E> + 'a, - E: Effect<'ctx>, ->( +pub fn transform<'a, 'ctx, B: Builder<'ctx, E> + 'a, W: Walker<'ctx, E> + 'a, E: Effect<'ctx>>( seed: B::Seed, walker: W, ) -> Future<'a, 'ctx, (Result<B::Value, B::Error>, Result<W::Output, W::Error>), E> { diff --git a/src/walk.rs b/src/walk.rs index 32232fd..0dbccee 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,23 +1,17 @@ pub mod walkers; -use core::ops::ControlFlow; - use crate::{ effect::{Effect, Future}, protocol::Visitor, + Flow, }; /// A type that can be walked. -pub trait Walk<'ctx>: WalkerTypes + Sized { +pub trait Walk<'ctx, M, E: Effect<'ctx>>: WalkerTypes + Sized { /// The walker for the type. - 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>; + type Walker: Walker<'ctx, E, Error = Self::Error, Output = Self::Output>; + + fn into_walker(self) -> Self::Walker; } pub trait WalkerTypes { @@ -38,40 +32,34 @@ pub trait WalkerTypes { /// - 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 + Send { - type Effect: Effect<'ctx>; - +pub trait Walker<'ctx, E: Effect<'ctx>>: WalkerTypes + Send { /// Walk the value. /// /// The walker should send data to the `visitor` as it walks the value. fn walk<'a>( self, visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> where Self: 'a; } -pub trait WalkerObjSafe<'ctx>: Send { - type Effect: Effect<'ctx>; - - fn walk<'a>( - &'a mut self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> +pub trait WalkerObjSafe<'ctx, E: Effect<'ctx>>: Send { + fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E> where Self: 'a; fn skip(&mut self); } -pub type DynWalker<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, Effect = E> + Send + 'a); +pub type DynWalker<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, E> + Send + 'a); enum DynWalkerState<W: WalkerTypes> { Skipped, Walking, Pending(W), - Done(Result<W::Output, W::Error>), + Done(W::Output), + Err(W::Error), } pub enum DynWalkerError<W: WalkerTypes> { @@ -100,31 +88,39 @@ impl<W: WalkerTypes> DynWalkerAdapter<W> { DynWalkerState::Skipped => Ok(None), DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished), DynWalkerState::Pending(walker) => Err(DynWalkerError::NeverWalked(walker)), - DynWalkerState::Done(result) => result.map(Some).map_err(DynWalkerError::Walker), + DynWalkerState::Done(value) => Ok(Some(value)), + DynWalkerState::Err(err) => Err(DynWalkerError::Walker(err)), } } } -impl<'ctx, W: Walker<'ctx>> WalkerObjSafe<'ctx> for DynWalkerAdapter<W> { - type Effect = W::Effect; - - fn walk<'a>( - &'a mut self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> +impl<'ctx, W: Walker<'ctx, E>, E: Effect<'ctx>> WalkerObjSafe<'ctx, E> for DynWalkerAdapter<W> { + fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E> where Self: 'a, { - Self::Effect::wrap(async { + E::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); + match walker.walk(visitor).await { + Ok(value) => { + self.state = DynWalkerState::Done(value); + Flow::Continue + } + Err(err) => { + self.state = DynWalkerState::Err(err); + + // Signal that control flow should stop as soon as possible as we + // are in an error state. + Flow::Break + } + } } else { // Can't do anything if the walker has already been walked. + Flow::Continue } - ControlFlow::Continue(()) }) } diff --git a/src/walk/walkers/core.rs b/src/walk/walkers/core.rs index 734a5c6..172244d 100644 --- a/src/walk/walkers/core.rs +++ b/src/walk/walkers/core.rs @@ -1,4 +1,6 @@ // pub mod array; pub mod bool; +pub mod noop; pub mod tag; +pub mod value; diff --git a/src/walk/walkers/core/array.rs b/src/walk/walkers/core/array.rs index c4b9568..cc3a6da 100644 --- a/src/walk/walkers/core/array.rs +++ b/src/walk/walkers/core/array.rs @@ -2,12 +2,6 @@ use core::{mem::MaybeUninit, ops::ControlFlow}; use crate::{ any_trait, - effect::{Effect, SyncEffect, Yield}, - protocol::{ - visitor::{RequestHint, Sequence, SequenceScope, Status}, - walker::{Hint, HintMeta}, - Visitor, - }, }; impl<'ctx, T: crate::Walk<'ctx>, const N: usize> crate::Walk<'ctx> for [T; N] diff --git a/src/walk/walkers/core/bool.rs b/src/walk/walkers/core/bool.rs index 24bb421..a3f2a93 100644 --- a/src/walk/walkers/core/bool.rs +++ b/src/walk/walkers/core/bool.rs @@ -1,55 +1,29 @@ -use crate::{any::static_wrapper::OwnedStatic, protocol::visitor::value::Value}; -use core::{marker::PhantomData, mem::MaybeUninit, ops::ControlFlow}; +use crate::{effect::Effect, Walk, WalkerTypes}; -use crate::{ - any_trait, - effect::{Effect, Future}, - protocol::{ - walker::hint::{Hint, HintMeta}, - Visitor, - }, -}; +use super::value::{ValueWalker, BorrowWalker}; -impl<'ctx> crate::Walk<'ctx> for bool { - type Walker<E: Effect<'ctx>> = Walker<E>; +impl<'ctx, M, E: Effect<'ctx>> Walk<'ctx, M, E> for bool { + type Walker = ValueWalker<bool>; - fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E> { - Walker(self, PhantomData) + fn into_walker(self) -> Self::Walker { + ValueWalker::new(self) } } -pub struct Walker<E>(bool, PhantomData<fn() -> E>); - -impl crate::WalkerTypes for bool { - type Error = (); - - type Output = (); +impl WalkerTypes for bool { + type Error = <ValueWalker<bool> as WalkerTypes>::Error; + type Output = <ValueWalker<bool> as WalkerTypes>::Output; } -impl<E> crate::WalkerTypes for Walker<E> { - type Error = (); +impl<'ctx, M, E: Effect<'ctx>> Walk<'ctx, M, E> for &'ctx bool { + type Walker = ValueWalker<bool>; - type Output = (); + fn into_walker(self) -> Self::Walker { + ValueWalker::new(*self) + } } -impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for Walker<E> { - type Effect = E; - #[inline] - fn walk<'a>( - self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> - where - 'ctx: 'a, - { - E::wrap(async move { - if let Some(object) = - visitor.upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<bool>, Effect = E> + '_>() - { - object.visit(OwnedStatic(self.0)).await; - } - - Ok(()) - }) - } +impl<'ctx> WalkerTypes for &'ctx bool { + type Error = <ValueWalker<bool> as WalkerTypes>::Error; + type Output = <ValueWalker<bool> as WalkerTypes>::Output; } diff --git a/src/walk/walkers/core/noop.rs b/src/walk/walkers/core/noop.rs new file mode 100644 index 0000000..03b4b7c --- /dev/null +++ b/src/walk/walkers/core/noop.rs @@ -0,0 +1,36 @@ +use crate::{ + effect::{Effect, Future}, + never::Never, + protocol::Visitor, + WalkerTypes, +}; + +/// A walker that does nothing. +/// +/// This walker is useful for tags that don't need a value. +#[non_exhaustive] +pub struct NoopWalker; + +impl NoopWalker { + pub fn new() -> Self { + Self + } +} + +impl WalkerTypes for NoopWalker { + type Error = Never; + + type Output = (); +} + +impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx, E> for NoopWalker { + fn walk<'a>( + self, + _visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> + where + Self: 'a, + { + E::ready(Ok(())) + } +} diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs index 8c40f2d..5c5d144 100644 --- a/src/walk/walkers/core/tag.rs +++ b/src/walk/walkers/core/tag.rs @@ -2,268 +2,110 @@ use core::{any::TypeId, marker::PhantomData}; use crate::{ any::static_wrapper::OwnedStatic, + any_trait, effect::{Effect, Future}, + macros::{visit_tag, TagError}, + never::Never, protocol::{ - visitor::{sequence::{DynSequence, SequenceScope, SequenceFlow}, value::Value, tag::DynTag}, + visitor::{ + request_hint::{visit_request_hint, DynRequestHint, RequestHint}, + sequence::{DynSequence, SequenceScope}, + tag::DynTag, + Status, + value::{visit_value, DynValue, Value}, + }, Visitor, }, - WalkerTypes, Flow, macros::{visit_tag, TagError}, TAG_FIELD_NAMES, TAG_SEQ_INDEX, never::Never, TAG_SEQ_LEN, + Flow, WalkerTypes, TAG_FIELD_NAMES, TAG_SEQ_INDEX, TAG_SEQ_LEN, }; -pub struct ValueWalker<T, E>(T, PhantomData<fn() -> E>); +use super::value::ValueWalker; -impl<T, E> ValueWalker<T, E> { - pub fn new(value: T) -> Self { - Self(value, PhantomData) - } -} - -pub struct MissingProtocol(pub &'static str); - -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, T: Send + 'static, E: Effect<'ctx>> crate::Walker<'ctx> for ValueWalker<T, 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<T>, Effect = E> + '_>() - { - // Visit with the name. - object.visit(OwnedStatic(self.0)).await; - - Ok(()) - } else { - Err(MissingProtocol( - "visitor missing protocol Value<?>", - )) - } - }) - } -} - -pub struct NamesWalker<E> { - names: &'static [&'static str], +pub struct StaticSliceWalker<T: 'static, W> { + names: &'static [T], current: usize, - error: Option<(usize, WithTagError<MissingProtocol>)>, - _marker: PhantomData<fn() -> E>, + _marker: PhantomData<fn() -> W>, } -impl<E> NamesWalker<E> { - pub fn new(names: &'static [&'static str]) -> Self { +impl<T, W> StaticSliceWalker<T, W> { + pub fn new(names: &'static [T]) -> Self { Self { names, current: 0, - error: None, _marker: PhantomData, } } } -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>>; +impl<T, W> WalkerTypes for StaticSliceWalker<T, W> { + type Error = TagError<Never>; type Output = (); } -impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for NamesWalker<E> { - type Effect = E; - +impl<'ctx, T, W, E> crate::Walker<'ctx, E> for StaticSliceWalker<T, W> +where + E: Effect<'ctx>, + W: crate::Walker<'ctx, E> + WalkerTypes<Output = ()>, + T: Sync, + &'static T: Into<W>, +{ fn walk<'a>( mut self, visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> where Self: 'a, { E::wrap(async move { - 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)), + if visit_request_hint::<E>(visitor, &mut self).await { + return Ok(()); + } + + if matches!( + visit_value::<_, E>(visitor, OwnedStatic(self.names)).await, + Status::Break | Status::Continue + ) { + return 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(SequenceError::Err(MissingProtocol("visitor missing protocol Sequence"))) } + + Ok(()) }) } } -impl<'ctx, E: Effect<'ctx>> SequenceScope<'ctx> for NamesWalker<E> { - type Effect = E; +any_trait! { + impl['a, 'ctx, T, W] StaticSliceWalker<T, W> = [ + ] +} - fn next<'a>( - &'a mut self, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, 'ctx, SequenceFlow, Self::Effect> { +impl<'ctx, T, W, E> SequenceScope<'ctx, E> for StaticSliceWalker<T, W> +where + E: Effect<'ctx>, + W: crate::Walker<'ctx, E> + WalkerTypes<Output = ()>, + T: Sync, + &'static T: Into<W>, +{ + fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E> { 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 - }, + match crate::Walker::walk(name.into(), visitor).await { + Ok(()) => Flow::Continue, + Err(_) => unreachable!(), } }) } else { - E::ready(SequenceFlow::Done) + E::ready(Flow::Done) } } - fn size_hint<'a>( - &'a mut self, - ) -> Future<'a, 'ctx, (usize, Option<usize>), Self::Effect> { + fn size_hint<'a>(&'a mut self) -> Future<'a, 'ctx, (usize, Option<usize>), E> { 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(())) - } } diff --git a/src/walk/walkers/core/value.rs b/src/walk/walkers/core/value.rs new file mode 100644 index 0000000..4f75750 --- /dev/null +++ b/src/walk/walkers/core/value.rs @@ -0,0 +1,89 @@ +use crate::{ + any::static_wrapper::{BorrowedStatic, OwnedStatic}, + effect::{Effect, Future}, + never::Never, + protocol::{visitor::value::visit_value, Visitor}, + WalkerTypes, +}; + +/// A very basic walker that uses the [`Value`][crate::protocol::visitor::value::Value] protocol. +/// +/// Primitive types use this walker as their main walker. +/// This walker doesn't consider it an error if the visitor doesn't have the protocol. +pub struct ValueWalker<T>(T); + +impl<T> ValueWalker<T> { + /// Create walker from a value. + pub fn new(value: T) -> Self { + Self(value) + } +} + +impl<T> From<T> for ValueWalker<T> { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl<T: Copy> From<&T> for ValueWalker<T> { + fn from(value: &T) -> Self { + Self::new(*value) + } +} + +impl<T> WalkerTypes for ValueWalker<T> { + type Error = Never; + + type Output = (); +} + +impl<'ctx, T: Send + 'static, E: Effect<'ctx>> crate::Walker<'ctx, E> for ValueWalker<T> { + fn walk<'a>( + self, + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> + where + Self: 'a, + { + // Attempt to visit using the value protocol. + E::map( + visit_value::<_, E>(visitor, OwnedStatic(self.0)), + |_| Ok(()), + ) + } +} + +/// Borrowed form of [`ValueWalker`]. +/// +/// This walker supports values borrowed for `'ctx` or longer. +pub struct BorrowWalker<'ctx, T: ?Sized>(&'ctx T); + +impl<'ctx, T: ?Sized> BorrowWalker<'ctx, T> { + /// Create walker from a value. + pub fn new(value: &'ctx T) -> Self { + Self(value) + } +} + +impl<'ctx, T: ?Sized> WalkerTypes for BorrowWalker<'ctx, T> { + type Error = Never; + + type Output = (); +} + +impl<'ctx, T: ?Sized + Sync + 'static, E: Effect<'ctx>> crate::Walker<'ctx, E> + for BorrowWalker<'ctx, T> +{ + fn walk<'a>( + self, + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> + where + Self: 'a, + { + // Attempt to visit using the value protocol. + E::map(visit_value::<_, E>(visitor, BorrowedStatic(self.0)), |_| { + Ok(()) + }) + } +} |