Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 170 |
1 files changed, 123 insertions, 47 deletions
@@ -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!(); } |