updated how the tag walkers are setup
| -rw-r--r-- | src/build.rs | 6 | ||||
| -rw-r--r-- | src/build/builders/core/bool.rs | 4 | ||||
| -rw-r--r-- | src/build/builders/debug.rs | 107 | ||||
| -rw-r--r-- | src/effect.rs | 37 | ||||
| -rw-r--r-- | src/lib.rs | 153 | ||||
| -rw-r--r-- | src/macros.rs | 120 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs | 32 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 25 | ||||
| -rw-r--r-- | src/walk.rs | 34 | ||||
| -rw-r--r-- | src/walk/walkers/core/bool.rs | 4 | ||||
| -rw-r--r-- | src/walk/walkers/core/tag.rs | 234 |
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)) } } @@ -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(())) + } +} |