Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 244 |
1 files changed, 67 insertions, 177 deletions
@@ -28,7 +28,7 @@ use core::ops::ControlFlow; pub use build::*; use effect::{Effect, Future}; -use protocol::{Visitor, visitor::tag::TagError}; +use protocol::{visitor::tag::TagError, Visitor}; use symbol::Symbol; pub use transform::*; pub use walk::*; @@ -56,22 +56,18 @@ 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_VALUE: Symbol = Symbol::new("Value"); 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_KEY_VALUE: Symbol = Symbol::new("Key Value"); pub const TAG_ENUM: Symbol = Symbol::new("Enum"); pub enum DefaultMode {} -#[derive(Debug)] -pub enum StructWalkError { - Tag(TagError<never::Never>), - FieldTag(TagError<TagError<never::Never>>), -} - #[must_use] pub enum Flow { /// Processing should continue as normal. @@ -95,196 +91,86 @@ macro_rules! Walk { ),* $(,)?} } => { const _: () = { - impl<'ctx, M, E: $crate::effect::Effect<'ctx>> $crate::Walk<'ctx, M, E> for &'ctx $name { - type Walker = Walker<'ctx, M>; + impl<'ctx, M: 'ctx, E: $crate::effect::Effect<'ctx>> $crate::Walk<'ctx, M, E> for &'ctx $name { + type Walker = $crate::walkers::core::r#struct::StructWalker<'ctx, $name, Info, M, E>; fn into_walker(self) -> Self::Walker { - Walker { - value: self, - field: 0, - _marker: ::core::marker::PhantomData, - } + $crate::walkers::core::r#struct::StructWalker::new(self) } } impl<'ctx> $crate::WalkerTypes for &'ctx $name { - type Error = $crate::StructWalkError; + type Error = $crate::walkers::core::r#struct::StructWalkError<FieldError<'ctx>>; type Output = (); } - pub struct Walker<'ctx, M> { - value: &'ctx $name, - field: usize, - _marker: ::core::marker::PhantomData<fn() -> M>, - } + $vis enum Info {} - impl<'ctx, M> $crate::WalkerTypes for Walker<'ctx, M> { - type Error = $crate::StructWalkError; - type Output = (); - } + #[derive(Debug)] + #[allow(non_camel_case_types)] + enum FieldErrorKind<'ctx> {$( + $field($crate::walkers::core::key_value::KeyValueError<$crate::never::Never, <&'ctx $type as $crate::WalkerTypes>::Error>) + ),*} - 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>, E> - where - Self: 'a - { - E::wrap(async move { - // We should check if the visitor wants something specific. - 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 { - $crate::Flow::Continue => { - // The visitor wants the walker to continue to it's normal - // walking. - }, - _ => { - // The visitor is done (either because of an error or because - // it already used a hint). - return Ok(()); - }, - } - } - - // Attempt to visit the value directly. - if !matches!($crate::protocol::visitor::value::visit_value::<_, E>( - visitor, - $crate::any::static_wrapper::BorrowedStatic(self.value) - ).await, $crate::protocol::visitor::Status::Skipped) { - 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::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(S::Skipped) | Ok(S::Continue) => {}, - Ok(S::Break) => return Ok(()), - Err(err) => return Err(StructWalkError::Tag(err)), - } - - // Signal this is a struct. - match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>( - visitor, - $crate::walkers::core::noop::NoopWalker::new() - ).await { - 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::protocol::visitor::tag::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>( - visitor, - $crate::walkers::core::value::ValueWalker::new(stringify!($name)) - ).await { - 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::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(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>( - visitor, - &mut self, - ).await, $crate::protocol::visitor::Status::Skipped) { - return Ok(()); - } - - Ok(()) - }) - } - } + #[derive(Debug)] + $vis struct FieldError<'ctx>(FieldErrorKind<'ctx>); - 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::protocol::visitor::tag::visit_tag::<{ $crate::TAG_FIELD.to_int() }, E, _>( - visitor, - $crate::walkers::core::noop::NoopWalker::new() - ).await { - Ok(S::Skipped) | Ok(S::Continue) => {}, - Ok(S::Break) => return Flow::Break, - Err(err) => return Flow::Break, - } + impl<'ctx, M: 'ctx> $crate::walkers::core::r#struct::StructTypeInfo<'ctx, M> for Info { + const NAME: &'static str = stringify!($name); + const FIELDS: &'static [&'static str] = &[$(stringify!($field)),*]; - match $crate::protocol::visitor::tag::visit_tag::<{ $crate::TAG_KEY.to_int() }, E, _>( - visitor, - $crate::walkers::core::value::ValueWalker::new(stringify!($field)) - ).await { - Ok(S::Skipped) | Ok(S::Continue) => {}, - Ok(S::Break) => return Flow::Break, - Err(err) => return Flow::Break, - } + type FieldError = FieldError<'ctx>; + type T = $name; - // 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; - Flow::Continue - } - )* - _ => Flow::Done - } - }) - } + #[allow(unreachable_code, non_snake_case, non_upper_case_globals, non_camel_case_types)] + fn walk_field<'a, E: $crate::effect::Effect<'ctx>>( + index: usize, + value: &'ctx Self::T, + visitor: $crate::Visitor<'a, 'ctx>, + ) -> $crate::effect::Future<'a, 'ctx, Result<$crate::Flow, Self::FieldError>, E> { + mod fields { + enum Fields {$($field),*} - 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()))) - } - } + $(pub const $field: usize = Fields::$field as usize;)* + } - $crate::any::any_trait! { - impl['a, 'ctx, M] Walker<'ctx, M> = [ - // dyn Hint<'a, 'ctx, OwnedStatic<bool>, E> + 'a, - ] - } + match index { + $(fields::$field => { + let key_walker = $crate::walkers::core::value::ValueWalker::new(stringify!($field)); + + let value_walker = <&'ctx $type as $crate::Walk::<'ctx, M, E>>::into_walker(&value.$field); + + let walker = $crate::walkers::core::key_value::KeyValueWalker::<$crate::protocol::visitor::tag::TagConst<{ $crate::TAG_FIELD.to_int() }>, _, _>::new($crate::protocol::visitor::tag::TagConst, key_walker, value_walker); + E::map($crate::Walker::<'ctx, E>::walk(walker, visitor), |result| match result { + Ok(_) => { + Ok(Flow::Continue) + } + Err(err) => { + Err(FieldError(FieldErrorKind::$field(err))) + } + }) + })* + _ => E::ready(Ok($crate::Flow::Done)) + } + } + } }; }; } +pub struct Demo { + pub a: bool, + pub b: bool, +} + +Walk! { + pub struct Demo { + a: bool, + b: bool, + } +} + #[cfg(test)] mod test { use crate::effect::{BlockOn, Blocking, Spin}; @@ -306,7 +192,11 @@ mod test { #[test] fn demo() { - let value = Demo { a: true, b: false, other: Other { value: true } }; + let value = Demo { + a: true, + b: false, + other: Other { value: true }, + }; let walker = Walk::<DefaultMode, Blocking>::into_walker(&value); let mut visitor = builders::debug::Visitor::<Blocking>::new(); |