Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs244
1 files changed, 67 insertions, 177 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 7733233..f444735 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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();