-rw-r--r--Cargo.toml5
-rw-r--r--src/build/builders/core/bool.rs6
-rw-r--r--src/build/builders/core/struct.rs168
-rw-r--r--src/effect.rs473
-rw-r--r--src/effect/blocking.rs151
-rw-r--r--src/lib.rs80
-rw-r--r--src/macros/build.rs8
-rw-r--r--src/protocol/visitor.rs124
-rw-r--r--src/protocol/visitor/recoverable.rs4
-rw-r--r--src/protocol/visitor/request_hint.rs4
-rw-r--r--src/protocol/visitor/sequence.rs19
-rw-r--r--src/protocol/visitor/tag.rs107
-rw-r--r--src/protocol/visitor/value.rs4
-rw-r--r--src/transform.rs9
-rw-r--r--src/walk.rs47
-rw-r--r--src/walk/walkers/core/key_value.rs58
-rw-r--r--src/walk/walkers/core/noop.rs2
-rw-r--r--src/walk/walkers/core/struct.rs333
-rw-r--r--src/walk/walkers/core/tag.rs9
-rw-r--r--src/walk/walkers/core/value.rs6
-rw-r--r--tests/builder_struct.rs24
-rw-r--r--tests/common/builder.rs4
-rw-r--r--tests/common/protocol/hint.rs4
-rw-r--r--tests/common/protocol/recoverable.rs4
-rw-r--r--tests/common/protocol/request_hint.rs2
-rw-r--r--tests/common/protocol/sequence.rs19
-rw-r--r--tests/common/protocol/tag.rs1
-rw-r--r--tests/common/protocol/visitor.rs1
-rw-r--r--tests/common/walker.rs2
-rw-r--r--tests/protocol_visitor_recoverable.rs8
-rw-r--r--tests/walker_struct.rs1
31 files changed, 947 insertions, 740 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 107f0b8..c6ad4a8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,7 @@ readme = "README.md"
# include = ["LICENSE-APACHE", "LICENSE-MIT", "README.md", "empty.rs"]
[dependencies]
+macro_rules_attribute = "0.2.0"
futures = "0.3.30"
pin-project = "1.1.5"
# serde = { version = "1.0", default-features = false, optional = true }
@@ -28,6 +29,10 @@ proptest = "1.4.0"
serde_json = "1.0.114"
tokio = { version = "1.36.0", features = ["full"] }
+[profile.release]
+opt-level = 3
+codegen-units = 1
+
[profile.test.package.proptest]
opt-level = 3
diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs
index 3cb60a6..60170e5 100644
--- a/src/build/builders/core/bool.rs
+++ b/src/build/builders/core/bool.rs
@@ -44,7 +44,7 @@ impl<'ctx, E: Effect> crate::Builder<'ctx, E> for Builder<E> {
where
Self: 'a,
{
- E::ready(self.0.ok_or(Error::Incomplete)).into_erased()
+ E::ready(self.0.ok_or(Error::Incomplete))
}
#[inline(always)]
@@ -52,7 +52,7 @@ impl<'ctx, E: Effect> crate::Builder<'ctx, E> for Builder<E> {
where
Self: 'a,
{
- E::ready(Self(None, PhantomData)).into_erased()
+ E::ready(Self(None, PhantomData))
}
#[inline(always)]
@@ -77,6 +77,6 @@ impl<'ctx, E: Effect> Value<'ctx, OwnedStatic<bool>, E> for Builder<E> {
'ctx: 'a,
{
self.0 = Some(value);
- E::ready(Flow::Done.into()).into_erased()
+ E::ready(Flow::Done.into())
}
}
diff --git a/src/build/builders/core/struct.rs b/src/build/builders/core/struct.rs
index b3983ab..b8ca483 100644
--- a/src/build/builders/core/struct.rs
+++ b/src/build/builders/core/struct.rs
@@ -1,9 +1,11 @@
-use core::{marker::PhantomData, ops::ControlFlow};
+use core::ops::ControlFlow;
use crate::{
any::{OwnedStatic, TempBorrowedStatic, TempBorrowedStaticHrt, TypeName},
any_trait,
- effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
+ effect::{
+ Effect, EffectExt as _, Effective, EffectiveExt as _, ErasedEffective, ReadyExt as _,
+ },
hkt::Marker,
protocol::{
visitor::{
@@ -12,7 +14,7 @@ use crate::{
},
DynVisitor,
},
- Builder, BuilderTypes, DynWalkerObjSafe, Flow,
+ tri, Builder, BuilderTypes, DynWalkerObjSafe, Flow,
};
use super::NoopVisitor;
@@ -92,16 +94,14 @@ where
where
Self: 'a,
{
- I::new_builders(seed)
- .map(|builders| {
- Self {
- builders,
- // Start in tuple mode until a struct or map tag is visited.
- mode: StructMode::Tuple,
- _generics: Default::default(),
- }
- })
- .into_erased()
+ I::new_builders(seed).map(|builders| {
+ Self {
+ builders,
+ // Start in tuple mode until a struct or map tag is visited.
+ mode: StructMode::Tuple,
+ _generics: Default::default(),
+ }
+ })
}
fn build<'a>(self) -> ErasedEffective<'a, Result<Self::Value, Self::Error>, E>
@@ -109,11 +109,7 @@ where
Self: 'a,
{
I::from_builders(self.builders)
- .map(|builders| match builders {
- Ok(value) => Ok(value),
- Err(err) => Err(StructError { error: err }),
- })
- .into_erased()
+ .map(|builders| builders.map_err(|err| StructError { error: err }))
}
fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> {
@@ -144,19 +140,12 @@ where
// This signals to go into map mode for the sequence.
self.mode = StructMode::Map;
- E::ready(NoopVisitor::new())
- .as_ctx(
- all_ctx,
- |noop, _| {
- walker
- .walk(DynVisitor(noop))
- .map(|x| x.to_continue().into())
- .into_erased()
- },
- merge_ctx,
- )
- .map(|(_, value)| value)
- .into_erased()
+ E::ready(NoopVisitor::new()).as_ctx_map(|noop| {
+ walker
+ .walk(DynVisitor(noop))
+ .map(|x| x.to_continue().into())
+ .cast()
+ })
}
}
@@ -167,73 +156,55 @@ where
E: Effect,
{
#[inline(always)]
- fn visit<'a>(
+ fn visit<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
- scope: DynSequenceScope<'a, 'ctx, E>,
- ) -> ErasedEffective<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> {
+ scope: DynSequenceScope<'b, 'ctx, E>,
+ ) -> ErasedEffective<'c, VisitResult<DynSequenceScope<'b, 'ctx, E>>, E>
+ where
+ 'ctx: 'c,
+ {
match self.mode {
StructMode::Tuple => {
- E::ready((self, scope, 0))
- .r#loop(|(this, scope, index)| {
- if let Some(marker) = I::marker_from_index(*index) {
- // Select the visitor for this field.
- let visitor = I::as_visitor(marker, &mut this.builders);
-
- // For rust analyzer.
- let scope: &mut DynSequenceScope<'_, '_, E> = scope;
-
- scope
- .next(visitor)
- .map(|flow| match flow {
- Flow::Continue => {
- *index += 1;
-
- ControlFlow::Continue(())
- }
- Flow::Err => {
- ControlFlow::Break(VisitResult::Control(Flow::Err))
- }
- Flow::Done => {
- ControlFlow::Break(VisitResult::Control(Flow::Done))
- }
- })
- .into_erased()
- } else {
- E::ready(ControlFlow::Break(VisitResult::Control(Flow::Done)))
- .into_erased()
- }
- })
- .map(|(_, value)| value)
- .into_erased()
+ // Tuple-like is based on the index of the field.
+ let mut index = 0;
+
+ // Loop through all the fields getting a value for each one.
+ E::repeat_map((self, scope), |(this, scope)| {
+ // Get the marker for the field at this index.
+ let marker = tri!(I::marker_from_index(index));
+
+ // Move to the next field for the next iteration.
+ index += 1;
+
+ // Select the visitor for this field.
+ let visitor = I::as_visitor(marker, &mut this.builders);
+
+ // Visit the next item in the sequence.
+ scope.next(visitor).map(Flow::to_control_flow).cast()
+ })
}
- StructMode::Map => E::ready((self, scope))
- .r#loop(|(this, scope)| {
- let visitor = FieldVisitor::<I, M, E> {
- builders: &mut this.builders,
- marker: None,
- _marker: Default::default(),
- };
-
- E::ready((scope, visitor))
- .as_ctx(
- all_ctx,
- |(scope, visitor), _| {
- let scope: &mut DynSequenceScope<'_, '_, _> = scope;
-
- scope.next(DynVisitor(visitor)).into_erased()
- },
- merge_ctx,
- )
- .map(|(_, result)| match result {
- Flow::Continue => ControlFlow::Continue(()),
- Flow::Err => ControlFlow::Break(VisitResult::Control(Flow::Err)),
- Flow::Done => ControlFlow::Break(VisitResult::Control(Flow::Done)),
- })
- .into_erased()
+ StructMode::Map => {
+ // A visitor that knows how to use field names.
+ let visitor = FieldVisitor::<I, M, E> {
+ builders: &mut self.builders,
+ marker: None,
+ _marker: Default::default(),
+ };
+
+ // Loop through all the elements in the sequence.
+ // Each key value pair will be mapped to a field.
+ E::repeat_map((visitor, scope), |(visitor, scope)| {
+ E::as_ctx_map((scope, visitor), |(scope, visitor)| {
+ // Visit the next element of the sequence.
+ // When there are no more items in the sequence then the loop ends.
+ scope.next(DynVisitor(*visitor)).cast()
+ })
+ .map(Flow::to_control_flow)
+ .cast()
})
- .map(|(_, value)| value)
- .into_erased(),
+ }
}
+ .map(Into::into)
}
}
@@ -277,16 +248,11 @@ where
};
E::ready((self, visitor, walker))
- .as_ctx(
- all_ctx,
- |(_, visitor, walker), _| walker.walk(DynVisitor(visitor)).into_erased(),
- merge_ctx,
- )
+ .as_ctx(|(_, visitor, walker)| walker.walk(DynVisitor(visitor)).cast())
.map(|((this, visitor, _), flow)| {
this.marker = visitor.field_marker;
flow.to_continue().into()
})
- .into_erased()
}
}
@@ -321,7 +287,7 @@ where
{
self.field_marker = I::marker_from_index(index);
- E::ready(VisitResult::Control(Flow::Done)).into_erased()
+ E::ready(VisitResult::Control(Flow::Done))
}
}
@@ -341,7 +307,7 @@ where
{
self.field_marker = I::marker_from_name(name);
- E::ready(VisitResult::Control(Flow::Done)).into_erased()
+ E::ready(VisitResult::Control(Flow::Done))
}
}
@@ -361,6 +327,6 @@ where
{
self.field_marker = I::marker_from_name(name);
- E::ready(VisitResult::Control(Flow::Done)).into_erased()
+ E::ready(VisitResult::Control(Flow::Done))
}
}
diff --git a/src/effect.rs b/src/effect.rs
index 0f85ee3..458ed8a 100644
--- a/src/effect.rs
+++ b/src/effect.rs
@@ -3,7 +3,7 @@ pub mod blocking;
use core::{future::Future, ops::ControlFlow};
-use crate::{higher_ranked_trait, higher_ranked_type, hkt::Marker};
+use crate::{higher_ranked_trait, higher_ranked_type, hkt::Marker, never::Never};
// Goal: code using the module shouldn't care if the underlying environment is async or not.
// That is the API should allow yielding without forcing it.
@@ -106,164 +106,364 @@ pub trait Effect: Join<Effect = Self> + TryJoin<Effect = Self> + Ss + Sized + 's
F::Output: Ss + 'a;
}
-pub fn all_ctx<T>(x: T) -> (T, ()) {
- (x, ())
+pub trait ReadyExt<'lt, Eff: Effective<'lt, Output = Self>>: Ss + Sized {
+ fn ready(self) -> Eff;
}
-pub fn merge_ctx<C, T>(ctx: C, x: T) -> (C, T) {
- (ctx, x)
+impl<'lt, Eff: Effective<'lt, Output = T>, T: Ss> ReadyExt<'lt, Eff> for T {
+ fn ready(self) -> Eff {
+ Eff::ready(self)
+ }
+}
+
+pub trait ConvertShort<T> {
+ fn convert_short(short: Self) -> T;
}
-pub trait ShortCircuit {
- type Normal: Ss;
+pub trait FromShort<S = <Self as ShortCircuit>::Short> {
+ fn from_short(short: S) -> Self;
+}
- type Short: Ss;
+impl<T, S> FromShort<S> for T
+where
+ S: ConvertShort<T>,
+{
+ fn from_short(short: S) -> Self {
+ S::convert_short(short)
+ }
+}
- type NormalWith<T: Ss>: ShortCircuit<Normal = T, Short = Self::Short> + Ss;
+pub trait ShortCircuit: FromShort {
+ type Output;
+ type Short;
- fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R>
- where
- F: FnOnce(Self::Normal) -> R;
+ fn from_output(output: Self::Output) -> Self;
+ fn branch(self) -> ControlFlow<Self::Short, Self::Output>;
+}
- fn or_else<F>(self, f: F) -> Self
- where
- F: FnOnce(Self::Short) -> Self;
+pub fn effective_from_short<'lt, Eff, S>(short: S) -> Eff
+where
+ Eff: Effective<'lt>,
+ Eff::Output: FromShort<S>,
+{
+ Eff::ready(FromShort::from_short(short))
+}
+
+impl<T> ConvertShort<Option<T>> for Option<Never> {
+ fn convert_short(short: Option<Never>) -> Option<T> {
+ match short {
+ None => None,
+ Some(_) => unreachable!(),
+ }
+ }
}
-impl<T: Ss> ShortCircuit for Option<T> {
- type Normal = T;
+impl<T> ShortCircuit for Option<T> {
+ type Output = T;
- type Short = ();
+ type Short = Option<Never>;
- type NormalWith<U: Ss> = Option<U>;
+ fn branch(self) -> ControlFlow<Self::Short, Self::Output> {
+ match self {
+ Some(v) => ControlFlow::Continue(v),
+ None => ControlFlow::Break(None),
+ }
+ }
- fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R>
- where
- F: FnOnce(Self::Normal) -> R,
- {
- Option::map(self, f)
+ fn from_output(output: Self::Output) -> Self {
+ Some(output)
}
+}
- fn or_else<F>(self, f: F) -> Self
- where
- F: FnOnce(Self::Short) -> Self,
- {
- Option::or_else(self, || f(()))
+impl<T, E> ConvertShort<Result<T, E>> for Result<Never, E> {
+ fn convert_short(short: Result<Never, E>) -> Result<T, E> {
+ match short {
+ Err(err) => Err(err),
+ Ok(_) => unreachable!(),
+ }
}
}
-impl<T: Ss, E: Ss> ShortCircuit for Result<T, E> {
- type Normal = T;
+impl<T, E> ShortCircuit for Result<T, E> {
+ type Output = T;
+
+ type Short = Result<Never, E>;
+
+ fn branch(self) -> ControlFlow<Self::Short, Self::Output> {
+ match self {
+ Ok(v) => ControlFlow::Continue(v),
+ Err(err) => ControlFlow::Break(Err(err)),
+ }
+ }
+
+ fn from_output(output: Self::Output) -> Self {
+ Ok(output)
+ }
+}
- type Short = E;
+#[macro_export]
+macro_rules! tri {
+ ($expr:expr $(,)?) => {
+ match $crate::effect::ShortCircuit::branch($expr) {
+ ::core::ops::ControlFlow::Continue(val) => val,
+ ::core::ops::ControlFlow::Break(short) => {
+ return $crate::effect::effective_from_short(short);
+ }
+ }
+ };
+}
+pub use tri;
- type NormalWith<U: Ss> = Result<U, E>;
+pub trait EffectExt: Effect {
+ fn repeat_map<'ctx, 'wrap, I: Ss + 'wrap, U: Ss, F: Ss>(
+ input: I,
+ f: F,
+ ) -> ErasedEffective<'wrap, U, Self>
+ where
+ F: for<'temp> FnMut(&'temp mut I) -> ErasedEffective<'temp, ControlFlow<U>, Self, &'ctx ()>,
+ 'ctx: 'wrap,
+ {
+ Self::ready(input).repeat_map(f)
+ }
- fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R>
+ #[inline(always)]
+ fn as_ctx<'ctx, 'wrap, I: Ss + 'wrap, U: Ss, F: Ss>(
+ input: I,
+ f: F,
+ ) -> ErasedEffective<'wrap, (I, U), Self>
where
- F: FnOnce(Self::Normal) -> R,
+ F: for<'temp> FnOnce(&'temp mut I) -> ErasedEffective<'temp, U, Self, &'ctx ()>,
+ 'ctx: 'wrap,
{
- Result::map(self, f)
+ Self::ready(input).as_ctx(f)
}
- fn or_else<F>(self, f: F) -> Self
+ fn as_ctx_map<'ctx, 'wrap, I: Ss + 'wrap, U: Ss, F: Ss>(
+ input: I,
+ f: F,
+ ) -> ErasedEffective<'wrap, U, Self>
where
- F: FnOnce(Self::Short) -> Self,
+ F: for<'temp> FnOnce(&'temp mut I) -> ErasedEffective<'temp, U, Self, &'ctx ()>,
+ 'ctx: 'wrap,
{
- Result::or_else(self, f)
+ Self::ready(input).as_ctx_map(f)
}
}
+impl<T: Effect> EffectExt for T {}
+
pub trait EffectiveExt<'lt>: Effective<'lt> {
- fn map_normal<'wrap, F: Ss, R: Ss>(
- self,
- f: F,
- ) -> ErasedEffective<'wrap, <Self::Output as ShortCircuit>::NormalWith<R>, Self::Effect>
+ fn remove_ctx<'wrap, Ctx: Ss, T: Ss>(self) -> ErasedEffective<'wrap, T, Self::Effect>
where
- F: FnOnce(<Self::Output as ShortCircuit>::Normal) -> R,
- Self::Output: ShortCircuit,
- 'lt: 'wrap;
+ Self: Effective<'lt, Output = (Ctx, T)>,
+ 'lt: 'wrap,
+ {
+ self.map(|(_, value)| value)
+ }
- fn or_else<'wrap, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Self::Output, Self::Effect>
+ fn map<'wrap, U: Ss, F: Ss>(self, f: F) -> ErasedEffective<'wrap, U, Self::Effect>
where
- F: FnOnce(<Self::Output as ShortCircuit>::Short) -> Self::Output,
- Self::Output: ShortCircuit,
- 'lt: 'wrap;
+ F: FnOnce(Self::Output) -> U,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |v| ((), ControlFlow::<_, Never>::Break(f(v))),
+ |_, _| unreachable!(),
+ |_, _: Never| unreachable!(),
+ |_, _: &mut Never| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |_, _, v| v,
+ )
+ }
- fn demo(self)
+ fn then<'wrap, U: Ss, F: Ss>(self, f: F) -> ErasedEffective<'wrap, U, Self::Effect>
where
- Self: Effective<'lt, Output = (i32, i32)>;
+ F: FnOnce(Self::Output) -> ErasedEffective<'wrap, U, Self::Effect>,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |v| ((), ControlFlow::Continue(v)),
+ |_, v| f(v).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |_, _, v| v,
+ )
+ }
- fn as_ctx_or_else<'ctx: 'lt, 'wrap, T: Ss, U: Ss, F: Ss>(
- self,
- f: F,
- ) -> ErasedEffective<'wrap, (T, Option<U>), Self::Effect>
+ fn or_else<'wrap, U: Ss, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Option<U>, Self::Effect>
where
- Self: Effective<'lt, Output = (T, Option<U>)>,
- F: for<'b> FnOnce(&'b mut T) -> ErasedEffective<'b, Option<U>, Self::Effect, &'ctx ()>,
- 'lt: 'wrap;
-}
+ Self: Effective<'lt, Output = Option<U>>,
+ F: FnOnce() -> ErasedEffective<'wrap, Option<U>, Self::Effect>,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |v| {
+ (
+ (),
+ match v {
+ Some(v) => ControlFlow::Break(Some(v)),
+ None => ControlFlow::Continue(()),
+ },
+ )
+ },
+ |_, _| f().cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |_, _, v| v,
+ )
+ }
-impl<'lt, T: Effective<'lt>> EffectiveExt<'lt> for T {
- fn map_normal<'wrap, F: Ss, R: Ss>(
+ #[inline(always)]
+ fn as_ctx<'ctx: 'lt, 'wrap, U: Ss, F: Ss>(
self,
f: F,
- ) -> ErasedEffective<'wrap, <Self::Output as ShortCircuit>::NormalWith<R>, Self::Effect>
+ ) -> ErasedEffective<'wrap, (Self::Output, U), Self::Effect>
where
- F: FnOnce(<Self::Output as ShortCircuit>::Normal) -> R,
- Self::Output: ShortCircuit,
+ F: for<'temp> FnOnce(
+ &'temp mut Self::Output,
+ ) -> ErasedEffective<'temp, U, Self::Effect, &'ctx ()>,
'lt: 'wrap,
{
- self.map(move |value| value.map(f))
+ self.r#do(
+ |ctx| (ctx, ControlFlow::Continue(())),
+ #[inline(always)]
+ |ctx, _| f(ctx).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |ctx, _, v| (ctx, v),
+ )
}
- fn or_else<'wrap, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Self::Output, Self::Effect>
+ fn as_ctx_map<'ctx: 'lt, 'wrap, U: Ss, F: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, U, Self::Effect>
where
- F: FnOnce(<Self::Output as ShortCircuit>::Short) -> Self::Output,
- Self::Output: ShortCircuit,
+ F: for<'temp> FnOnce(
+ &'temp mut Self::Output,
+ ) -> ErasedEffective<'temp, U, Self::Effect, &'ctx ()>,
'lt: 'wrap,
{
- self.map(move |value| value.or_else(f))
+ self.r#do(
+ |ctx| (ctx, ControlFlow::Continue(())),
+ |ctx, _| f(ctx).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |_, _, v| v,
+ )
}
- fn demo(self)
+ fn as_ctx_or_else<'ctx: 'lt, 'wrap, Ctx: Ss, U: Ss, F: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, (Ctx, Option<U>), Self::Effect>
where
- Self: Effective<'lt, Output = (i32, i32)>,
+ Self: Effective<'lt, Output = (Ctx, Option<U>)>,
+ F: for<'temp> FnOnce(
+ &'temp mut Ctx,
+ ) -> ErasedEffective<'temp, Option<U>, Self::Effect, &'ctx ()>,
+ 'lt: 'wrap,
{
- self.map(|(a, b)| a + b);
+ self.r#do(
+ |(ctx, v)| {
+ (
+ ctx,
+ match v {
+ Some(v) => ControlFlow::Break(Some(v)),
+ None => ControlFlow::Continue(()),
+ },
+ )
+ },
+ |ctx, ()| f(ctx).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |ctx, _, v| (ctx, v),
+ )
}
- fn as_ctx_or_else<'ctx: 'lt, 'wrap, N: Ss, U: Ss, F: Ss>(
+ fn as_ctx_or_else_map<'ctx: 'lt, 'wrap, Ctx: Ss, U: Ss, F: Ss>(
self,
f: F,
- ) -> ErasedEffective<'wrap, (N, Option<U>), Self::Effect>
+ ) -> ErasedEffective<'wrap, Option<U>, Self::Effect>
where
- Self: Effective<'lt, Output = (N, Option<U>)>,
- F: for<'b> FnOnce(&'b mut N) -> ErasedEffective<'b, Option<U>, Self::Effect, &'ctx ()>,
+ Self: Effective<'lt, Output = (Ctx, Option<U>)>,
+ F: for<'temp> FnOnce(
+ &'temp mut Ctx,
+ ) -> ErasedEffective<'temp, Option<U>, Self::Effect, &'ctx ()>,
'lt: 'wrap,
{
- self.as_ctx(
- // Replace everything in Effective with just the loop construct which can skip
- // the as_ctx body.
- all_ctx,
- |(ctx, value), _| {
- if value.is_some() {
- <Self::Effect as Effect>::ready(None).into_erased()
- } else {
- f(ctx)
- }
- },
- |(ctx, a), b| match (a, b) {
- (None, None) => (ctx, None),
- (Some(v), None) | (None, Some(v)) => (ctx, Some(v)),
- (Some(_), Some(_)) => unreachable!(),
+ self.r#do(
+ |(ctx, v)| {
+ (
+ ctx,
+ match v {
+ Some(v) => ControlFlow::Break(Some(v)),
+ None => ControlFlow::Continue(()),
+ },
+ )
},
+ |ctx, ()| f(ctx).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |_, _, v| v,
+ )
+ }
+
+ fn repeat<'ctx: 'lt, 'wrap, U: Ss, F: Ss>(
+ self,
+ mut f: F,
+ ) -> ErasedEffective<'wrap, (Self::Output, U), Self::Effect>
+ where
+ F: for<'temp> FnMut(
+ &'temp mut Self::Output,
+ )
+ -> ErasedEffective<'temp, ControlFlow<U>, Self::Effect, &'ctx ()>,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |ctx| (ctx, ControlFlow::Continue(())),
+ |_, _| <Self::Effect as Effect>::ready(()).cast(),
+ |_, _| ControlFlow::Continue(()),
+ |ctx, _| f(ctx).cast(),
+ |_, _, v| v,
+ |ctx, _, v| (ctx, v),
+ )
+ }
+
+ fn repeat_map<'ctx: 'lt, 'wrap, U: Ss, F: Ss>(
+ self,
+ mut f: F,
+ ) -> ErasedEffective<'wrap, U, Self::Effect>
+ where
+ F: for<'temp> FnMut(
+ &'temp mut Self::Output,
+ )
+ -> ErasedEffective<'temp, ControlFlow<U>, Self::Effect, &'ctx ()>,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |ctx| (ctx, ControlFlow::Continue(())),
+ |_, _| <Self::Effect as Effect>::ready(()).cast(),
+ |_, _| ControlFlow::Continue(()),
+ |ctx, _| f(ctx).cast(),
+ |_, _, v| v,
+ |_, _, v| v,
)
}
}
-pub trait Effective<'lt>: Ss + 'lt {
- fn into_erased<B>(self) -> ErasedEffective<'lt, Self::Output, Self::Effect, B>;
+impl<'lt, T: Effective<'lt>> EffectiveExt<'lt> for T {}
+
+pub trait Effective<'lt>: Sized + Ss + 'lt {
+ fn cast<'wrap, B>(self) -> ErasedEffective<'wrap, Self::Output, Self::Effect, B>
+ where
+ 'lt: 'wrap;
/// The effect the effective belongs to.
type Effect: Effect;
@@ -277,36 +477,49 @@ pub trait Effective<'lt>: Ss + 'lt {
/// Convert the effective into a general future for use in async.
fn into_future(self) -> Self::IntoFuture;
- fn map<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect>
- where
- F: FnOnce(Self::Output) -> T,
- 'lt: 'wrap;
-
- fn then<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect>
- where
- F: FnOnce(Self::Output) -> ErasedEffective<'wrap, T, Self::Effect>,
- 'lt: 'wrap;
-
- fn as_ctx<'ctx: 'lt, 'wrap, T: Ss, S: Ss, C: Ss, U: Ss, F: Ss, A: Ss, R: Ss>(
- self,
- split: S,
- cb: F,
- after: A,
- ) -> ErasedEffective<'wrap, R, Self::Effect>
- where
- S: FnOnce(Self::Output) -> (C, U),
- F: for<'b> FnOnce(&'b mut C, U) -> ErasedEffective<'b, T, Self::Effect, &'ctx ()>,
- A: FnOnce(C, T) -> R,
- 'lt: 'wrap;
-
- fn r#loop<'ctx: 'lt, 'wrap, T: Ss, F: Ss>(
+ fn ready(value: Self::Output) -> Self;
+
+ fn r#do<
+ 'ctx: 'lt,
+ 'wrap,
+ Pre: Ss,
+ Ctx: Ss,
+ Owned: Ss,
+ First: Ss,
+ FirstOutput: Ss,
+ FirstPost: Ss,
+ Done: Ss,
+ Extra: Ss,
+ Repeat: Ss,
+ RepeatOutput: Ss,
+ RepeatPost: Ss,
+ Post: Ss,
+ Return: Ss,
+ >(
self,
- cb: F,
- ) -> ErasedEffective<'wrap, (Self::Output, T), Self::Effect>
+ pre: Pre,
+ first: First,
+ first_post: FirstPost,
+ repeat: Repeat,
+ repeat_post: RepeatPost,
+ post: Post,
+ ) -> ErasedEffective<'wrap, Return, Self::Effect>
where
- F: for<'b> FnMut(
- &'b mut Self::Output,
- ) -> ErasedEffective<'b, ControlFlow<T>, Self::Effect, &'ctx ()>,
+ Pre: FnOnce(Self::Output) -> (Ctx, ControlFlow<Done, Owned>),
+ First: for<'temp> FnOnce(
+ &'temp mut Ctx,
+ Owned,
+ )
+ -> ErasedEffective<'temp, FirstOutput, Self::Effect, &'wrap ()>,
+ FirstPost: for<'temp> FnOnce(&'temp mut Ctx, FirstOutput) -> ControlFlow<Done, Extra>,
+ Repeat: for<'temp> FnMut(
+ &'temp mut Ctx,
+ &'temp mut Extra,
+ )
+ -> ErasedEffective<'temp, RepeatOutput, Self::Effect, &'wrap ()>,
+ RepeatPost:
+ for<'temp> FnMut(&'temp mut Ctx, &'temp mut Extra, RepeatOutput) -> ControlFlow<Done>,
+ Post: FnOnce(Ctx, Option<Extra>, Done) -> Return,
'lt: 'wrap;
}
@@ -502,3 +715,19 @@ where
<E as TryJoin>::two(self)
}
}
+
+impl<'lt, E: Effect, F0, F1, F2, T0, T1, T2> TryJoinable<'lt, E> for (F0, F1, F2)
+where
+ F0: FnOnce() -> T0 + Ss + 'lt,
+ F1: FnOnce() -> T1 + Ss + 'lt,
+ F2: FnOnce() -> T2 + Ss + 'lt,
+ T0: TryEffective<'lt, Effect = E>,
+ T1: TryEffective<'lt, Err = T0::Err, Effect = E>,
+ T2: TryEffective<'lt, Err = T0::Err, Effect = E>,
+{
+ type Output = <E as TryJoin>::Three<'lt, T0, T1, T2>;
+
+ fn join(self) -> Self::Output {
+ <E as TryJoin>::three(self)
+ }
+}
diff --git a/src/effect/blocking.rs b/src/effect/blocking.rs
index 11c3b7d..c504445 100644
--- a/src/effect/blocking.rs
+++ b/src/effect/blocking.rs
@@ -35,17 +35,10 @@ impl<T: Ss, B: BlockOn> Erased::Hkt<T, Blocking<B>> for Value<T, B> {
impl<B: BlockOn> Effect for Blocking<B> {
type Erased<T: Ss> = Value<T, B>;
- // type Ready<'a, T: Ss + 'a> = Value<T, B>;
-
fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self> {
Value(value, Default::default())
}
- // type FromFuture<'a, F: Ss + 'a> = Value<F::Output, B>
- // where
- // F: Future,
- // F::Output: Ss + 'a;
-
fn from_future<'a, F: Ss + 'a>(future: F) -> ErasedEffective<'a, F::Output, Self>
where
F: Future,
@@ -56,7 +49,7 @@ impl<B: BlockOn> Effect for Blocking<B> {
}
impl<'lt, U: Ss + 'lt, B: BlockOn> Effective<'lt> for Value<U, B> {
- fn into_erased<X>(self) -> ErasedEffective<'lt, Self::Output, Self::Effect, X> {
+ fn cast<'wrap, X>(self) -> ErasedEffective<'wrap, Self::Output, Self::Effect, X> {
self
}
@@ -70,74 +63,74 @@ impl<'lt, U: Ss + 'lt, B: BlockOn> Effective<'lt> for Value<U, B> {
core::future::ready(self.0)
}
- // type Loop<'ctx: 'a, 'a, T: Ss + 'a, F: Ss + 'a>
- // = Value<(U, T), B>
- // where
- // F: for<'b> FnMut(&'b mut Self::Output) -> ErasedEffective<'b, ControlFlow<T>, Self::Effect>,
- // 'lt: 'a;
-
- fn r#loop<'ctx: 'lt, 'wrap, T: Ss, F: Ss>(
+ #[inline(always)]
+ fn r#do<
+ 'ctx: 'lt,
+ 'wrap,
+ Pre: Ss,
+ Ctx: Ss,
+ Owned: Ss,
+ First: Ss,
+ FirstOutput: Ss,
+ FirstPost: Ss,
+ Done: Ss,
+ Extra: Ss,
+ Repeat: Ss,
+ RepeatOutput: Ss,
+ RepeatPost: Ss,
+ Post: Ss,
+ Return: Ss,
+ >(
self,
- mut cb: F,
- ) -> ErasedEffective<'wrap, (Self::Output, T), Self::Effect>
+ pre: Pre,
+ first: First,
+ first_post: FirstPost,
+ mut repeat: Repeat,
+ mut repeat_post: RepeatPost,
+ post: Post,
+ ) -> ErasedEffective<'wrap, Return, Self::Effect>
where
- F: for<'b> FnMut(&'b mut Self::Output) -> ErasedEffective<'b, ControlFlow<T>, Self::Effect>,
- {
- let mut this = self.0;
-
- loop {
- if let ControlFlow::Break(value) = cb(&mut this).0 {
- return Value((this, value), Default::default());
- }
- }
- }
-
- // type Map<'a, T: Ss + 'a, F: Ss + 'a> = Value<T, B>
- // where
- // F: FnOnce(Self::Output) -> T,
- // 'lt: 'a;
-
- fn map<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect>
- where
- F: FnOnce(Self::Output) -> T,
+ Pre: FnOnce(Self::Output) -> (Ctx, ControlFlow<Done, Owned>),
+ First: for<'b> FnOnce(
+ &'b mut Ctx,
+ Owned,
+ ) -> ErasedEffective<'b, FirstOutput, Self::Effect, &'wrap ()>,
+ FirstPost: for<'b> FnOnce(&'b mut Ctx, FirstOutput) -> ControlFlow<Done, Extra>,
+ Repeat: for<'b> FnMut(
+ &'b mut Ctx,
+ &'b mut Extra,
+ )
+ -> ErasedEffective<'b, RepeatOutput, Self::Effect, &'wrap ()>,
+ RepeatPost: for<'b> FnMut(&'b mut Ctx, &'b mut Extra, RepeatOutput) -> ControlFlow<Done>,
+ Post: FnOnce(Ctx, Option<Extra>, Done) -> Return,
'lt: 'wrap,
{
- Value(cb(self.0), Default::default())
- }
-
- // type Then<'a, T: Ss + 'a, V: Ss + 'a, F: Ss + 'a> = Value<T, B>
- // where
- // F: FnOnce(Self::Output) -> V,
- // V: Effective<'a, Output = T, Effect = Self::Effect>,
- // 'lt: 'a;
+ let (ctx, done, extra) = match pre(self.0) {
+ (mut ctx, ControlFlow::Continue(owned)) => {
+ let first_output = first(&mut ctx, owned).0;
+
+ let (done, extra) = match first_post(&mut ctx, first_output) {
+ ControlFlow::Continue(mut extra) => loop {
+ let repeat_output = repeat(&mut ctx, &mut extra).0;
+
+ match repeat_post(&mut ctx, &mut extra, repeat_output) {
+ ControlFlow::Continue(()) => {}
+ ControlFlow::Break(done) => break (done, Some(extra)),
+ }
+ },
+ ControlFlow::Break(done) => (done, None),
+ };
+
+ (ctx, done, extra)
+ }
+ (ctx, ControlFlow::Break(done)) => (ctx, done, None),
+ };
- fn then<'a, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'a, T, Self::Effect>
- where
- F: FnOnce(Self::Output) -> ErasedEffective<'a, T, Self::Effect>,
- 'lt: 'a,
- {
- cb(self.0).into_erased::<()>()
+ Value(post(ctx, extra, done), Default::default())
}
- // type AsCtx<'ctx: 'a, 'a, T: Ss + 'a, F: Ss + 'a> = Value<(U, T), B>
- // where
- // F: for<'b> FnOnce(&'b mut Self::Output) -> ErasedEffective<'b, T, Self::Effect, (&'b mut Self::Output, &'ctx ())>,
- // 'lt: 'a;
-
- fn as_ctx<'ctx: 'lt, 'wrap, T: Ss, S: Ss, C: Ss, K: Ss, F: Ss, A: Ss, R: Ss>(
- self,
- split: S,
- cb: F,
- after: A,
- ) -> ErasedEffective<'wrap, R, Self::Effect>
- where
- S: FnOnce(Self::Output) -> (C, K),
- F: for<'b> FnOnce(&'b mut C, K) -> ErasedEffective<'b, T, Self::Effect>,
- A: FnOnce(C, T) -> R,
- {
- let (mut this, owned) = split(self.0);
- let result = cb(&mut this, owned).0;
- Value(after(this, result), Default::default())
+ fn ready(value: Self::Output) -> Self {
+ Value(value, Default::default())
}
}
@@ -160,8 +153,8 @@ impl<B: BlockOn> Join for Blocking<B> {
T0: Effective<'a, Effect = Self::Effect>,
T1: Effective<'a, Effect = Self::Effect>,
{
- let v0 = cb.0.into_erased::<()>().0;
- let v1 = cb.1.into_erased::<()>().0;
+ let v0 = cb.0.cast::<()>().0;
+ let v1 = cb.1.cast::<()>().0;
Value((v0, v1), Default::default())
}
@@ -174,9 +167,9 @@ impl<B: BlockOn> Join for Blocking<B> {
T1: Effective<'a, Effect = Self::Effect>,
T2: Effective<'a, Effect = Self::Effect>,
{
- let v0 = cb.0.into_erased::<()>().0;
- let v1 = cb.1.into_erased::<()>().0;
- let v2 = cb.2.into_erased::<()>().0;
+ let v0 = cb.0.cast::<()>().0;
+ let v1 = cb.1.cast::<()>().0;
+ let v2 = cb.2.cast::<()>().0;
Value((v0, v1, v2), Default::default())
}
@@ -205,12 +198,12 @@ impl<B: BlockOn> TryJoin for Blocking<B> {
F0: FnOnce() -> T0,
F1: FnOnce() -> T1,
{
- let v0 = match (cb.0)().into_erased::<()>().0 {
+ let v0 = match (cb.0)().cast::<()>().0 {
Ok(v) => v,
Err(err) => return Value(Err(err), Default::default()),
};
- let v1 = match (cb.1)().into_erased::<()>().0 {
+ let v1 = match (cb.1)().cast::<()>().0 {
Ok(v) => v,
Err(err) => return Value(Err(err), Default::default()),
};
@@ -229,17 +222,17 @@ impl<B: BlockOn> TryJoin for Blocking<B> {
F1: FnOnce() -> T1,
F2: FnOnce() -> T2,
{
- let v0 = match (cb.0)().into_erased::<()>().0 {
+ let v0 = match (cb.0)().cast::<()>().0 {
Ok(v) => v,
Err(err) => return Value(Err(err), Default::default()),
};
- let v1 = match (cb.1)().into_erased::<()>().0 {
+ let v1 = match (cb.1)().cast::<()>().0 {
Ok(v) => v,
Err(err) => return Value(Err(err), Default::default()),
};
- let v2 = match (cb.2)().into_erased::<()>().0 {
+ let v2 = match (cb.2)().cast::<()>().0 {
Ok(v) => v,
Err(err) => return Value(Err(err), Default::default()),
};
diff --git a/src/lib.rs b/src/lib.rs
index e9627c5..c4b7528 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,10 @@ pub mod symbol;
mod transform;
mod walk;
+use core::ops::ControlFlow;
+
pub use build::*;
+use effect::ConvertShort;
pub use transform::*;
pub use walk::*;
@@ -55,7 +58,11 @@ pub const TAG_ENUM: Symbol = Symbol::new("Enum");
pub enum DefaultMode {}
-pub type Status = Result<(), ()>;
+#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum Status {
+ Ok,
+ Err,
+}
#[derive(Clone, Copy, PartialEq, Debug)]
#[must_use]
@@ -67,7 +74,23 @@ pub enum Flow {
Done,
}
+impl ConvertShort<ControlFlow<Flow>> for Option<never::Never> {
+ fn convert_short(short: Self) -> ControlFlow<Flow> {
+ match short {
+ None => ControlFlow::Break(Flow::Done),
+ Some(_) => unreachable!(),
+ }
+ }
+}
+
impl Flow {
+ pub fn to_status(self) -> Status {
+ match self {
+ Flow::Continue | Flow::Done => Status::Ok,
+ Flow::Err => Status::Err,
+ }
+ }
+
pub fn to_done(self) -> Self {
match self {
Flow::Continue | Flow::Done => Flow::Done,
@@ -81,6 +104,13 @@ impl Flow {
Flow::Err => Flow::Err,
}
}
+
+ pub fn to_control_flow(self) -> ControlFlow<Self> {
+ match self {
+ Flow::Continue => ControlFlow::Continue(()),
+ flow => ControlFlow::Break(flow),
+ }
+ }
}
#[macro_export]
@@ -137,7 +167,7 @@ macro_rules! Walk {
$(pub const $field: usize = Fields::$field as usize;)*
}
- use $crate::effect::Effective;
+ use $crate::effect::EffectiveExt;
match index {
$(fields::$field => {
@@ -154,7 +184,7 @@ macro_rules! Walk {
Err(err) => {
Err(FieldError(FieldErrorKind::$field(err)))
}
- }).into_erased()
+ })
// E::map($crate::Walker::<'ctx, E>::walk(walker, visitor), |result| match result {
// Ok(_) => {
@@ -165,7 +195,7 @@ macro_rules! Walk {
// }
// })
})*
- _ => E::ready(Ok($crate::Flow::Done)).into_erased()
+ _ => E::ready(Ok($crate::Flow::Done))
}
}
}
@@ -211,3 +241,45 @@ macro_rules! Walk {
// todo!();
// }
// }
+
+
+pub mod demo {
+ use crate::Walk;
+ use macro_rules_attribute::derive;
+ use crate::{
+ effect::{
+ blocking::{BlockOn, Blocking, Spin},
+ // r#async::Async,
+ Effective as _,
+ },
+ transform, Build, DefaultMode,
+ };
+
+ #[derive(Walk!, Debug)]
+ pub struct X {
+ pub a: bool,
+ pub b: bool,
+ pub c: bool,
+ }
+
+ #[derive(Build!, Debug, PartialEq)]
+ pub struct Y {
+ pub a: bool,
+ pub b: bool,
+ pub c: bool,
+ }
+
+ #[inline(never)]
+ pub fn ident(x: X) -> Y {
+ let other =
+ transform::<<Y as crate::Build<'_, DefaultMode, _>>::Builder, _, Blocking<Spin>>(
+ ((), (), ()),
+ Walk::<DefaultMode, _>::into_walker(&x),
+ )
+ .value();
+
+ // let other = Spin::block_on(other.into_future());
+
+ other.0.unwrap()
+ }
+}
diff --git a/src/macros/build.rs b/src/macros/build.rs
index 380063b..b990f08 100644
--- a/src/macros/build.rs
+++ b/src/macros/build.rs
@@ -48,7 +48,7 @@ macro_rules! Build {
fn new_builders<'a>(seed: Self::Seed) -> $crate::effect::ErasedEffective<'a, Self::Builders, E> {
let ($($field),*) = seed;
- use $crate::effect::Effective;
+ use $crate::effect::EffectiveExt;
$crate::effect::join(
($(<<$type as $crate::Build<'ctx, M, E>>::Builder as $crate::Builder::<E>>::from_seed($field),)*)
@@ -56,7 +56,7 @@ macro_rules! Build {
Builders {
$($field),*
}
- }).into_erased()
+ })
// E::wrap(async move {
// Builders {
@@ -67,7 +67,7 @@ macro_rules! Build {
fn from_builders<'a>(builders: Self::Builders) -> $crate::effect::ErasedEffective<'a, Result<Self::T, Self::Error>, E> {
use $crate::Builder;
- use $crate::effect::Effective;
+ use $crate::effect::EffectiveExt;
$crate::effect::try_join(
(
@@ -78,7 +78,7 @@ macro_rules! Build {
$($field),*
}),
Err(err) => Err(err)
- }).into_erased()
+ })
// E::wrap(async {
// Ok($name {
diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs
index fbcfdd2..6dc58fb 100644
--- a/src/protocol/visitor.rs
+++ b/src/protocol/visitor.rs
@@ -1,4 +1,10 @@
-use crate::Flow;
+use core::ops::ControlFlow;
+
+use crate::{
+ effect::{Effective, EffectiveExt as _, ErasedEffective, Ss},
+ never::Never,
+ Flow, Status,
+};
mod recoverable;
mod request_hint;
@@ -25,6 +31,122 @@ pub enum VisitResult<S> {
Control(Flow),
}
+impl<S> VisitResult<S> {
+ pub fn unit_skipped(self) -> VisitResult<()> {
+ match self {
+ VisitResult::Skipped(_) => VisitResult::Skipped(()),
+ VisitResult::Control(flow) => VisitResult::Control(flow),
+ }
+ }
+
+ pub fn to_status(self) -> Status {
+ match self {
+ VisitResult::Skipped(_) => Status::Ok,
+ VisitResult::Control(flow) => flow.to_status(),
+ }
+ }
+
+ pub fn to_flow(self) -> Option<Flow> {
+ match self {
+ VisitResult::Skipped(_) => None,
+ VisitResult::Control(flow) => Some(flow),
+ }
+ }
+
+ pub fn dont_break_if_skipped(self) -> Option<Status> {
+ match self {
+ VisitResult::Skipped(_) => None,
+ VisitResult::Control(Flow::Continue) => Some(Status::Ok),
+ VisitResult::Control(Flow::Done) => Some(Status::Ok),
+ VisitResult::Control(Flow::Err) => Some(Status::Err),
+ }
+ }
+
+ pub fn break_if_done_or_err(self) -> Option<Status> {
+ match self {
+ VisitResult::Skipped(_) => None,
+ VisitResult::Control(Flow::Continue) => None,
+ VisitResult::Control(Flow::Done) => Some(Status::Ok),
+ VisitResult::Control(Flow::Err) => Some(Status::Err),
+ }
+ }
+
+ pub fn break_if_err(self) -> Option<Status> {
+ match self {
+ VisitResult::Skipped(_) => None,
+ VisitResult::Control(Flow::Continue) => None,
+ VisitResult::Control(Flow::Done) => None,
+ VisitResult::Control(Flow::Err) => Some(Status::Err),
+ }
+ }
+}
+
+pub trait EffectiveVisitExt<'lt>: Effective<'lt> {
+ fn if_skipped<'ctx: 'lt, 'wrap, Ctx: Ss, F: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, (Ctx, VisitResult<()>), Self::Effect>
+ where
+ Self: Effective<'lt, Output = (Ctx, VisitResult<()>)>,
+ F: for<'temp> FnOnce(
+ &'temp mut Ctx,
+ )
+ -> ErasedEffective<'temp, VisitResult<()>, Self::Effect, &'ctx ()>,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |(ctx, v)| {
+ (
+ ctx,
+ match v {
+ VisitResult::Skipped(()) => ControlFlow::Continue(()),
+ v => ControlFlow::Break(v),
+ },
+ )
+ },
+ |ctx, ()| f(ctx).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |ctx, _, v| (ctx, v),
+ )
+ }
+
+ fn if_not_finished<'ctx: 'lt, 'wrap, Ctx: Ss, F: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, (Ctx, VisitResult<()>), Self::Effect>
+ where
+ Self: Effective<'lt, Output = (Ctx, VisitResult<()>)>,
+ F: for<'temp> FnOnce(
+ &'temp mut Ctx,
+ )
+ -> ErasedEffective<'temp, VisitResult<()>, Self::Effect, &'ctx ()>,
+ 'lt: 'wrap,
+ {
+ self.r#do(
+ |(ctx, v)| {
+ (
+ ctx,
+ match v {
+ VisitResult::Skipped(()) | VisitResult::Control(Flow::Continue) => {
+ ControlFlow::Continue(())
+ }
+ v => ControlFlow::Break(v),
+ },
+ )
+ },
+ |ctx, ()| f(ctx).cast(),
+ |_, v| ControlFlow::<_, Never>::Break(v),
+ |_, _| unreachable!(),
+ |_, _, _: Never| unreachable!(),
+ |ctx, _, v| (ctx, v),
+ )
+ }
+}
+
+impl<'lt, T: Effective<'lt>> EffectiveVisitExt<'lt> for T {}
+
impl<S> PartialEq for VisitResult<S> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs
index 7a2b455..9f67c22 100644
--- a/src/protocol/visitor/recoverable.rs
+++ b/src/protocol/visitor/recoverable.rs
@@ -1,6 +1,6 @@
use crate::{
any::TypeName,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, ErasedEffective, ReadyExt as _},
higher_ranked_type,
hkt::Marker,
protocol::{
@@ -76,6 +76,6 @@ pub fn visit_recoverable<'a, 'ctx, E: Effect>(
object.visit(scope)
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(VisitResult::Skipped(scope)).into_erased()
+ VisitResult::Skipped(scope).ready()
}
}
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index f60005e..73c95db 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -1,6 +1,6 @@
use crate::{
any::TypeName,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, ErasedEffective, ReadyExt as _},
higher_ranked_type,
hkt::Marker,
protocol::{DynVisitor, DynWalker},
@@ -54,6 +54,6 @@ pub fn visit_request_hint<'a, 'ctx, E: Effect>(
object.request_hint(walker)
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(VisitResult::Skipped(walker)).into_erased()
+ VisitResult::Skipped(walker).ready()
}
}
diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs
index 4f18f49..e748eef 100644
--- a/src/protocol/visitor/sequence.rs
+++ b/src/protocol/visitor/sequence.rs
@@ -1,6 +1,6 @@
use crate::{
any::TypeName,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, ErasedEffective, ReadyExt as _},
higher_ranked_type,
hkt::Marker,
protocol::{
@@ -17,10 +17,12 @@ use super::VisitResult;
/// This protocol uses a scope to give temporary control to the visitor.
/// The visitor will drive the walker for each item.
pub trait Sequence<'ctx, E: Effect> {
- fn visit<'a>(
+ fn visit<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
- scope: DynSequenceScope<'a, 'ctx, E>,
- ) -> ErasedEffective<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E>;
+ scope: DynSequenceScope<'b, 'ctx, E>,
+ ) -> ErasedEffective<'c, VisitResult<DynSequenceScope<'b, 'ctx, E>>, E>
+ where
+ 'ctx: 'a;
}
pub struct SequenceProto<E: Effect>(Marker<E>);
@@ -44,7 +46,12 @@ higher_ranked_type! {
pub trait SequenceScope<'ctx, E: Effect> {
fn size_hint(&mut self) -> ErasedEffective<'_, (usize, Option<usize>), E>;
- fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> ErasedEffective<'a, Flow, E>;
+ fn next<'a: 'c, 'b: 'c, 'c>(
+ &'a mut self,
+ visitor: DynVisitor<'b, 'ctx>,
+ ) -> ErasedEffective<'c, Flow, E>
+ where
+ 'ctx: 'c + 'a + 'b;
}
pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + Sync + 'a);
@@ -96,6 +103,6 @@ pub fn visit_sequence<'a, 'ctx, E: Effect>(
object.visit(scope)
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(VisitResult::Skipped(scope)).into_erased()
+ VisitResult::Skipped(scope).ready()
}
}
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index 5053bd0..33b76ec 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -1,6 +1,8 @@
+use core::any::TypeId;
+
use crate::{
any::TypeName,
- effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, EffectiveExt, ErasedEffective, ReadyExt},
higher_ranked_type,
hkt::Marker,
protocol::{
@@ -8,7 +10,7 @@ use crate::{
DynVisitor,
},
symbol::Symbol,
- DynWalkerAdapter, DynWalkerError, DynWalkerObjSafe, Flow, WalkerTypes,
+ tri, DynWalkerAdapter, DynWalkerError, DynWalkerObjSafe, WalkerTypes,
};
use super::VisitResult;
@@ -118,7 +120,7 @@ impl<K: TagKind, E: Effect> HintMeta for TagProto<K, E> {
pub enum TagErrorKind<E> {
NeverWalked,
- /// This can only happen if a panic happens furing the walk and is then caught before calling
+ /// This can only happen if a panic happens during the walk and is then caught before calling
/// finish.
WalkNeverFinished,
@@ -165,91 +167,58 @@ impl<E> TagError<E> {
}
#[inline(always)]
-pub fn visit_tag<'a, 'ctx: 'a, K: TagKind, E: Effect, W: crate::Walker<'ctx, E> + 'a>(
+pub fn visit_tag<
+ 'ctx: 'visitor,
+ 'visitor: 'wrap,
+ 'wrap,
+ K: TagKind,
+ E: Effect,
+ W: crate::Walker<'ctx, E> + 'wrap,
+>(
kind: K,
- visitor: DynVisitor<'a, 'ctx>,
+ visitor: DynVisitor<'visitor, 'ctx>,
walker: W,
-) -> ErasedEffective<'a, Result<VisitResult<W>, TagError<W::Error>>, E>
+) -> ErasedEffective<'wrap, Result<VisitResult<W>, TagError<W::Error>>, E>
where
W: WalkerTypes,
{
// Wrap the walker to allow it to be passed to a dyn walker argument.
let walker = DynWalkerAdapter::new(walker);
+ // Give everything to the effective chain to be used as context.
E::ready((kind, visitor, walker))
- .as_ctx(
- all_ctx,
- |(kind, visitor, walker), _| {
- let object = visitor.upcast_mut::<TagProto<K, E>>();
-
- E::ready((*kind, object, walker))
- .as_ctx(
- all_ctx,
- |(kind, object, walker), _| match object {
- Some(object) => object
- .visit(*kind, &mut **walker)
- .map(|value| match value {
- VisitResult::Skipped(_) => None,
- VisitResult::Control(flow) => Some(flow),
- })
- .into_erased(),
- None => E::ready(None).into_erased(),
- },
- merge_ctx,
- )
- .map(|((_, _, _), value)| value)
- .into_erased()
- },
- merge_ctx,
- )
- .as_ctx(
- all_ctx,
- |((kind, visitor, walker), result), _| {
- if result.is_some()
- || core::any::TypeId::of::<TagDyn>() != core::any::TypeId::of::<K>()
- {
- E::ready(None).into_erased()
- } else {
- let object = visitor.upcast_mut::<TagProto<TagDyn, E>>();
-
- E::ready((*kind, object, walker))
- .as_ctx(
- all_ctx,
- |(kind, object, walker), _| match object {
- Some(object) => object
- .visit(TagDyn(kind.symbol()), &mut **walker)
- .map(|value| match value {
- VisitResult::Skipped(_) => None,
- VisitResult::Control(flow) => Some(flow),
- })
- .into_erased(),
- None => E::ready(None).into_erased(),
- },
- merge_ctx,
- )
- .map(|((_, _, _), value)| value)
- .into_erased()
- }
- },
- merge_ctx,
- )
- .map(|((ctx, result), other)| match (result, other) {
- (Some(result), None) => (ctx, Some(result)),
- (None, Some(result)) => (ctx, Some(result)),
- (Some(_), Some(_)) => unreachable!(),
- (None, None) => (ctx, None),
+ .as_ctx(|(kind, visitor, walker)| {
+ // Try to visit the tag kind as given.
+ tri!(visitor.upcast_mut::<TagProto<K, E>>())
+ .visit(*kind, walker)
+ .map(VisitResult::to_flow)
+ .cast()
+ })
+ .as_ctx_or_else(|(kind, visitor, walker)| {
+ // If the tag type is already dynamic we don't need to try visiting again.
+ if TypeId::of::<K>() == TypeId::of::<TagDyn>() {
+ return None.ready();
+ }
+
+ // Visit using the dynamic tag, but with the same symbol.
+ tri!(visitor.upcast_mut::<TagProto<TagDyn, E>>())
+ .visit(TagDyn(kind.symbol()), walker)
+ .map(VisitResult::to_flow)
+ .cast()
})
.map(|((kind, _, walker), result)| match result {
+ // The visit was performed so return the control flow.
Some(flow) => Ok(VisitResult::Control(flow)),
+
+ // The visit was not performed.
+ // We need to give back the walker as we got it.
None => match walker.into_inner() {
Ok(walker) => Ok(VisitResult::Skipped(walker)),
Err(err) => Err(map_walker_err(kind, err)),
},
})
- .into_erased()
}
-#[inline(always)]
fn map_walker_err<K: TagKind, W: WalkerTypes>(
kind: K,
err: DynWalkerError<W>,
diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs
index 11c78ff..2c616ec 100644
--- a/src/protocol/visitor/value.rs
+++ b/src/protocol/visitor/value.rs
@@ -4,7 +4,7 @@
use crate::{
any::TypeName,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, ErasedEffective, ReadyExt as _},
higher_ranked_type,
hkt::Marker,
protocol::{
@@ -108,6 +108,6 @@ where
object.visit(value)
} else {
// If the visitor doesn't support request hint then we continue.
- E::ready(VisitResult::Skipped(value)).into_erased()
+ VisitResult::Skipped(value).ready()
}
}
diff --git a/src/transform.rs b/src/transform.rs
index 65b9887..caf24ab 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -2,7 +2,7 @@ use core::marker::PhantomData;
use crate::{
build::Builder,
- effect::{all_ctx, merge_ctx, Effect, Effective, EffectiveExt, ErasedEffective},
+ effect::{Effect, Effective, EffectiveExt, ErasedEffective},
hkt::Marker,
BuilderTypes, Walk, Walker, WalkerTypes,
};
@@ -14,17 +14,12 @@ pub fn transform<'a, 'ctx: 'a, B: Builder<'ctx, E> + 'a, W: Walker<'ctx, E> + 'a
walker: W,
) -> ErasedEffective<'a, (Result<B::Value, B::Error>, Result<W::Output, W::Error>), E> {
B::from_seed(seed)
- .as_ctx(
- all_ctx,
- |builder, _| walker.walk(builder.as_visitor()).into_erased(),
- merge_ctx,
- )
+ .as_ctx(|builder| walker.walk(builder.as_visitor()).cast())
.then(|(builder, walker_result)| {
builder
.build()
.map(|builder_result| (builder_result, walker_result))
})
- .into_erased()
// B::from_seed(seed).map_with(walker, |builder, walker| walker.walk(builder.as_visitor()));
// E::wrap(async {
diff --git a/src/walk.rs b/src/walk.rs
index 9f4a828..9c6cd10 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -1,7 +1,7 @@
pub mod walkers;
use crate::{
- effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, EffectiveExt, ErasedEffective},
protocol::DynVisitor,
Flow,
};
@@ -121,34 +121,29 @@ impl<'ctx, W: Walker<'ctx, E>, E: Effect> WalkerObjSafe<'ctx, E> for DynWalkerAd
core::mem::replace(&mut self.state, DynWalkerState::Walking)
{
E::ready((self, visitor))
- .as_ctx(
- all_ctx,
- |(this, visitor), _| {
- // Walk the walker.
- walker
- .walk(visitor.cast())
- .map(|value| match value {
- Ok(value) => {
- this.state = DynWalkerState::Done(value);
- Flow::Done
- }
- Err(err) => {
- this.state = DynWalkerState::Err(err);
-
- // Signal that control flow should stop as soon as possible as we
- // are in an error state.
- Flow::Err
- }
- })
- .into_erased()
- },
- merge_ctx,
- )
+ .as_ctx(|(this, visitor)| {
+ // Walk the walker.
+ walker
+ .walk(visitor.cast())
+ .map(|value| match value {
+ Ok(value) => {
+ this.state = DynWalkerState::Done(value);
+ Flow::Done
+ }
+ Err(err) => {
+ this.state = DynWalkerState::Err(err);
+
+ // Signal that control flow should stop as soon as possible as we
+ // are in an error state.
+ Flow::Err
+ }
+ })
+ .cast()
+ })
.map(|(_, value)| value)
- .into_erased()
} else {
// Can't do anything if the walker has already been walked.
- E::ready(Flow::Done).into_erased()
+ E::ready(Flow::Done)
}
}
}
diff --git a/src/walk/walkers/core/key_value.rs b/src/walk/walkers/core/key_value.rs
index 3c0f700..1adb7b1 100644
--- a/src/walk/walkers/core/key_value.rs
+++ b/src/walk/walkers/core/key_value.rs
@@ -1,16 +1,20 @@
use core::marker::PhantomData;
use crate::{
- effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
+ effect::{Effect, EffectExt as _, Effective, EffectiveExt as _, ErasedEffective},
never::Never,
protocol::{
- visitor::{visit_tag, TagConst, TagError, TagKind, VisitResult},
+ visitor::{
+ tags, visit_tag, EffectiveVisitExt as _, TagConst, TagError, TagKind, VisitResult,
+ },
DynVisitor,
},
walkers::core::noop::NoopWalker,
Flow, WalkerTypes, TAG_KEY, TAG_KEY_VALUE, TAG_VALUE,
};
+use super::value::ValueWalker;
+
pub struct KeyValueWalker<T, K, V> {
key_walker: K,
value_walker: V,
@@ -53,7 +57,7 @@ impl<'ctx, T, K, V, E> crate::Walker<'ctx, E> for KeyValueWalker<T, K, V>
where
E: Effect,
T: TagKind,
- K: crate::Walker<'ctx, E>,
+ K: crate::Walker<'ctx, E> + 'ctx,
V: crate::Walker<'ctx, E> + 'ctx,
{
#[inline(always)]
@@ -61,22 +65,38 @@ where
self,
visitor: DynVisitor<'b, 'ctx>,
) -> ErasedEffective<'c, Result<Self::Output, Self::Error>, E> {
- E::ready(visitor)
- .as_ctx(
- all_ctx,
- move |visitor, _| {
- self.value_walker
- .walk(visitor.cast())
- .map(|result| match result {
- Ok(_) => Ok::<_, Self::Error>(()),
- Err(_err) => todo!(),
- })
- .into_erased()
- },
- merge_ctx,
- )
- .map(|(_, value)| value)
- .into_erased()
+ let Self {
+ key_walker,
+ value_walker,
+ tag,
+ } = self;
+
+ E::as_ctx(
+ visitor,
+ #[inline(always)]
+ |visitor| {
+ visit_tag::<tags::Key, E, _>(TagConst, visitor.cast(), key_walker)
+ .map(|result| match result {
+ Ok(visit) => visit.unit_skipped(),
+ Err(_) => Flow::Err.into(),
+ })
+ .cast()
+ },
+ )
+ .if_not_finished(
+ #[inline(always)]
+ |visitor| {
+ value_walker
+ .walk(visitor.cast())
+ .map(|result| match result {
+ Ok(_) => Flow::Done.into(),
+ Err(_err) => Flow::Err.into(),
+ })
+ .cast()
+ },
+ )
+ .remove_ctx()
+ .map(|visit| Ok(()))
// E::wrap(async move {
// match visit_tag::<T, E, _>(self.tag, visitor.cast(), NoopWalker::new()).await {
diff --git a/src/walk/walkers/core/noop.rs b/src/walk/walkers/core/noop.rs
index 6c846e7..d961d7e 100644
--- a/src/walk/walkers/core/noop.rs
+++ b/src/walk/walkers/core/noop.rs
@@ -29,6 +29,6 @@ impl<'ctx, E: Effect> crate::Walker<'ctx, E> for NoopWalker {
self,
_visitor: DynVisitor<'b, 'ctx>,
) -> ErasedEffective<'c, Result<Self::Output, Self::Error>, E> {
- E::ready(Ok(())).into_erased()
+ E::ready(Ok(()))
}
}
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
index 82e399d..393450f 100644
--- a/src/walk/walkers/core/struct.rs
+++ b/src/walk/walkers/core/struct.rs
@@ -3,15 +3,15 @@ use core::{any::TypeId, marker::PhantomData};
use crate::{
any::{AnyTrait, BorrowedStatic, BorrowedStaticHrt},
any_trait,
- effect::{all_ctx, merge_ctx, Effect, Effective, EffectiveExt, ErasedEffective},
+ effect::{Effect, EffectExt as _, Effective, EffectiveExt, ErasedEffective, ReadyExt as _},
hkt::Marker,
never::Never,
protocol::{
visitor::{
visit_recoverable, visit_request_hint, visit_sequence, visit_tag, visit_value,
- RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto,
- SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown,
- ValueProto, VisitResult,
+ EffectiveVisitExt as _, RecoverableKnown, RecoverableProto, RecoverableScope,
+ SequenceKnown, SequenceProto, SequenceScope, TagConst, TagDyn, TagError, TagHint,
+ TagKnown, TagProto, ValueKnown, ValueProto, VisitResult,
},
walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown},
DynVisitor, DynWalker,
@@ -104,6 +104,16 @@ where
_generics: Default::default(),
}
}
+
+ fn record_tag_error<U>(
+ &mut self,
+ result: Result<VisitResult<U>, TagError<Never>>,
+ ) -> VisitResult<U> {
+ result.unwrap_or_else(|err| {
+ self.error = Some(StructWalkErrorKind::Tag(err));
+ Flow::Err.into()
+ })
+ }
}
impl<'ctx, I, S, M, E> WalkerTypes for StructWalker<'ctx, I, S, M, E>
@@ -130,19 +140,15 @@ where
{
E::ready((self, visitor))
.as_ctx(
- all_ctx,
#[inline(always)]
- |(this, visitor), _| {
- RecoverableScope::<'ctx, E>::new_walk::<'_, '_, '_>(this, visitor.cast())
- .into_erased()
+ |(this, visitor)| {
+ RecoverableScope::<'ctx, E>::new_walk::<'_, '_, '_>(this, visitor.cast()).cast()
},
- merge_ctx,
)
.map(|((this, _), _)| match this.error {
Some(err) => Err(StructWalkError { kind: err }),
None => Ok(()),
})
- .into_erased()
// E::ready(self).as_ctx_for::<'ctx, '_>(|this, _| {
// (RecoverableScope::<'ctx, E>::new_walk::<'_, 'b, '_>(this, visitor), PhantomData)
@@ -175,6 +181,7 @@ any_trait! {
] where
E: Effect,
I: StructTypeInfo<'ctx, M, S = StaticType>,
+ M: 'ctx,
I::T: 'static
}
@@ -205,7 +212,7 @@ where
&'a mut self,
_hint: &'a <RecoverableProto<E> as HintMeta>::Hint,
) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, RecoverableProto<E>>, ()>, E> {
- E::ready(Ok(RecoverableKnown)).into_erased()
+ E::ready(Ok(RecoverableKnown))
}
}
@@ -251,7 +258,6 @@ where
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
- .into_erased()
}
}
@@ -297,7 +303,6 @@ where
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
- .into_erased()
}
}
@@ -339,7 +344,6 @@ where
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
- .into_erased()
}
}
@@ -385,7 +389,6 @@ where
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
- .into_erased()
}
}
@@ -432,7 +435,6 @@ where
E::ready(Ok(TagKnown {
kind_available: Some(true),
}))
- .into_erased()
}
}
@@ -479,7 +481,7 @@ where
'ctx,
TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>,
>::hint(self, visitor, TagHint { kind: TagConst }),
- _ => E::ready(Flow::Continue).into_erased(),
+ _ => E::ready(Flow::Continue),
}
}
@@ -496,7 +498,6 @@ where
kind_available: Some(false),
}),
})
- .into_erased()
}
}
@@ -528,7 +529,7 @@ where
&'a mut self,
_hint: &'a (),
) -> ErasedEffective<'a, Result<ValueKnown<'a, BorrowedStatic<'ctx, I::T>>, ()>, E> {
- E::ready(Ok(ValueKnown { preview: None })).into_erased()
+ E::ready(Ok(ValueKnown { preview: None }))
}
}
@@ -560,11 +561,10 @@ where
E::ready(Ok(SequenceKnown {
len: (len, Some(len)),
}))
- .into_erased()
}
}
-impl<'ctx, I, S, M, E> SequenceScope<'ctx, E> for StructWalker<'ctx, I, S, M, E>
+impl<'ctx, I, S, M: 'ctx, E> SequenceScope<'ctx, E> for StructWalker<'ctx, I, S, M, E>
where
E: Effect,
I: StructTypeInfo<'ctx, M, S = S>,
@@ -573,28 +573,29 @@ where
fn size_hint(&mut self) -> ErasedEffective<'_, (usize, Option<usize>), E> {
let len = I::FIELDS.len();
- E::ready((len, Some(len))).into_erased()
+ E::ready((len, Some(len)))
}
#[inline(always)]
- fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> ErasedEffective<'a, Flow, E> {
+ fn next<'a: 'c, 'b: 'c, 'c>(
+ &'a mut self,
+ visitor: DynVisitor<'b, 'ctx>,
+ ) -> ErasedEffective<'c, Flow, E> {
if self.index >= I::FIELDS.len() {
- return E::ready(Flow::Done).into_erased();
+ return Flow::Done.ready();
}
let index = self.index;
self.index += 1;
- I::walk_field::<E>(index, self.value, visitor)
- .map(|result| match result {
- Ok(flow) => flow,
- Err(err) => {
- // Record the error and signal a break.
- self.error = Some(StructWalkErrorKind::Field(err));
- Flow::Err
- }
- })
- .into_erased()
+ I::walk_field::<E>(index, self.value, visitor).map(|result| match result {
+ Ok(flow) => flow,
+ Err(err) => {
+ // Record the error and signal a break.
+ self.error = Some(StructWalkErrorKind::Field(err));
+ Flow::Err
+ }
+ })
// E::map(
// I::walk_field::<E>(index, self.value, visitor),
@@ -610,7 +611,7 @@ where
}
}
-impl<'ctx, I, M, E> RecoverableScope<'ctx, E> for StructWalker<'ctx, I, StaticType, M, E>
+impl<'ctx, I, M: 'ctx, E> RecoverableScope<'ctx, E> for StructWalker<'ctx, I, StaticType, M, E>
where
E: Effect,
I: StructTypeInfo<'ctx, M, S = StaticType>,
@@ -619,7 +620,7 @@ where
#[inline(always)]
fn new_walk<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
- mut visitor: DynVisitor<'b, 'ctx>,
+ visitor: DynVisitor<'b, 'ctx>,
) -> ErasedEffective<'c, Status, E> {
// Reset the errors to default state.
self.error = None;
@@ -627,225 +628,49 @@ where
// Reset the field index to the default.
self.index = 0;
- E::ready((self, visitor))
- .as_ctx(
- all_ctx,
- |(this, visitor), _| {
- visit_request_hint::<E>(visitor.cast(), DynWalker(*this))
- .map(|result| match result {
- VisitResult::Control(Flow::Continue) | VisitResult::Skipped(_) => None,
- VisitResult::Control(Flow::Done) => Some(Ok(())),
- VisitResult::Control(Flow::Err) => Some(Err(())),
- })
- .into_erased()
- },
- merge_ctx,
+ E::as_ctx((self, visitor), |(this, visitor)| {
+ visit_request_hint::<E>(visitor.cast(), DynWalker(*this))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ })
+ .if_not_finished(|(this, visitor)| {
+ visit_value::<_, E>(visitor.cast(), BorrowedStatic(this.value))
+ .map(VisitResult::unit_skipped)
+ .cast()
+ })
+ .if_not_finished(|(this, visitor)| {
+ visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
+ TagConst,
+ visitor.cast(),
+ ValueWalker::new(TypeId::of::<I::T>()),
)
- .as_ctx(
- all_ctx,
- |((this, visitor), result), _| {
- if result.is_some() {
- E::ready(None).into_erased()
- } else {
- visit_sequence::<E>(visitor.cast(), *this)
- .map(|result| match result {
- VisitResult::Control(Flow::Continue) | VisitResult::Skipped(_) => {
- None
- }
- VisitResult::Control(Flow::Done) => Some(Ok(())),
- VisitResult::Control(Flow::Err) => Some(Err(())),
- })
- .into_erased()
- }
- },
- merge_ctx,
+ .map(|result| this.record_tag_error(result).unit_skipped())
+ .cast()
+ })
+ .if_not_finished(|(this, visitor)| {
+ visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>(
+ TagConst,
+ visitor.cast(),
+ NoopWalker::new(),
)
- .map(|((ctx, result), other)| match (result, other) {
- (Some(result), None) => (ctx, Some(result)),
- (None, Some(result)) => (ctx, Some(result)),
- (Some(_), Some(_)) => unreachable!(),
- (None, None) => (ctx, None),
- })
- .as_ctx_or_else(|(this, visitor)| {
- // .as_ctx(all_ctx, |((this, visitor), result), _| {
- // if result.is_some() {
- // E::ready(None).into_erased()
- // } else {
- visit_value::<_, E>(visitor.cast(), BorrowedStatic(this.value))
- .map(|result| match result {
- VisitResult::Control(Flow::Continue) | VisitResult::Skipped(_) => None,
- VisitResult::Control(Flow::Done) => Some(Ok(())),
- VisitResult::Control(Flow::Err) => Some(Err(())),
- })
- .into_erased()
- // }
- // })
- // .map(|((ctx, result), other)| match (result, other) {
- // (Some(result), None) => (ctx, Some(result)),
- // (None, Some(result)) => (ctx, Some(result)),
- // (Some(_), Some(_)) => unreachable!(),
- // (None, None) => (ctx, None),
- })
- .as_ctx_or_else(|(this, visitor)| {
- visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
- TagConst,
- visitor.cast(),
- ValueWalker::new(TypeId::of::<I::T>()),
- )
- .map(|result| match result {
- Err(err) => {
- this.error = Some(StructWalkErrorKind::Tag(err));
- Some(Err(()))
- }
- Ok(VisitResult::Control(Flow::Continue) | VisitResult::Skipped(_)) => None,
- Ok(VisitResult::Control(Flow::Done)) => Some(Ok(())),
- Ok(VisitResult::Control(Flow::Err)) => Some(Err(())),
- })
- .into_erased()
- })
- // .as_ctx(all_ctx, |((this, visitor), result), _| {
- // if result.is_some() {
- // E::ready(None).into_erased()
- // } else {
- // visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>(
- // TagConst,
- // visitor.cast(),
- // ValueWalker::new(TypeId::of::<I::T>()),
- // )
- // .map(|result| match result {
- // Err(err) => {
- // this.error = Some(StructWalkErrorKind::Tag(err));
- // Some(Err(()))
- // }
- // Ok(VisitResult::Control(Flow::Continue) | VisitResult::Skipped(_)) => None,
- // Ok(VisitResult::Control(Flow::Done)) => Some(Ok(())),
- // Ok(VisitResult::Control(Flow::Err)) => Some(Err(())),
- // })
- // .into_erased()
- // }
- // })
- // .map(|((ctx, result), other)| match (result, other) {
- // (Some(result), None) => (ctx, Some(result)),
- // (None, Some(result)) => (ctx, Some(result)),
- // (Some(_), Some(_)) => unreachable!(),
- // (None, None) => (ctx, None),
- // })
- .map(|(_, value)| match value {
- None => Ok(()),
- Some(value) => value,
- })
- .into_erased()
-
- // E::wrap(async move {
- // // // We should check if the visitor wants something specific.
- // // match visit_request_hint::<E>(visitor.cast(), DynWalker(self)).await {
- // // VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {}
- // // VisitResult::Control(Flow::Done) => return Ok(()),
- // // VisitResult::Control(Flow::Err) => return Err(()),
- // // }
- // //
- // // // Attempt to visit the value directly.
- // // match visit_value::<_, E>(visitor.cast(), BorrowedStatic(self.value)).await {
- // // VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {}
- // // VisitResult::Control(Flow::Done) => return Ok(()),
- // // VisitResult::Control(Flow::Err) => return Err(()),
- // // }
- // //
- // // // 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.cast(),
- // // ValueWalker::new(TypeId::of::<I::T>()),
- // // )
- // // .await
- // // {
- // // Err(err) => {
- // // self.error = Some(StructWalkErrorKind::Tag(err));
- // // return Err(());
- // // }
- // // Ok(VisitResult::Skipped(_)) | Ok(VisitResult::Control(Flow::Continue)) => {}
- // // Ok(VisitResult::Control(Flow::Done)) => return Ok(()),
- // // Ok(VisitResult::Control(Flow::Err)) => return Err(()),
- // // }
- // //
- // // match visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>(
- // // TagConst,
- // // visitor.cast(),
- // // NoopWalker::new(),
- // // )
- // // .await
- // // {
- // // Ok(VisitResult::Skipped(_)) => {
- // // match visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>(
- // // TagConst,
- // // visitor.cast(),
- // // NoopWalker::new(),
- // // )
- // // .await
- // // {
- // // Err(err) => {
- // // self.error = Some(StructWalkErrorKind::Tag(err));
- // // return Err(());
- // // }
- // // Ok(VisitResult::Skipped(_)) | Ok(VisitResult::Control(Flow::Continue)) => {}
- // // Ok(VisitResult::Control(Flow::Done)) => return Ok(()),
- // // Ok(VisitResult::Control(Flow::Err)) => return Err(()),
- // // }
- // // }
- // // Err(err) => {
- // // self.error = Some(StructWalkErrorKind::Tag(err));
- // // return Err(());
- // // }
- // // Ok(VisitResult::Control(Flow::Continue)) => {}
- // // Ok(VisitResult::Control(Flow::Done)) => return Ok(()),
- // // Ok(VisitResult::Control(Flow::Err)) => return Err(()),
- // // }
- // //
- // // match visit_tag::<TagConst<{ TAG_TYPE_NAME.to_int() }>, E, _>(
- // // TagConst,
- // // visitor.cast(),
- // // ValueWalker::new(I::NAME),
- // // )
- // // .await
- // // {
- // // Err(err) => {
- // // self.error = Some(StructWalkErrorKind::Tag(err));
- // // return Err(());
- // // }
- // // Ok(VisitResult::Skipped(_)) | Ok(VisitResult::Control(Flow::Continue)) => {}
- // // Ok(VisitResult::Control(Flow::Done)) => return Ok(()),
- // // Ok(VisitResult::Control(Flow::Err)) => return Err(()),
- // // }
- // //
- // // match visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>(
- // // TagConst,
- // // visitor.cast(),
- // // StaticSliceWalker::<_, ValueWalker<&'static str>>::new(I::FIELDS),
- // // )
- // // .await
- // // {
- // // Err(err) => {
- // // self.error = Some(StructWalkErrorKind::FieldTag(err));
- // // return Err(());
- // // }
- // // Ok(VisitResult::Skipped(_)) | Ok(VisitResult::Control(Flow::Continue)) => {}
- // // Ok(VisitResult::Control(Flow::Done)) => return Ok(()),
- // // Ok(VisitResult::Control(Flow::Err)) => return Err(()),
- // // }
- //
- // match visit_sequence::<E>(visitor, self).await {
- // VisitResult::Control(Flow::Continue) | VisitResult::Skipped(_) => {}
- // VisitResult::Control(Flow::Done) => return Ok(()),
- // VisitResult::Control(Flow::Err) => return Err(()),
- // }
- //
- // Ok(())
- // })
+ .map(|result| this.record_tag_error(result).unit_skipped())
+ .cast()
+ })
+ .if_skipped(|(this, visitor)| {
+ visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>(
+ TagConst,
+ visitor.cast(),
+ NoopWalker::new(),
+ )
+ .map(|result| this.record_tag_error(result).unit_skipped())
+ .cast()
+ })
+ .if_not_finished(|(this, visitor)| {
+ visit_sequence::<E>(visitor.cast(), *this)
+ .map(VisitResult::unit_skipped)
+ .cast()
+ })
+ .remove_ctx()
+ .map(VisitResult::to_status)
}
}
diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs
index 36d0013..d2b170f 100644
--- a/src/walk/walkers/core/tag.rs
+++ b/src/walk/walkers/core/tag.rs
@@ -84,7 +84,10 @@ where
&'static T: Into<W>,
{
#[inline(always)]
- fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> ErasedEffective<'a, Flow, E> {
+ fn next<'a: 'c, 'b: 'c, 'c>(
+ &'a mut self,
+ visitor: DynVisitor<'b, 'ctx>,
+ ) -> ErasedEffective<'c, Flow, E> {
if let Some(name) = self.names.get(self.current) {
self.current += 1;
todo!()
@@ -95,12 +98,12 @@ where
// }
// })
} else {
- E::ready(Flow::Done).into_erased()
+ E::ready(Flow::Done)
}
}
#[inline(always)]
fn size_hint(&mut self) -> ErasedEffective<'_, (usize, Option<usize>), E> {
- E::ready((self.names.len(), Some(self.names.len()))).into_erased()
+ E::ready((self.names.len(), Some(self.names.len())))
}
}
diff --git a/src/walk/walkers/core/value.rs b/src/walk/walkers/core/value.rs
index bc6a44f..72715cb 100644
--- a/src/walk/walkers/core/value.rs
+++ b/src/walk/walkers/core/value.rs
@@ -1,6 +1,6 @@
use crate::{
any::{BorrowedStatic, OwnedStatic},
- effect::{Effect, Effective, ErasedEffective},
+ effect::{Effect, Effective, EffectiveExt as _, ErasedEffective},
never::Never,
protocol::{visitor::visit_value, DynVisitor},
WalkerTypes,
@@ -48,9 +48,7 @@ impl<'ctx, T: Send + Sync + 'static, E: Effect> crate::Walker<'ctx, E> for Value
visitor: DynVisitor<'b, 'ctx>,
) -> ErasedEffective<'c, Result<Self::Output, Self::Error>, E> {
// Attempt to visit using the value protocol.
- visit_value::<_, E>(visitor, OwnedStatic(self.0))
- .map(|_| Ok(()))
- .into_erased()
+ visit_value::<_, E>(visitor, OwnedStatic(self.0)).map(|_| Ok(()))
// E::map(
// visit_value::<_, E>(visitor, OwnedStatic(self.0)),
// |_| Ok(()),
diff --git a/tests/builder_struct.rs b/tests/builder_struct.rs
index b3502dd..290676b 100644
--- a/tests/builder_struct.rs
+++ b/tests/builder_struct.rs
@@ -117,7 +117,6 @@ impl<'ctx, M, E: Effect> builders::core::r#struct::StructTypeInfo<'ctx, M, E> fo
b: builders.b.build().into_future().await.unwrap(),
})
})
- .into_erased()
}
#[inline(always)]
@@ -141,7 +140,6 @@ impl<'ctx, M, E: Effect> builders::core::r#struct::StructTypeInfo<'ctx, M, E> fo
b: Builder::<E>::from_seed(()).into_future().await,
}
})
- .into_erased()
}
}
@@ -308,23 +306,33 @@ pub mod demo {
pub struct X {
pub a: bool,
pub b: bool,
+ pub c: bool,
}
- #[derive(Build!, Debug)]
+ #[derive(Build!, Debug, PartialEq)]
pub struct Y {
pub b: bool,
pub a: bool,
+ pub c: bool,
}
#[no_mangle]
+ #[inline(never)]
pub fn ident(x: X) -> Y {
- let other = transform::<<Y as crate::Build<'_, DefaultMode, _>>::Builder, _, Blocking<Spin>>(
- ((), ()),
- Walk::<DefaultMode, _>::into_walker(&x),
- );
+ let other =
+ transform::<<Y as crate::Build<'_, DefaultMode, _>>::Builder, _, Blocking<Spin>>(
+ ((), (), ()),
+ Walk::<DefaultMode, _>::into_walker(&x),
+ )
+ .value();
- let other = Spin::block_on(other.into_future());
+ // let other = Spin::block_on(other.into_future());
other.0.unwrap()
}
+
+ #[test]
+ fn demo() {
+ assert_eq!(ident(X { a: true, b: false, c: true }), Y { a: true, b: false, c: true });
+ }
}
diff --git a/tests/common/builder.rs b/tests/common/builder.rs
index a40e8fa..35bc8a8 100644
--- a/tests/common/builder.rs
+++ b/tests/common/builder.rs
@@ -53,14 +53,14 @@ impl<'ctx, Seed: Send + Sync, Value: Send + Sync, Error: Send + Sync, E: Effect>
where
Self: 'a,
{
- E::ready(Self::from_seed(seed)).into_erased()
+ E::ready(Self::from_seed(seed))
}
fn build<'a>(self) -> ErasedEffective<'a, Result<Self::Value, Self::Error>, E>
where
Self: 'a,
{
- E::ready(self.build()).into_erased()
+ E::ready(self.build())
}
fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> {
diff --git a/tests/common/protocol/hint.rs b/tests/common/protocol/hint.rs
index 5809380..ec94277 100644
--- a/tests/common/protocol/hint.rs
+++ b/tests/common/protocol/hint.rs
@@ -33,13 +33,13 @@ impl<'ctx, P: HintMeta> Hint<'ctx, P> for MockHintWalker<P> {
visitor: DynVisitor<'a, 'ctx>,
hint: MetaHint<'a, 'ctx, P>,
) -> ErasedEffective<'a, Flow, P::Effect> {
- P::Effect::ready(self.hint(visitor, hint)).into_erased()
+ P::Effect::ready(self.hint(visitor, hint))
}
fn known<'a>(
&'a mut self,
hint: &'a MetaHint<'a, 'ctx, P>,
) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, P>, ()>, P::Effect> {
- P::Effect::ready(Self::known(self)(&(), hint)).into_erased()
+ P::Effect::ready(Self::known(self)(&(), hint))
}
}
diff --git a/tests/common/protocol/recoverable.rs b/tests/common/protocol/recoverable.rs
index 47c6d21..1ccce92 100644
--- a/tests/common/protocol/recoverable.rs
+++ b/tests/common/protocol/recoverable.rs
@@ -40,7 +40,7 @@ impl<'ctx, E: Effect> Recoverable<'ctx, E> for MockRecoverableVisitor<E> {
&'a mut self,
scope: DynRecoverableScope<'a, 'ctx, E>,
) -> ErasedEffective<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> {
- E::ready(self.visit()(&(), scope)).into_erased()
+ E::ready(self.visit()(&(), scope))
}
}
@@ -55,6 +55,6 @@ impl<'ctx, E: Effect> RecoverableScope<'ctx, E> for MockRecoverableScopeVisitor<
&'a mut self,
visitor: DynVisitor<'b, 'ctx>,
) -> ErasedEffective<'c, Status, E> {
- E::ready(self.new_walk(visitor)).into_erased()
+ E::ready(self.new_walk(visitor))
}
}
diff --git a/tests/common/protocol/request_hint.rs b/tests/common/protocol/request_hint.rs
index 012ca99..dc57b5e 100644
--- a/tests/common/protocol/request_hint.rs
+++ b/tests/common/protocol/request_hint.rs
@@ -28,6 +28,6 @@ impl<'ctx, E: Effect> RequestHint<'ctx, E> for MockRequestHintVisitor<E> {
&'a mut self,
walker: DynWalker<'a, 'ctx>,
) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
- E::ready(self.request_hint()(&(), walker)).into_erased()
+ E::ready(self.request_hint()(&(), walker))
}
}
diff --git a/tests/common/protocol/sequence.rs b/tests/common/protocol/sequence.rs
index 9b3f6b2..c7e68b1 100644
--- a/tests/common/protocol/sequence.rs
+++ b/tests/common/protocol/sequence.rs
@@ -32,27 +32,30 @@ any_trait! {
}
impl<'ctx, E: Effect> Sequence<'ctx, E> for MockSequenceVisitor<E> {
- fn visit<'a>(
+ fn visit<'a: 'c, 'b: 'c, 'c>(
&'a mut self,
- scope: DynSequenceScope<'a, 'ctx, E>,
- ) -> ErasedEffective<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> {
- E::ready(self.visit()(&(), scope)).into_erased()
+ scope: DynSequenceScope<'b, 'ctx, E>,
+ ) -> ErasedEffective<'c, VisitResult<DynSequenceScope<'b, 'ctx, E>>, E> {
+ E::ready(self.visit()(&(), scope))
}
}
mock! {
pub SequenceScope<E> {
pub fn size_hint(&mut self) -> (usize, Option<usize>);
- pub fn next<'a, 'ctx>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Flow;
+ pub fn next<'a, 'b, 'ctx>(&'a mut self, visitor: DynVisitor<'b, 'ctx>) -> Flow;
}
}
impl<'ctx, E: Effect> SequenceScope<'ctx, E> for MockSequenceScope<E> {
fn size_hint(&mut self) -> ErasedEffective<'_, (usize, Option<usize>), E> {
- E::ready(self.size_hint()).into_erased()
+ E::ready(self.size_hint())
}
- fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> ErasedEffective<'a, Flow, E> {
- E::ready(self.next(visitor)).into_erased()
+ fn next<'a: 'c, 'b: 'c, 'c>(
+ &'a mut self,
+ visitor: DynVisitor<'b, 'ctx>,
+ ) -> ErasedEffective<'c, Flow, E> {
+ E::ready(self.next(visitor))
}
}
diff --git a/tests/common/protocol/tag.rs b/tests/common/protocol/tag.rs
index 9d2f98a..2dcd805 100644
--- a/tests/common/protocol/tag.rs
+++ b/tests/common/protocol/tag.rs
@@ -30,6 +30,5 @@ impl<'ctx, K: TagKind, E: Effect> Tag<'ctx, K, E> for MockTagVisitor<K, E> {
VisitResult::Skipped(_) => VisitResult::Skipped(walker),
VisitResult::Control(flow) => VisitResult::Control(flow),
})
- .into_erased()
}
}
diff --git a/tests/common/protocol/visitor.rs b/tests/common/protocol/visitor.rs
index fdc9921..b0f2273 100644
--- a/tests/common/protocol/visitor.rs
+++ b/tests/common/protocol/visitor.rs
@@ -40,6 +40,5 @@ where
VisitResult::Skipped(_) => VisitResult::Skipped(value),
VisitResult::Control(flow) => VisitResult::Control(flow),
})
- .into_erased()
}
}
diff --git a/tests/common/walker.rs b/tests/common/walker.rs
index e4e879e..5ba0ef8 100644
--- a/tests/common/walker.rs
+++ b/tests/common/walker.rs
@@ -31,7 +31,7 @@ impl<'ctx, Output: Send + Sync, Error: Send + Sync, E: Effect> Walker<'ctx, E>
where
Self: 'c,
{
- E::ready(self.walk(visitor)).into_erased()
+ E::ready(self.walk(visitor))
}
}
diff --git a/tests/protocol_visitor_recoverable.rs b/tests/protocol_visitor_recoverable.rs
index a0a0b95..cde5ca1 100644
--- a/tests/protocol_visitor_recoverable.rs
+++ b/tests/protocol_visitor_recoverable.rs
@@ -6,7 +6,7 @@ use treaty::{
visitor::{Recoverable, ValueProto, VisitResult},
DynVisitor,
},
- Flow,
+ Flow, Status,
};
use crate::common::{
@@ -30,10 +30,10 @@ fn recoverable_can_be_visited() {
visitor.expect_traits().times(2).return_const(None);
// Attempt to walk once.
- assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Ok(()));
+ assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Status::Ok);
// Attempt to walk twice.
- assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Ok(()));
+ assert_eq!(scope.new_walk(DynVisitor(&mut visitor)).value(), Status::Ok);
// We are done.
VisitResult::Control(Flow::Done)
@@ -51,7 +51,7 @@ fn recoverable_can_be_visited() {
.upcast::<ValueProto<OwnedStatic<i32>, Blocking>>()
.is_none());
- Ok(())
+ Status::Ok
});
// Visit using the recoverable protocol.
diff --git a/tests/walker_struct.rs b/tests/walker_struct.rs
index 4ff61d1..381b6c1 100644
--- a/tests/walker_struct.rs
+++ b/tests/walker_struct.rs
@@ -81,7 +81,6 @@ impl<'ctx, M> StructTypeInfo<'ctx, M> for Info {
_ => Ok(Flow::Done),
}
})
- .into_erased()
}
}