added struct walker
Konnor Andrews 2024-04-09
parent 4b782ac · commit d7365d8
-rw-r--r--Cargo.toml4
-rw-r--r--empty.rs0
-rw-r--r--src/build/builders/debug.rs86
-rw-r--r--src/lib.rs244
-rw-r--r--src/macros.rs1
-rw-r--r--src/protocol/visitor.rs40
-rw-r--r--src/protocol/visitor/recoverable.rs73
-rw-r--r--src/protocol/visitor/request_hint.rs25
-rw-r--r--src/protocol/visitor/sequence.rs16
-rw-r--r--src/protocol/visitor/tag.rs170
-rw-r--r--src/protocol/visitor/value.rs11
-rw-r--r--src/protocol/walker/hint.rs39
-rw-r--r--src/walk.rs24
-rw-r--r--src/walk/walkers/core.rs2
-rw-r--r--src/walk/walkers/core/bool.rs2
-rw-r--r--src/walk/walkers/core/key_value.rs92
-rw-r--r--src/walk/walkers/core/struct.rs647
-rw-r--r--src/walk/walkers/core/tag.rs17
18 files changed, 1126 insertions, 367 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 52316d9..0ca50b9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,10 +9,6 @@ readme = "README.md"
include = ["LICENSE-APACHE", "LICENSE-MIT", "README.md", "empty.rs"]
-[lib]
-name = "treaty"
-path = "empty.rs"
-
[dependencies]
serde = { version = "1.0", default-features = false, optional = true }
diff --git a/empty.rs b/empty.rs
deleted file mode 100644
index e69de29..0000000
--- a/empty.rs
+++ /dev/null
diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs
index 4a51281..cd144d8 100644
--- a/src/build/builders/debug.rs
+++ b/src/build/builders/debug.rs
@@ -10,8 +10,8 @@ use crate::{
visitor::{
request_hint::{DynRequestHint, RequestHint},
sequence::{DynSequence, Sequence},
- tag::{Dyn, DynTag, Tag, DynFlow},
- value::{DynValue, Value},
+ tag::{DynTag, Tag, TagDyn},
+ value::{DynValue, Value}, Status,
},
},
DynWalker, Flow,
@@ -22,7 +22,8 @@ pub struct Visitor<E>(usize, PhantomData<fn() -> E>);
any_trait! {
impl['a, 'ctx, E] Visitor<E> = [
DynRequestHint<'a, 'ctx, E>,
- DynTag<'a, 'ctx, Dyn, E>,
+ // DynRecoverable<'a, 'ctx, E>,
+ DynTag<'a, 'ctx, TagDyn, E>,
DynValue<'a, 'ctx, OwnedStatic<&'static str>, E>,
DynValue<'a, 'ctx, OwnedStatic<TypeId>, E>,
DynValue<'a, 'ctx, OwnedStatic<usize>, E>,
@@ -42,8 +43,11 @@ impl<'ctx, E: Effect<'ctx>> Visitor<E> {
}
fn tab(&self) {
- for _ in 0..self.0 {
- print!(" ");
+ if self.0 > 0 {
+ for _ in 0..self.0 - 1 {
+ print!(" | ");
+ }
+ print!(" |-");
}
}
}
@@ -53,27 +57,53 @@ impl<'ctx, E: Effect<'ctx>> RequestHint<'ctx, E> for Visitor<E> {
&'a mut self,
_walker: crate::protocol::Walker<'a, 'ctx>,
) -> Future<'a, 'ctx, Flow, E> {
- self.tab();
- println!("Visit request hint (no hint given)");
+ // self.tab();
+ // println!("Visit request hint (no hint given)");
+ // println!("Visit request hint (hint for recoverable)");
E::ready(Flow::Continue)
}
}
-impl<'ctx, E: Effect<'ctx>> Tag<'ctx, Dyn, E> for Visitor<E> {
+impl<'ctx, E: Effect<'ctx>> Tag<'ctx, TagDyn, E> for Visitor<E> {
fn visit<'a>(
&'a mut self,
- kind: Dyn,
+ kind: TagDyn,
walker: DynWalker<'a, 'ctx, E>,
- ) -> Future<'a, 'ctx, DynFlow, E> {
- self.tab();
- println!("Visit tag: {}", kind.0);
-
- E::wrap(async {
- self.0 += 1;
- let result = walker.walk(self).await;
- self.0 -= 1;
- // DynFlow::Flow(result)
- DynFlow::Skipped
+ ) -> Future<'a, 'ctx, Status, E> {
+ E::wrap(async move {
+ match kind.0 {
+ crate::TAG_TYPE_NAME => {
+ self.tab();
+ println!("type name:");
+
+ self.0 += 1;
+ walker.walk(self).await;
+ self.0 -= 1;
+
+ Status::r#continue()
+ },
+ crate::TAG_KEY => {
+ self.tab();
+ println!("key:");
+
+ self.0 += 1;
+ walker.walk(self).await;
+ self.0 -= 1;
+
+ Status::r#continue()
+ },
+ crate::TAG_VALUE => {
+ self.tab();
+ println!("value:");
+
+ self.0 += 1;
+ walker.walk(self).await;
+ self.0 -= 1;
+
+ Status::r#continue()
+ },
+ _ => Status::skipped()
+ }
})
}
}
@@ -87,7 +117,7 @@ impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>, E
Self: 'a,
{
self.tab();
- println!("Visit static str: {:?}", value);
+ println!("{:?}", value);
E::ready(Flow::Continue)
}
}
@@ -98,7 +128,7 @@ impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<usize>, E> for V
Self: 'a,
{
self.tab();
- println!("Visit usize: {}", value);
+ println!("{}", value);
E::ready(Flow::Continue)
}
}
@@ -109,7 +139,7 @@ impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for Vi
Self: 'a,
{
self.tab();
- println!("Visit bool: {}", value);
+ println!("{}", value);
E::ready(Flow::Continue)
}
}
@@ -125,7 +155,7 @@ impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static [&'stat
Self: 'a,
{
self.tab();
- println!("Visit static slice of static str: {:?}", value);
+ println!("{:?}", value);
E::ready(Flow::Continue)
}
}
@@ -146,20 +176,22 @@ impl<'ctx, E: Effect<'ctx>> Sequence<'ctx, E> for Visitor<E> {
&'a mut self,
scope: protocol::visitor::sequence::DynSequenceScope<'a, 'ctx, E>,
) -> Future<'a, 'ctx, Flow, E> {
- self.tab();
E::wrap(async {
- println!("Visit sequence, size hint: {:?}", scope.size_hint().await);
+ self.tab();
+ println!("sequence{:?}", scope.size_hint().await);
+
self.0 += 1;
let mut index = 0;
let flow = loop {
self.tab();
- println!("Calling next: {}", index);
+ println!("{}:", index);
+
self.0 += 1;
match scope.next(self).await {
Flow::Done => {
self.tab();
- println!("Sequence done");
+ println!("<end>");
break Flow::Continue;
}
Flow::Continue => {}
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();
diff --git a/src/macros.rs b/src/macros.rs
index e69de29..8b13789 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -0,0 +1 @@
+
diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs
index aad879d..9fc98c0 100644
--- a/src/protocol/visitor.rs
+++ b/src/protocol/visitor.rs
@@ -1,15 +1,41 @@
+use crate::Flow;
+
+pub mod recoverable;
pub mod request_hint;
pub mod sequence;
pub mod tag;
pub mod value;
-pub enum Status {
- /// The protocol was used.
- Continue,
-
+pub enum Status<S = ()> {
/// The protocol was not used.
- Skipped,
+ Skipped(S),
+
+ Flow(Flow)
+}
+
+impl<S> Status<S> {
+ pub fn r#continue() -> Self {
+ Self::Flow(Flow::Continue)
+ }
+
+ pub fn done() -> Self {
+ Self::Flow(Flow::Done)
+ }
- /// Should stop processing.
- Break,
+ pub fn r#break() -> Self {
+ Self::Flow(Flow::Break)
+ }
}
+
+impl Status {
+ pub fn skipped() -> Self {
+ Self::Skipped(())
+ }
+}
+
+impl From<Flow> for Status {
+ fn from(value: Flow) -> Self {
+ Status::Flow(value)
+ }
+}
+
diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs
new file mode 100644
index 0000000..f2d12f7
--- /dev/null
+++ b/src/protocol/visitor/recoverable.rs
@@ -0,0 +1,73 @@
+use crate::{
+ effect::{Effect, Future},
+ higher_ranked_type,
+ hkt::AnySend,
+ nameable,
+ protocol::{walker::hint::HintMeta, Visitor},
+ Flow,
+};
+
+use super::Status;
+
+pub trait Recoverable<'ctx, E: Effect<'ctx>> {
+ fn visit<'a>(
+ &'a mut self,
+ scope: DynRecoverableScope<'a, 'ctx, E>,
+ ) -> Future<'a, 'ctx, Flow, E>;
+}
+
+pub type DynRecoverable<'a, 'ctx, E> = &'a mut (dyn Recoverable<'ctx, E> + Send + 'a);
+
+nameable! {
+ pub struct Name['a, 'ctx, E];
+
+ impl [E] for DynRecoverable<'a, 'ctx, E> where {
+ E: Effect<'ctx>,
+ 'ctx: 'a
+ }
+
+ impl [E] where DynRecoverable<'a, 'ctx, E> {
+ E: Effect<'ctx>,
+ 'ctx: 'a
+ }
+}
+
+pub trait RecoverableScope<'ctx, E: Effect<'ctx>> {
+ fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>;
+}
+
+pub type DynRecoverableScope<'a, 'ctx, E> = &'a mut (dyn RecoverableScope<'ctx, E> + Send + 'a);
+
+higher_ranked_type! {
+ pub type RecoverableKnownHkt['ctx]: (AnySend) = for<'lt> ()
+}
+
+impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for DynRecoverable<'a, 'ctx, E> {
+ type Known = RecoverableKnownHkt<'ctx>;
+
+ type Hint = ();
+}
+
+pub fn visit_recoverable<'a, 'ctx, E: Effect<'ctx>>(
+ visitor: Visitor<'a, 'ctx>,
+ scope: DynRecoverableScope<'a, 'ctx, E>,
+) -> Future<'a, 'ctx, Status, E> {
+ if let Some(object) = visitor.upcast_mut::<DynRecoverable<'_, 'ctx, E>>() {
+ // Allow the visitor to give a hint if it wants.
+ E::map(object.visit(scope), |flow| match flow {
+ Flow::Continue => {
+ // The visitor wants the walker to continue to it's normal
+ // walking.
+ Status::r#continue()
+ }
+ Flow::Break | Flow::Done => {
+ // The visitor is done (either because of an error or because
+ // it already used a hint).
+ Status::r#break()
+ }
+ })
+ } else {
+ // If the visitor doesn't support request hint then we continue.
+ E::ready(Status::skipped())
+ }
+}
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index 50ae76d..f70fc29 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -1,7 +1,6 @@
use crate::{
effect::{Effect, Future},
nameable,
- never::Never,
protocol::{Visitor, Walker},
Flow,
};
@@ -27,28 +26,20 @@ nameable! {
/// Visit using the [`RequestHint`] protocol.
///
-/// If `true` is returned then the walker should stop.
-/// This is either because of an error or the visitor is done.
+/// If [`Flow::Continue`] is returned then the visitor wants/needs more information it didn't get
+/// from the hints.
+/// If [`Flow::Done`] is returned then the visitor doesn't need any more information and the walker
+/// should stop walking.
+/// If [`Flow::Break`] is returned then there was an error and the walker should stop walking.
pub fn visit_request_hint<'a, 'ctx, E: Effect<'ctx>>(
visitor: Visitor<'a, 'ctx>,
walker: Walker<'a, 'ctx>,
-) -> Future<'a, 'ctx, bool, E> {
+) -> Future<'a, 'ctx, Flow, E> {
if let Some(object) = visitor.upcast_mut::<DynRequestHint<'_, 'ctx, E>>() {
// Allow the visitor to give a hint if it wants.
- E::map(object.request_hint(walker), |flow| match flow {
- Flow::Continue => {
- // The visitor wants the walker to continue to it's normal
- // walking.
- false
- }
- _ => {
- // The visitor is done (either because of an error or because
- // it already used a hint).
- true
- }
- })
+ object.request_hint(walker)
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(false)
+ E::ready(Flow::Continue)
}
}
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index 8c7b2e4..d313e5b 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -38,22 +38,22 @@ pub trait SequenceScope<'ctx, E: Effect<'ctx>> {
pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + 'a);
higher_ranked_type! {
- pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known
+ pub type SequenceKnownHkt['ctx]: (AnySend) = for<'lt> SequenceKnown
}
#[derive(Default)]
-pub struct Known {
+pub struct SequenceKnown {
pub len: (usize, Option<usize>),
}
-pub struct Hint {
+pub struct SequenceHint {
pub len: (usize, Option<usize>),
}
impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for DynSequence<'a, 'ctx, E> {
- type Known = KnownHkt<'ctx>;
+ type Known = SequenceKnownHkt<'ctx>;
- type Hint = Hint;
+ type Hint = SequenceHint;
}
pub fn visit_sequence<'a, 'ctx, E: Effect<'ctx>>(
@@ -66,16 +66,16 @@ pub fn visit_sequence<'a, 'ctx, E: Effect<'ctx>>(
Flow::Continue => {
// The visitor wants the walker to continue to it's normal
// walking.
- Status::Continue
+ Status::r#continue()
}
Flow::Break | Flow::Done => {
// The visitor is done (either because of an error or because
// it already used a hint).
- Status::Break
+ Status::r#break()
}
})
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(Status::Skipped)
+ E::ready(Status::skipped())
}
}
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index 2747c95..6a4fc1e 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -5,21 +5,24 @@ use crate::{
nameable,
protocol::{walker::hint::HintMeta, Visitor},
symbol::Symbol,
- DynWalker, Flow, WalkerTypes, DynWalkerAdapter, DynWalkerError,
+ DynWalker, DynWalkerAdapter, DynWalkerError, Flow, WalkerTypes,
};
use super::Status;
-pub trait Kind: 'static {
- type Flow: Send;
+pub trait TagKind: Copy + Send + 'static {
+ type Flow: Send + Into<Status>;
fn symbol(&self) -> Symbol;
}
-pub struct Const<const SYMBOL: u64>;
-pub struct Dyn(pub Symbol);
+#[derive(Copy, Clone)]
+pub struct TagConst<const SYMBOL: u64>;
-impl<const SYMBOL: u64> Kind for Const<SYMBOL> {
+#[derive(Copy, Clone)]
+pub struct TagDyn(pub Symbol);
+
+impl<const SYMBOL: u64> TagKind for TagConst<SYMBOL> {
type Flow = Flow;
fn symbol(&self) -> Symbol {
@@ -27,20 +30,15 @@ impl<const SYMBOL: u64> Kind for Const<SYMBOL> {
}
}
-pub enum DynFlow {
- Skipped,
- Flow(Flow),
-}
-
-impl Kind for Dyn {
- type Flow = DynFlow;
+impl TagKind for TagDyn {
+ type Flow = Status;
fn symbol(&self) -> Symbol {
self.0
}
}
-pub trait Tag<'ctx, K: Kind, E: Effect<'ctx>> {
+pub trait Tag<'ctx, K: TagKind, E: Effect<'ctx>> {
fn visit<'a>(
&'a mut self,
kind: K,
@@ -54,34 +52,34 @@ nameable! {
pub struct Name['a, 'ctx, K, E];
impl [K, E] for DynTag<'a, 'ctx, K, E> where {
- K: Kind,
+ K: TagKind,
E: Effect<'ctx>,
'ctx: 'a
}
impl [K, E] where DynTag<'a, 'ctx, K, E> {
- K: Kind,
+ K: TagKind,
E: Effect<'ctx>,
'ctx: 'a
}
}
higher_ranked_type! {
- pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known
+ pub type TagKnownHkt['ctx]: (AnySend) = for<'lt> TagKnown
}
-pub struct Known {
+pub struct TagKnown {
pub kind_available: Option<bool>,
}
-pub struct Hint<K> {
- pub kind: Option<K>,
+pub struct TagHint<K> {
+ pub kind: K,
}
impl<'a, 'ctx: 'a, K, E> HintMeta<'ctx> for DynTag<'a, 'ctx, K, E> {
- type Known = KnownHkt<'ctx>;
+ type Known = TagKnownHkt<'ctx>;
- type Hint = Hint<K>;
+ type Hint = TagHint<K>;
}
#[derive(Debug)]
@@ -89,10 +87,12 @@ pub enum TagErrorKind<E> {
NeverWalked,
/// This can only happen if a panic happens furing the walk and is then caught before calling
- /// finish..
+ /// finish.
WalkNeverFinished,
Walker(E),
+
+ SkippedWasWalked,
}
#[derive(Debug)]
@@ -102,92 +102,98 @@ pub struct TagError<E> {
}
impl<E> TagError<E> {
- fn new<const SYMBOL: u64>(err: E) -> Self {
+ fn new<K: TagKind>(tag: K, err: E) -> Self {
Self {
- symbol: Symbol::from_int(SYMBOL),
+ symbol: tag.symbol(),
err: TagErrorKind::Walker(err),
}
}
- fn never_walked<const SYMBOL: u64>() -> Self {
+ fn never_walked<K: TagKind>(tag: K) -> Self {
Self {
- symbol: Symbol::from_int(SYMBOL),
+ symbol: tag.symbol(),
err: TagErrorKind::NeverWalked,
}
}
- fn walk_never_finished<const SYMBOL: u64>() -> Self {
+ fn walk_never_finished<K: TagKind>(tag: K) -> Self {
Self {
- symbol: Symbol::from_int(SYMBOL),
+ symbol: tag.symbol(),
err: TagErrorKind::WalkNeverFinished,
}
}
-}
+ fn was_walked<K: TagKind>(tag: K) -> Self {
+ Self {
+ symbol: tag.symbol(),
+ err: TagErrorKind::SkippedWasWalked,
+ }
+ }
+}
-pub fn visit_tag<'a, 'ctx: 'a, const SYMBOL: u64, E: Effect<'ctx>, W: crate::Walker<'ctx, E> + 'a>(
+pub fn visit_tag<'a, 'ctx: 'a, K: TagKind, E: Effect<'ctx>, W: crate::Walker<'ctx, E> + 'a>(
+ kind: K,
visitor: Visitor<'a, 'ctx>,
walker: W,
-) -> Future<'a, 'ctx, Result<Status, TagError<W::Error>>, E>
+) -> Future<'a, 'ctx, Result<Status<W>, TagError<W::Error>>, E>
where
- W: WalkerTypes<Output = ()>,
+ W: WalkerTypes,
{
- E::wrap(async {
- let result =
- if let Some(object) = visitor.upcast_mut::<DynTag<'_, 'ctx, Const<SYMBOL>, E>>() {
- // The visitor knows about this tag at compile time.
+ E::wrap(async move {
+ let (flow, walker) =
+ if let Some(object) = visitor.upcast_mut::<DynTag<'_, 'ctx, K, E>>() {
+ // The visitor knows about this tag.
// Wrap the walker to allow it to be passed to a dyn walker argument.
- let mut name_walker = DynWalkerAdapter::new(walker);
+ let mut walker = DynWalkerAdapter::new(walker);
// Visit the tag.
- let flow = object.visit(Const, &mut name_walker).await;
-
- // Finish the dynamic walker to get any errors from it.
- let result = name_walker.finish();
-
- (DynFlow::Flow(flow), result)
- } else if let Some(object) = visitor.upcast_mut::<DynTag<'_, 'ctx, 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(Dyn(Symbol::from_int(SYMBOL)), &mut name_walker)
- .await;
-
- // Finish the dynamic walker to get any errors from it.
- let result = name_walker.finish();
-
- (flow, result)
+ let flow = object.visit(kind, &mut walker).await;
+
+ (flow.into(), walker)
+ } else if core::any::TypeId::of::<TagDyn>() != core::any::TypeId::of::<K>() {
+ // Try the dynamic form if we didn't already.
+ if let Some(object) = visitor.upcast_mut::<DynTag<'_, 'ctx, TagDyn, 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 walker = DynWalkerAdapter::new(walker);
+
+ // Visit the tag.
+ let flow = object
+ .visit(TagDyn(kind.symbol()), &mut walker)
+ .await;
+
+ (flow, walker)
+ } else {
+ return Ok(Status::Skipped(walker));
+ }
} else {
- return Ok(Status::Skipped);
+ return Ok(Status::Skipped(walker));
};
- match result {
- // The happy path.
- (DynFlow::Flow(Flow::Continue), Ok(_)) => Ok(Status::Continue),
-
- // The visitor wants to stop the control flow for some reason.
- (DynFlow::Flow(Flow::Break), Ok(_)) => Ok(Status::Break),
- (DynFlow::Flow(Flow::Done), Ok(_)) => Ok(Status::Break),
- (DynFlow::Skipped, Ok(_)) => Ok(Status::Skipped),
-
- // The walker had an error.
- (_, Err(DynWalkerError::Walker(err))) => Err(TagError::new::<SYMBOL>(err)),
-
- // The visitor never walked the dynamic walker. Aka it didn't call walk.
- (_, Err(DynWalkerError::NeverWalked(_))) => 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)) => {
- Err(TagError::walk_never_finished::<SYMBOL>())
- }
+ match flow {
+ // The walker was skipped.
+ Status::Skipped(()) => {
+ match walker.into_innter() {
+ Ok(walker) => Ok(Status::Skipped(walker)),
+ Err(DynWalkerError::Walker(err)) => Err(TagError::new(kind, err)),
+ Err(DynWalkerError::NeverWalked(_)) => Err(TagError::never_walked(kind)),
+ Err(DynWalkerError::WalkNeverFinished) => Err(TagError::walk_never_finished(kind)),
+ Err(DynWalkerError::WasWalked(_)) => Err(TagError::was_walked(kind)),
+ }
+ },
+ Status::Flow(flow) => {
+ match walker.finish() {
+ Ok(_) => Ok(Status::Flow(flow)),
+ Err(DynWalkerError::Walker(err)) => Err(TagError::new(kind, err)),
+ Err(DynWalkerError::NeverWalked(_)) => Err(TagError::never_walked(kind)),
+ Err(DynWalkerError::WalkNeverFinished) => Err(TagError::walk_never_finished(kind)),
+ Err(DynWalkerError::WasWalked(_)) => Err(TagError::was_walked(kind)),
+ }
+ },
}
})
}
diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs
index 8e7902c..3e9a3bc 100644
--- a/src/protocol/visitor/value.rs
+++ b/src/protocol/visitor/value.rs
@@ -8,7 +8,6 @@ use crate::{
higher_ranked_type,
hkt::AnySend,
nameable,
- never::Never,
protocol::{walker::hint::HintMeta, Visitor},
Flow,
};
@@ -50,12 +49,12 @@ nameable! {
}
higher_ranked_type! {
- pub type Known['ctx]: (AnySend) = for<'lt> ()
+ pub type ValueKnownHkt['ctx]: (AnySend) = for<'lt> ()
}
// This enrolls the Value protocol into the walker hint system.
impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> HintMeta<'ctx> for DynValue<'a, 'ctx, T, E> {
- type Known = Known<'ctx>;
+ type Known = ValueKnownHkt<'ctx>;
type Hint = ();
}
@@ -70,17 +69,17 @@ pub fn visit_value<'a, 'ctx, T: TypeNameable<'a, 'ctx>, E: Effect<'ctx>>(
Flow::Continue => {
// The visitor wants the walker to continue to it's normal
// walking.
- Status::Continue
+ Status::r#continue()
}
Flow::Break | Flow::Done => {
// The visitor is done (either because of an error or because
// it already used a hint).
- Status::Break
+ Status::r#break()
}
})
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(Status::Skipped)
+ E::ready(Status::skipped())
}
}
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index 52da09b..16b2515 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -12,6 +12,7 @@ use crate::{
hkt::AnySend,
nameable,
protocol::Visitor,
+ Flow,
};
/// Meta information for the hint.
@@ -31,35 +32,35 @@ pub trait HintMeta<'ctx> {
pub type Known<'a, 'ctx, Protocol> = AnySend::T<'a, 'ctx, <Protocol as HintMeta<'ctx>>::Known>;
/// Object implementing the [`Hint`] protocol.
-pub trait Hint<'ctx, Protocol: ?Sized + HintMeta<'ctx>> {
- type Effect: Effect<'ctx>;
-
+pub trait Hint<'a, 'ctx: 'a, Protocol: ?Sized + HintMeta<'ctx>, E: Effect<'ctx>> {
/// Hint to the walker to use the `P` protocol.
///
/// This should only be called once per [`RequestHint`].
- fn hint<'a>(
+ fn hint(
&'a mut self,
visitor: Visitor<'a, 'ctx>,
hint: <Protocol as HintMeta<'ctx>>::Hint,
- ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>;
+ ) -> Future<'a, 'ctx, Flow, E>;
/// Ask the walker for information about it's support of the protocol.
- fn known<'a>(
+ fn known(
&'a mut self,
hint: &'a <Protocol as HintMeta<'ctx>>::Hint,
- ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Protocol>>, Self::Effect>;
+ ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, Protocol>, ()>, E>;
}
+pub type DynHint<'a, 'ctx, Protocol, E> = dyn Hint<'a, 'ctx, Protocol, E> + Send + 'a;
+
nameable! {
pub struct Name['a, 'ctx, Protocol, E];
- impl [Protocol::Name, E] for dyn Hint<'ctx, Protocol, Effect = E> + 'a where {
+ impl [Protocol::Name, E] for DynHint<'a, 'ctx, Protocol, E> where {
Protocol: TypeNameable<'a, 'ctx> + ?Sized,
E: Effect<'ctx>,
'ctx: 'a,
}
- impl [Protocol, E] where dyn Hint<'ctx, Protocol::Nameable, Effect = E> + 'a {
+ impl [Protocol, E] where DynHint<'a, 'ctx, Protocol::Nameable, E> {
Protocol: TypeName<'a, 'ctx> + ?Sized,
E: Effect<'ctx>,
'ctx: 'a,
@@ -90,22 +91,20 @@ mod test {
impl for Y where {}
}
- impl<'ctx> Hint<'ctx, Y> for X<'ctx> {
- type Effect = Blocking;
-
- fn hint<'a>(
+ impl<'a, 'ctx: 'a, E: Effect<'ctx>> Hint<'a, 'ctx, Y, E> for X<'ctx> {
+ fn hint(
&'a mut self,
_visitor: Visitor<'a, 'ctx>,
_hint: <Y as HintMeta<'ctx>>::Hint,
- ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> {
+ ) -> Future<'a, 'ctx, Flow, E> {
todo!()
}
- fn known<'a>(
+ fn known(
&'a mut self,
_hint: &'a <Y as HintMeta<'ctx>>::Hint,
- ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Y>>, Self::Effect> {
- Self::Effect::wrap(async { ControlFlow::Continue(&mut *self.0) })
+ ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, Y>, ()>, E> {
+ E::ready(Ok(&mut *self.0))
}
}
@@ -121,15 +120,15 @@ mod test {
let mut z = 42;
let mut x = X(&mut z);
- let y: &mut dyn Hint<'_, Y, Effect = Blocking> = &mut x;
+ let y: &mut DynHint<'_, '_, Y, Blocking> = &mut x;
fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(_x: &T) {}
id(y);
let x = Spin::block_on(y.known(&()));
match x {
- ControlFlow::Continue(value) => *value += 1,
- ControlFlow::Break(_) => todo!(),
+ Ok(value) => *value += 1,
+ Err(_) => todo!(),
}
assert_eq!(z, 43);
}
diff --git a/src/walk.rs b/src/walk.rs
index 0dbccee..c99251d 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -11,6 +11,7 @@ pub trait Walk<'ctx, M, E: Effect<'ctx>>: WalkerTypes + Sized {
/// The walker for the type.
type Walker: Walker<'ctx, E, Error = Self::Error, Output = Self::Output>;
+ #[must_use]
fn into_walker(self) -> Self::Walker;
}
@@ -48,14 +49,11 @@ pub trait WalkerObjSafe<'ctx, E: Effect<'ctx>>: Send {
fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>
where
Self: 'a;
-
- fn skip(&mut self);
}
pub type DynWalker<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, E> + Send + 'a);
enum DynWalkerState<W: WalkerTypes> {
- Skipped,
Walking,
Pending(W),
Done(W::Output),
@@ -70,6 +68,8 @@ pub enum DynWalkerError<W: WalkerTypes> {
WalkNeverFinished,
Walker(W::Error),
+
+ WasWalked(W::Output),
}
pub struct DynWalkerAdapter<W: WalkerTypes> {
@@ -83,12 +83,20 @@ impl<W: WalkerTypes> DynWalkerAdapter<W> {
}
}
- pub fn finish(self) -> Result<Option<W::Output>, DynWalkerError<W>> {
+ pub fn finish(self) -> Result<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(value) => Ok(Some(value)),
+ DynWalkerState::Done(value) => Ok(value),
+ DynWalkerState::Err(err) => Err(DynWalkerError::Walker(err)),
+ }
+ }
+
+ pub fn into_innter(self) -> Result<W, DynWalkerError<W>> {
+ match self.state {
+ DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished),
+ DynWalkerState::Pending(walker) => Ok(walker),
+ DynWalkerState::Done(value) => Err(DynWalkerError::WasWalked(value)),
DynWalkerState::Err(err) => Err(DynWalkerError::Walker(err)),
}
}
@@ -123,8 +131,4 @@ impl<'ctx, W: Walker<'ctx, E>, E: Effect<'ctx>> WalkerObjSafe<'ctx, E> for DynWa
}
})
}
-
- fn skip(&mut self) {
- self.state = DynWalkerState::Skipped;
- }
}
diff --git a/src/walk/walkers/core.rs b/src/walk/walkers/core.rs
index 172244d..b1cc7af 100644
--- a/src/walk/walkers/core.rs
+++ b/src/walk/walkers/core.rs
@@ -2,5 +2,7 @@
pub mod bool;
pub mod noop;
+pub mod r#struct;
pub mod tag;
pub mod value;
+pub mod key_value;
diff --git a/src/walk/walkers/core/bool.rs b/src/walk/walkers/core/bool.rs
index a3f2a93..5e173fa 100644
--- a/src/walk/walkers/core/bool.rs
+++ b/src/walk/walkers/core/bool.rs
@@ -1,6 +1,6 @@
use crate::{effect::Effect, Walk, WalkerTypes};
-use super::value::{ValueWalker, BorrowWalker};
+use super::value::{BorrowWalker, ValueWalker};
impl<'ctx, M, E: Effect<'ctx>> Walk<'ctx, M, E> for bool {
type Walker = ValueWalker<bool>;
diff --git a/src/walk/walkers/core/key_value.rs b/src/walk/walkers/core/key_value.rs
new file mode 100644
index 0000000..3ac5b6b
--- /dev/null
+++ b/src/walk/walkers/core/key_value.rs
@@ -0,0 +1,92 @@
+use crate::{never::Never, WalkerTypes, effect::{Effect, Future}, protocol::{Visitor, visitor::{tag::{visit_tag, TagKind, TagConst, TagError}, Status}}, walkers::core::noop::NoopWalker, TAG_KEY_VALUE, Flow, TAG_KEY, TAG_VALUE};
+
+pub struct KeyValueWalker<T, K, V> {
+ key_walker: K,
+ value_walker: V,
+ tag: T,
+}
+
+impl<T, K, V> KeyValueWalker<T, K, V> {
+ pub fn new(tag: T, key_walker: K, value_walker: V) -> Self {
+ Self {
+ key_walker,
+ value_walker,
+ tag,
+ }
+ }
+}
+
+#[derive(Debug)]
+enum KeyValueErrorKind<K, V> {
+ Tag(TagError<Never>),
+ Key(K),
+ Value(V),
+}
+
+#[derive(Debug)]
+pub struct KeyValueError<K, V>(KeyValueErrorKind<K, V>);
+
+impl<T, K, V> WalkerTypes for KeyValueWalker<T, K, V>
+where
+ K: WalkerTypes,
+ V: WalkerTypes,
+{
+ type Error = KeyValueError<K::Error, V::Error>;
+
+ type Output = ();
+}
+
+impl<'ctx, T, K, V, E> crate::Walker<'ctx, E> for KeyValueWalker<T, K, V>
+where
+ E: Effect<'ctx>,
+ T: TagKind,
+ K: crate::Walker<'ctx, E>,
+ V: crate::Walker<'ctx, E>,
+{
+ fn walk<'a>(
+ self,
+ visitor: Visitor<'a, 'ctx>,
+ ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E>
+ where
+ Self: 'a
+ {
+ E::wrap(async move {
+ match visit_tag::<T, E, _>(self.tag, visitor, NoopWalker::new()).await {
+ Ok(Status::Skipped(_)) => {
+ match visit_tag::<TagConst<{ TAG_KEY_VALUE.to_int() }>, E, _>(TagConst, visitor, NoopWalker::new()).await
+ {
+ Ok(Status::Skipped(_) | Status::Flow(Flow::Continue)) => {},
+ Ok(Status::Flow(flow)) => return Ok(()),
+ Err(_) => todo!(),
+ }
+ }
+ Ok(Status::Flow(Flow::Continue)) => {},
+ Ok(Status::Flow(flow)) => todo!(),
+ Err(_) => todo!(),
+ }
+
+ match visit_tag::<TagConst<{ TAG_KEY.to_int() }>, E, _>(TagConst, visitor, self.key_walker).await
+ {
+ Ok(Status::Skipped(_) | Status::Flow(Flow::Continue)) => {},
+ Ok(Status::Flow(flow)) => return Ok(()),
+ Err(_) => todo!(),
+ }
+
+ match visit_tag::<TagConst<{ TAG_VALUE.to_int() }>, E, _>(TagConst, visitor, self.value_walker).await
+ {
+ Ok(Status::Flow(Flow::Continue)) => {},
+ Ok(Status::Skipped(value_walker)) => {
+ // Fallback to just walking the value.
+ match value_walker.walk(visitor).await {
+ Ok(_) => {},
+ Err(err) => todo!(),
+ }
+ },
+ Ok(Status::Flow(flow)) => todo!(),
+ Err(_) => todo!(),
+ }
+
+ Ok(())
+ })
+ }
+}
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
new file mode 100644
index 0000000..a07557f
--- /dev/null
+++ b/src/walk/walkers/core/struct.rs
@@ -0,0 +1,647 @@
+use core::{any::TypeId, marker::PhantomData};
+
+use crate::{
+ any::static_wrapper::BorrowedStatic,
+ any_trait,
+ effect::{Effect, Future},
+ never::Never,
+ protocol::{
+ visitor::{
+ recoverable::{visit_recoverable, DynRecoverable, RecoverableScope},
+ request_hint::visit_request_hint,
+ sequence::{visit_sequence, DynSequence, SequenceKnown, SequenceScope},
+ tag::{visit_tag, DynTag, TagConst, TagDyn, TagError, TagHint, TagKnown},
+ value::{visit_value, DynValue},
+ Status,
+ },
+ walker::hint::{DynHint, HintMeta},
+ walker::hint::{Hint, Known},
+ Visitor,
+ },
+ Flow, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, TAG_TYPE_NAME,
+};
+
+use super::{noop::NoopWalker, tag::StaticSliceWalker, value::ValueWalker};
+
+/// Walker for a borrow of a struct.
+///
+/// This walker implements the struct flow. The struct cannot contain lifetimes.
+pub struct StructWalker<'ctx, T, I: StructTypeInfo<'ctx, M>, M, E> {
+ /// Struct value to walk.
+ value: &'ctx T,
+
+ /// Index of the current field to walk.
+ index: usize,
+
+ /// Error if there was one.
+ ///
+ /// The visitor tracks it's own errors.
+ error: Option<StructWalkErrorKind<I::FieldError>>,
+
+ _marker: PhantomData<fn() -> (I, M, E)>,
+}
+
+/// Type info about a struct needed by [`StructWalker`].
+pub trait StructTypeInfo<'ctx, M>: 'static {
+ /// Name of the struct.
+ const NAME: &'static str;
+
+ /// The field names in definition order.
+ const FIELDS: &'static [&'static str];
+
+ /// The walking errors for the fields.
+ type FieldError: Send;
+
+ /// The struct being described.
+ type T: Send;
+
+ /// Walk the given field.
+ fn walk_field<'a, E: Effect<'ctx>>(
+ index: usize,
+ value: &'ctx Self::T,
+ visitor: Visitor<'a, 'ctx>,
+ ) -> Future<'a, 'ctx, Result<Flow, Self::FieldError>, E>;
+}
+
+#[derive(Debug)]
+enum StructWalkErrorKind<T> {
+ /// Error with visiting a tag for the struct.
+ ///
+ /// This error shouldn't really happen if the visitor behaves.
+ Tag(TagError<Never>),
+
+ /// Error with visiting a tag for a struct's field.
+ ///
+ /// This error shouldn't really happen if the visitor behaves.
+ FieldTag(TagError<TagError<Never>>),
+
+ /// Error with visiting a field.
+ Field(T),
+}
+
+/// Error from walking a struct.
+#[derive(Debug)]
+pub struct StructWalkError<T> {
+ kind: StructWalkErrorKind<T>,
+}
+
+impl<'ctx, T, I, M, E> StructWalker<'ctx, T, I, M, E>
+where
+ I: StructTypeInfo<'ctx, M>,
+{
+ /// Create walker from a borrow of a struct.
+ pub fn new(value: &'ctx T) -> Self {
+ Self {
+ value,
+ index: 0,
+ error: None,
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<'ctx, T, I, M, E> WalkerTypes for StructWalker<'ctx, T, I, M, E>
+where
+ I: StructTypeInfo<'ctx, M>,
+{
+ type Error = StructWalkError<I::FieldError>;
+ type Output = ();
+}
+
+impl<'ctx, T, I, E, M> crate::Walker<'ctx, E> for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M, T = T>,
+ T: Sync + 'static,
+{
+ fn walk<'a>(
+ mut self,
+ visitor: Visitor<'a, 'ctx>,
+ ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E>
+ where
+ Self: 'a,
+ {
+ E::wrap(async {
+ // Use the recoverable walk to not duplicate the code.
+ let _ = RecoverableScope::<'ctx, E>::new_walk(&mut self, visitor).await;
+
+ // Get the error if there was one.
+ match self.error {
+ Some(err) => Err(StructWalkError { kind: err }),
+ None => Ok(()),
+ }
+ })
+ }
+}
+
+any_trait! {
+ impl['a, 'ctx, T, I, M, E] StructWalker<'ctx, T, I, M, E> = [
+ DynHint<'a, 'ctx, DynRecoverable<'a, 'ctx, E>, E>,
+ DynHint<'a, 'ctx, DynSequence<'a, 'ctx, E>, E>,
+ DynHint<'a, 'ctx, DynValue<'a, 'ctx, BorrowedStatic<'ctx, T>, E>, E>,
+ DynHint<'a, 'ctx, DynTag<'a, 'ctx, TagDyn, E>, E>,
+ DynHint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>,
+ DynHint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_STRUCT.to_int() }>, E>, E>,
+ DynHint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_MAP.to_int() }>, E>, E>,
+ DynHint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, E>,
+ DynHint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E>,
+ ] where
+ E: Effect<'ctx>,
+ T: Sync + 'static,
+ I: StructTypeInfo<'ctx, M, T = T>
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E> Hint<'a, 'ctx, DynRecoverable<'a, 'ctx, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M, T = T>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynRecoverable<'a, 'ctx, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_recoverable::<E>(visitor, self),
+ |status| match status {
+ Status::Skipped(_) => Flow::Continue,
+ Status::Flow(flow) => flow,
+ },
+ )
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynRecoverable<'a, 'ctx, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, DynRecoverable<'a, 'ctx, E>>, ()>, E> {
+ E::ready(Ok(()))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E>
+ Hint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynTag<'a, 'ctx, TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>(
+ TagConst,
+ visitor,
+ StaticSliceWalker::<_, ValueWalker<&'static str>>::new(I::FIELDS),
+ ),
+ |status| match status {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::FieldTag(err));
+ Flow::Break
+ }
+ Ok(Status::Skipped(_)) => Flow::Continue,
+ Ok(Status::Flow(flow)) => flow,
+ },
+ )
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynTag<'a, 'ctx, TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta<
+ 'ctx,
+ >>::Hint,
+ ) -> Future<
+ 'a,
+ 'ctx,
+ Result<Known<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ()>,
+ E,
+ > {
+ E::ready(Ok(TagKnown {
+ kind_available: Some(true),
+ }))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E>
+ Hint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_tag::<TagConst<{ TAG_TYPE_NAME.to_int() }>, E, _>(TagConst, visitor, ValueWalker::new(I::NAME)),
+ |status| match status {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ Flow::Break
+ }
+ Ok(Status::Skipped(_)) => Flow::Continue,
+ Ok(Status::Flow(flow)) => flow,
+ },
+ )
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<
+ 'a,
+ 'ctx,
+ Result<Known<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ()>,
+ E,
+ > {
+ E::ready(Ok(TagKnown {
+ kind_available: Some(true),
+ }))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E>
+ Hint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_MAP.to_int() }>, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynTag<'a, 'ctx, TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>(TagConst, visitor, NoopWalker::new()),
+ |status| match status {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ Flow::Break
+ }
+ Ok(Status::Skipped(_)) => Flow::Continue,
+ Ok(Status::Flow(flow)) => flow,
+ },
+ )
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynTag<'a, 'ctx, TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<
+ 'a,
+ 'ctx,
+ Result<Known<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_MAP.to_int() }>, E>>, ()>,
+ E,
+ > {
+ E::ready(Ok(TagKnown {
+ kind_available: Some(true),
+ }))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E>
+ Hint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_STRUCT.to_int() }>, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynTag<'a, 'ctx, TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>(TagConst, visitor, NoopWalker::new()),
+ |status| match status {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ Flow::Break
+ }
+ Ok(Status::Skipped(_)) => Flow::Continue,
+ Ok(Status::Flow(flow)) => flow,
+ },
+ )
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynTag<'a, 'ctx, TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<
+ 'a,
+ 'ctx,
+ Result<Known<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_STRUCT.to_int() }>, E>>, ()>,
+ E,
+ > {
+ E::ready(Ok(TagKnown {
+ kind_available: Some(true),
+ }))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E>
+ Hint<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
+ TagConst,
+ visitor,
+ ValueWalker::new(TypeId::of::<T>()),
+ ),
+ |status| match status {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ Flow::Break
+ }
+ Ok(Status::Skipped(_)) => Flow::Continue,
+ Ok(Status::Flow(flow)) => flow,
+ },
+ )
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<
+ 'a,
+ 'ctx,
+ Result<Known<'a, 'ctx, DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ()>,
+ E,
+ > {
+ E::ready(Ok(TagKnown {
+ kind_available: Some(true),
+ }))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E> Hint<'a, 'ctx, DynTag<'a, 'ctx, TagDyn, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ hint: <DynTag<'a, 'ctx, TagDyn, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ match hint.kind.0 {
+ crate::TAG_TYPE_ID => Hint::<
+ 'a,
+ 'ctx,
+ DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_ID.to_int() }>, E>,
+ E,
+ >::hint(self, visitor, TagHint { kind: TagConst }),
+ crate::TAG_STRUCT => Hint::<
+ 'a,
+ 'ctx,
+ DynTag<'a, 'ctx, TagConst<{ TAG_STRUCT.to_int() }>, E>,
+ E,
+ >::hint(self, visitor, TagHint { kind: TagConst }),
+ crate::TAG_MAP => Hint::<
+ 'a,
+ 'ctx,
+ DynTag<'a, 'ctx, TagConst<{ TAG_MAP.to_int() }>, E>,
+ E,
+ >::hint(self, visitor, TagHint { kind: TagConst }),
+ crate::TAG_TYPE_NAME => Hint::<
+ 'a,
+ 'ctx,
+ DynTag<'a, 'ctx, TagConst<{ TAG_TYPE_NAME.to_int() }>, E>,
+ E,
+ >::hint(self, visitor, TagHint { kind: TagConst }),
+ crate::TAG_FIELD_NAMES => Hint::<
+ 'a,
+ 'ctx,
+ DynTag<'a, 'ctx, TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>,
+ E,
+ >::hint(self, visitor, TagHint { kind: TagConst }),
+ _ => E::ready(Flow::Continue),
+ }
+ }
+
+ fn known(
+ &'a mut self,
+ hint: &'a <DynTag<'a, 'ctx, TagDyn, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, DynTag<'a, 'ctx, TagDyn, E>>, ()>, E> {
+ E::ready(match hint.kind {
+ TagDyn(crate::TAG_TYPE_ID) | TagDyn(crate::TAG_STRUCT) => Ok(TagKnown {
+ kind_available: Some(true),
+ }),
+ _ => Ok(TagKnown {
+ kind_available: Some(false),
+ }),
+ })
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E> Hint<'a, 'ctx, DynValue<'a, 'ctx, BorrowedStatic<'ctx, T>, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M>,
+ T: Sync + 'static,
+{
+ fn hint(&'a mut self, visitor: Visitor<'a, 'ctx>, _hint: ()) -> Future<'a, 'ctx, Flow, E> {
+ E::map(
+ visit_value::<_, E>(visitor, BorrowedStatic(self.value)),
+ |status| match status {
+ Status::Skipped(_) => Flow::Continue,
+ Status::Flow(flow) => flow,
+ },
+ )
+ }
+
+ fn known(&'a mut self, _hint: &'a ()) -> Future<'a, 'ctx, Result<(), ()>, E> {
+ E::ready(Ok(()))
+ }
+}
+
+impl<'a, 'ctx: 'a, T, I, M, E> Hint<'a, 'ctx, DynSequence<'a, 'ctx, E>, E>
+ for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M, T = T>,
+ T: Sync,
+{
+ fn hint(
+ &'a mut self,
+ visitor: Visitor<'a, 'ctx>,
+ _hint: <DynSequence<'a, 'ctx, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Flow, E> {
+ E::map(visit_sequence::<E>(visitor, self), |status| match status {
+ Status::Skipped(_) => Flow::Continue,
+ Status::Flow(flow) => flow,
+ })
+ }
+
+ fn known(
+ &'a mut self,
+ _hint: &'a <DynSequence<'a, 'ctx, E> as HintMeta<'ctx>>::Hint,
+ ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, DynSequence<'a, 'ctx, E>>, ()>, E> {
+ let len = I::FIELDS.len();
+
+ E::ready(Ok(SequenceKnown {
+ len: (len, Some(len)),
+ }))
+ }
+}
+
+impl<'ctx, T, I, M, E> SequenceScope<'ctx, E> for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M, T = T>,
+{
+ fn size_hint<'a>(&'a mut self) -> Future<'a, 'ctx, (usize, Option<usize>), E> {
+ let len = I::FIELDS.len();
+
+ E::ready((len, Some(len)))
+ }
+
+ fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E> {
+ if self.index >= I::FIELDS.len() {
+ return E::ready(Flow::Done);
+ }
+
+ let index = self.index;
+ self.index += 1;
+
+ E::map(
+ I::walk_field::<E>(index, self.value, visitor),
+ |result| match result {
+ Ok(flow) => flow,
+ Err(err) => {
+ // Record the error and signal a break.
+ self.error = Some(StructWalkErrorKind::Field(err));
+ Flow::Break
+ }
+ },
+ )
+ }
+}
+
+impl<'ctx, T, I, M, E> RecoverableScope<'ctx, E> for StructWalker<'ctx, T, I, M, E>
+where
+ E: Effect<'ctx>,
+ I: StructTypeInfo<'ctx, M, T = T>,
+ T: Sync + 'static,
+{
+ fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E> {
+ // Reset the errors to default state.
+ self.error = None;
+
+ // Reset the field index to the default.
+ self.index = 0;
+
+ E::wrap(async move {
+ // We should check if the visitor wants something specific.
+ match visit_request_hint::<E>(visitor, self).await {
+ Flow::Continue => {}
+ flow => return flow,
+ }
+
+ // Attempt to visit the value directly.
+ match visit_value::<_, E>(visitor, BorrowedStatic(self.value)).await {
+ Status::Skipped(_) | Status::Flow(Flow::Continue) => {}
+ Status::Flow(flow) => return flow,
+ }
+
+ // Follow the standard set of protocols for a struct.
+ // - Tagged: type ID
+ // - Tagged: struct
+ // - Tagged: struct name
+ // - Tagged: struct field names
+ // - Sequence: the fields
+
+ match visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
+ TagConst,
+ visitor,
+ ValueWalker::new(TypeId::of::<T>()),
+ )
+ .await
+ {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ return Flow::Break;
+ }
+ Ok(Status::Skipped(_)) | Ok(Status::Flow(Flow::Continue)) => {}
+ Ok(Status::Flow(flow)) => return flow,
+ }
+
+ match visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>(TagConst, visitor, NoopWalker::new()).await {
+ Ok(Status::Skipped(_)) => {
+ match visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>(TagConst, visitor, NoopWalker::new()).await
+ {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ return Flow::Break;
+ }
+ Ok(Status::Skipped(_)) | Ok(Status::Flow(Flow::Continue)) => {}
+ Ok(Status::Flow(flow)) => return flow,
+ }
+ }
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ return Flow::Break;
+ }
+ Ok(Status::Flow(Flow::Continue)) => {}
+ Ok(Status::Flow(flow)) => return flow,
+ }
+
+ match visit_tag::<TagConst<{ TAG_TYPE_NAME.to_int() }>, E, _>(TagConst, visitor, ValueWalker::new(I::NAME))
+ .await
+ {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ return Flow::Break;
+ }
+ Ok(Status::Skipped(_)) | Ok(Status::Flow(Flow::Continue)) => {}
+ Ok(Status::Flow(flow)) => return flow,
+ }
+
+ match visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>(
+ TagConst,
+ visitor,
+ StaticSliceWalker::<_, ValueWalker<&'static str>>::new(I::FIELDS),
+ )
+ .await
+ {
+ Err(err) => {
+ self.error = Some(StructWalkErrorKind::FieldTag(err));
+ return Flow::Break;
+ }
+ Ok(Status::Skipped(_)) | Ok(Status::Flow(Flow::Continue)) => {}
+ Ok(Status::Flow(flow)) => return flow,
+ }
+
+ match visit_sequence::<E>(visitor, self).await {
+ Status::Flow(Flow::Continue) | Status::Skipped(_) => {}
+ Status::Flow(flow) => return flow,
+ }
+
+ Flow::Continue
+ })
+ }
+}
diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs
index 3bbe522..8ad92ec 100644
--- a/src/walk/walkers/core/tag.rs
+++ b/src/walk/walkers/core/tag.rs
@@ -10,8 +10,8 @@ use crate::{
request_hint::{visit_request_hint, DynRequestHint, RequestHint},
sequence::{DynSequence, SequenceScope},
tag::{DynTag, TagError},
- Status,
value::{visit_value, DynValue, Value},
+ Status,
},
Visitor,
},
@@ -57,15 +57,16 @@ where
Self: 'a,
{
E::wrap(async move {
- if visit_request_hint::<E>(visitor, &mut self).await {
- return Ok(());
+ match visit_request_hint::<E>(visitor, &mut self).await {
+ Flow::Continue => {},
+ _ => return Ok(()),
}
- if matches!(
- visit_value::<_, E>(visitor, OwnedStatic(self.names)).await,
- Status::Break | Status::Continue
- ) {
- return Ok(());
+ match visit_value::<_, E>(visitor, OwnedStatic(self.names)).await
+ {
+ Status::Skipped(_) => {},
+ Status::Flow(Flow::Continue) => {},
+ _ => return Ok(()),
}
if let Some(object) = visitor.upcast_mut::<DynSequence<'_, 'ctx, E>>() {