Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 81 |
1 files changed, 50 insertions, 31 deletions
@@ -28,8 +28,7 @@ use core::ops::ControlFlow; pub use build::*; use effect::{Effect, Future}; -use macros::TagError; -use protocol::Visitor; +use protocol::{Visitor, visitor::tag::TagError}; use symbol::Symbol; pub use transform::*; pub use walk::*; @@ -60,6 +59,8 @@ 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_MAP: Symbol = Symbol::new("Map"); +pub const TAG_SEQ: Symbol = Symbol::new("Sequence"); pub const TAG_FIELD: Symbol = Symbol::new("Field"); pub const TAG_ENUM: Symbol = Symbol::new("Enum"); @@ -68,6 +69,7 @@ pub enum DefaultMode {} #[derive(Debug)] pub enum StructWalkError { Tag(TagError<never::Never>), + FieldTag(TagError<TagError<never::Never>>), } #[must_use] @@ -146,12 +148,6 @@ macro_rules! Walk { } } - // Follow the standard set of protocols for a struct. - // - Tagged: struct name - // - Tagged: struct type - // - Tagged: struct field names - // - Sequence: the fields - // Attempt to visit the value directly. if !matches!($crate::protocol::visitor::value::visit_value::<_, E>( visitor, @@ -160,48 +156,67 @@ macro_rules! Walk { return Ok(()); } + // Follow the standard set of protocols for a struct. + // - Tagged: struct name + // - Tagged: struct type + // - Tagged: struct field names + // - Sequence: the fields + // Describe the struct in a general way: + use $crate::protocol::visitor::Status as S; + // Give the type ID - match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>( + match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>( visitor, $crate::walkers::core::value::ValueWalker::new(::core::any::TypeId::of::<$name>()) ).await { - Ok($crate::Flow::Continue) => {}, - Ok(_) => return Ok(()), - Err(_) => unreachable!(), + Ok(S::Skipped) | Ok(S::Continue) => {}, + Ok(S::Break) => return Ok(()), + Err(err) => return Err(StructWalkError::Tag(err)), } // Signal this is a struct. - match $crate::macros::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>( + match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>( visitor, $crate::walkers::core::noop::NoopWalker::new() ).await { - Ok($crate::Flow::Continue) => {}, - _ => return Ok(()), + Ok(S::Skipped) => { + // If can't tag as a struct try as a map. + match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_MAP.to_int() }, E, _>( + visitor, + $crate::walkers::core::noop::NoopWalker::new() + ).await { + Ok(S::Skipped) | Ok(S::Continue) => {}, + Ok(S::Break) => return Ok(()), + Err(err) => return Err(StructWalkError::Tag(err)), + } + }, + Ok(S::Continue) => {}, + Ok(S::Break) => return Ok(()), + Err(err) => return Err(StructWalkError::Tag(err)), } // Give the type name. - match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>( + match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>( visitor, $crate::walkers::core::value::ValueWalker::new(stringify!($name)) ).await { - Ok($crate::Flow::Continue) => {}, - Ok(_) => return Ok(()), - Err(_) => unreachable!(), + Ok(S::Skipped) | Ok(S::Continue) => {}, + Ok(S::Break) => return Ok(()), + Err(err) => return Err(StructWalkError::Tag(err)), } // Give the field names before hand. - match $crate::macros::visit_tag::<{ $crate::TAG_FIELD_NAMES.to_int() }, E, _>( + match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_FIELD_NAMES.to_int() }, E, _>( visitor, $crate::walkers::core::tag::StaticSliceWalker::<_, $crate::walkers::core::value::ValueWalker<&str>>::new(&[$( stringify!($field) ),*]) ).await { - Ok($crate::Flow::Continue) => {}, - Ok(_) => return Ok(()), - // Err(err) => return Err(StructWalkError::Tag(err)), - Err(err) => todo!(), + Ok(S::Skipped) | Ok(S::Continue) => {}, + Ok(S::Break) => return Ok(()), + Err(err) => return Err(StructWalkError::FieldTag(err)), } if !matches!($crate::protocol::visitor::sequence::visit_sequence::<E>( @@ -219,26 +234,30 @@ macro_rules! Walk { 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 { + use $crate::protocol::visitor::Status as S; + 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, _>( + match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_FIELD.to_int() }, E, _>( visitor, $crate::walkers::core::noop::NoopWalker::new() ).await { - Ok($crate::Flow::Continue) => {}, - _ => return Flow::Done, + Ok(S::Skipped) | Ok(S::Continue) => {}, + Ok(S::Break) => return Flow::Break, + Err(err) => return Flow::Break, } - match $crate::macros::visit_tag::<{ $crate::TAG_KEY.to_int() }, E, _>( + match $crate::protocol::visitor::tag::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!(), + Ok(S::Skipped) | Ok(S::Continue) => {}, + Ok(S::Break) => return Flow::Break, + Err(err) => return Flow::Break, } + // Use the type's walker in the same mode as the parent struct. let walker = $crate::Walk::<M, E>::into_walker(&self.value.$field); $crate::Walker::<E>::walk(walker, visitor).await; self.field += 1; |