added extension trait for effectives
Konnor Andrews 2024-05-31
parent c59d580 · commit 99aeb03
-rw-r--r--src/build/builders/core/struct.rs38
-rw-r--r--src/effect.rs323
-rw-r--r--src/effect/async.rs2
-rw-r--r--src/effect/blocking.rs98
-rw-r--r--src/protocol/visitor/tag.rs91
-rw-r--r--src/transform.rs10
-rw-r--r--src/walk.rs44
-rw-r--r--src/walk/walkers/core/key_value.rs26
-rw-r--r--src/walk/walkers/core/struct.rs151
-rw-r--r--tests/builder_struct.rs2
10 files changed, 501 insertions, 284 deletions
diff --git a/src/build/builders/core/struct.rs b/src/build/builders/core/struct.rs
index d1889b3..b3983ab 100644
--- a/src/build/builders/core/struct.rs
+++ b/src/build/builders/core/struct.rs
@@ -3,7 +3,7 @@ use core::{marker::PhantomData, ops::ControlFlow};
use crate::{
any::{OwnedStatic, TempBorrowedStatic, TempBorrowedStaticHrt, TypeName},
any_trait,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
hkt::Marker,
protocol::{
visitor::{
@@ -145,12 +145,16 @@ where
self.mode = StructMode::Map;
E::ready(NoopVisitor::new())
- .as_ctx(|noop| {
- walker
- .walk(DynVisitor(noop))
- .map(|x| x.to_continue().into())
- .into_erased()
- })
+ .as_ctx(
+ all_ctx,
+ |noop, _| {
+ walker
+ .walk(DynVisitor(noop))
+ .map(|x| x.to_continue().into())
+ .into_erased()
+ },
+ merge_ctx,
+ )
.map(|(_, value)| value)
.into_erased()
}
@@ -211,11 +215,15 @@ where
};
E::ready((scope, visitor))
- .as_ctx(|(scope, visitor)| {
- let scope: &mut DynSequenceScope<'_, '_, _> = scope;
-
- scope.next(DynVisitor(visitor)).into_erased()
- })
+ .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)),
@@ -269,7 +277,11 @@ where
};
E::ready((self, visitor, walker))
- .as_ctx(|(_, visitor, walker)| walker.walk(DynVisitor(visitor)).into_erased())
+ .as_ctx(
+ all_ctx,
+ |(_, visitor, walker), _| walker.walk(DynVisitor(visitor)).into_erased(),
+ merge_ctx,
+ )
.map(|((this, visitor, _), flow)| {
this.marker = visitor.field_marker;
flow.to_continue().into()
diff --git a/src/effect.rs b/src/effect.rs
index 87cee7e..0f85ee3 100644
--- a/src/effect.rs
+++ b/src/effect.rs
@@ -1,9 +1,9 @@
-pub mod r#async;
+// pub mod r#async;
pub mod blocking;
use core::{future::Future, ops::ControlFlow};
-use crate::{higher_ranked_trait, higher_ranked_type};
+use crate::{higher_ranked_trait, higher_ranked_type, hkt::Marker};
// 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.
@@ -42,40 +42,225 @@ pub trait Ss: Send + Sync {}
impl<T: Send + Sync> Ss for T {}
-pub trait Effect: Join<Effect = Self> + TryJoin<Effect = Self> + Ss + Sized + 'static {
- type Erased<T: Ss>: ErasedHrt<T, Self>;
+/// Type class for type erased higher-ranked effective types.
+#[allow(non_snake_case)]
+mod Erased {
+ use super::*;
+
+ /// For all lifetimes `'lt`.
+ ///
+ /// You should never need to interact with this trait directly.
+ /// Instead use the [`ErasedEffective`] type alias.
+ ///
+ /// The `Output` generic type is what the effective will output.
+ /// The `E` generic type is the effect this effective is for.
+ /// The `Bound` generic is for higher-ranked implied bounds.
+ /// See TODO for more info.
+ pub trait ForLt<'lt, Output: Ss + 'lt, E: Effect, Bound: 'lt> {
+ /// The effective type with the lifetime `'lt` given.
+ type Effective: Effective<'lt, Output = Output, Effect = E>;
+ }
+
+ /// A type class for higher-ranked types with an effective concrete type.
+ ///
+ /// You should never need to interact with this trait directly.
+ /// Instead use the [`ErasedEffective`] type alias.
+ ///
+ /// The `Output` generic type is what the effective will output.
+ /// The `E` generic type is the effect this effective is for.
+ pub trait Hkt<Output: Ss, E: Effect> {
+ /// Accessor to inject arbitrary higher-ranked implied bounds.
+ /// See TODO for more info.
+ type Hrt<Bound>: for<'a> ForLt<'a, Output, E, &'a (Output, Bound)>;
+ }
+}
- type Ready<'a, T: Ss + 'a>: Effective<'a, Output = T, Effect = Self>;
+/// Type alias to get the concrete [`Effect::Erased`] type.
+///
+/// The `'lt` lifetime is the minimum lifetime of the returned effective.
+/// `Output` is the output type of the effective.
+/// `E` is the effect to pull the [`Effect::Erased`] from.
+///
+/// The `Bound` generic shouldn't be needed or used in most code.
+/// It is only needed for adding higher-ranked implied bounds.
+/// See TODO for details.
+#[rustfmt::skip]
+pub type ErasedEffective<'lt, Output, E, Bound = ()> = <
+ <
+ <E as Effect>::Erased<Output>
+ as
+ Erased::Hkt<Output, E>
+ >::Hrt<Bound>
+ as
+ Erased::ForLt<'lt, Output, E, &'lt (Output, Bound)>
+ >::Effective;
- fn ready<'a, T: Ss + 'a>(value: T) -> Self::Ready<'a, T>;
+pub trait Effect: Join<Effect = Self> + TryJoin<Effect = Self> + Ss + Sized + 'static {
+ type Erased<T: Ss>: Erased::Hkt<T, Self>;
- type FromFuture<'a, F: Ss + 'a>: Effective<'a, Output = F::Output, Effect = Self>
+ fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self>;
+
+ fn from_future<'a, F: Ss + 'a>(future: F) -> ErasedEffective<'a, F::Output, Self>
where
F: Future,
F::Output: Ss + 'a;
+}
- fn from_future<'a, F: Ss + 'a>(future: F) -> Self::FromFuture<'a, F>
+pub fn all_ctx<T>(x: T) -> (T, ()) {
+ (x, ())
+}
+
+pub fn merge_ctx<C, T>(ctx: C, x: T) -> (C, T) {
+ (ctx, x)
+}
+
+pub trait ShortCircuit {
+ type Normal: Ss;
+
+ type Short: Ss;
+
+ type NormalWith<T: Ss>: ShortCircuit<Normal = T, Short = Self::Short> + Ss;
+
+ fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R>
where
- F: Future,
- F::Output: Ss + 'a;
+ F: FnOnce(Self::Normal) -> R;
+
+ fn or_else<F>(self, f: F) -> Self
+ where
+ F: FnOnce(Self::Short) -> Self;
}
-pub trait ErasedForLt<'a, T: Ss + 'a, E: Effect, Bound: 'a, O: 'a> {
- type T: Effective<'a, Output = T, Effect = E>;
+impl<T: Ss> ShortCircuit for Option<T> {
+ type Normal = T;
+
+ type Short = ();
+
+ type NormalWith<U: Ss> = Option<U>;
+
+ fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R>
+ where
+ F: FnOnce(Self::Normal) -> R,
+ {
+ Option::map(self, f)
+ }
+
+ fn or_else<F>(self, f: F) -> Self
+ where
+ F: FnOnce(Self::Short) -> Self,
+ {
+ Option::or_else(self, || f(()))
+ }
}
-pub trait ErasedHrt<T: Ss, E: Effect> {
- type T<B>: for<'a> ErasedForLt<'a, T, E, &'a (T, B), B>;
+impl<T: Ss, E: Ss> ShortCircuit for Result<T, E> {
+ type Normal = T;
+
+ type Short = E;
+
+ type NormalWith<U: Ss> = Result<U, E>;
+
+ fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R>
+ where
+ F: FnOnce(Self::Normal) -> R,
+ {
+ Result::map(self, f)
+ }
+
+ fn or_else<F>(self, f: F) -> Self
+ where
+ F: FnOnce(Self::Short) -> Self,
+ {
+ Result::or_else(self, f)
+ }
}
-pub type ErasedEffective<'lt, Output, E, B = ()> =
- <<<E as Effect>::Erased<Output> as ErasedHrt<Output, E>>::T<B> as ErasedForLt<
- 'lt,
- Output,
- E,
- &'lt (Output, B),
- B,
- >>::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>
+ where
+ F: FnOnce(<Self::Output as ShortCircuit>::Normal) -> R,
+ Self::Output: ShortCircuit,
+ 'lt: 'wrap;
+
+ fn or_else<'wrap, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Self::Output, Self::Effect>
+ where
+ F: FnOnce(<Self::Output as ShortCircuit>::Short) -> Self::Output,
+ Self::Output: ShortCircuit,
+ 'lt: 'wrap;
+
+ fn demo(self)
+ where
+ Self: Effective<'lt, Output = (i32, i32)>;
+
+ fn as_ctx_or_else<'ctx: 'lt, 'wrap, T: Ss, U: Ss, F: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, (T, 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;
+}
+
+impl<'lt, T: Effective<'lt>> EffectiveExt<'lt> for T {
+ fn map_normal<'wrap, F: Ss, R: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, <Self::Output as ShortCircuit>::NormalWith<R>, Self::Effect>
+ where
+ F: FnOnce(<Self::Output as ShortCircuit>::Normal) -> R,
+ Self::Output: ShortCircuit,
+ 'lt: 'wrap,
+ {
+ self.map(move |value| value.map(f))
+ }
+
+ fn or_else<'wrap, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Self::Output, Self::Effect>
+ where
+ F: FnOnce(<Self::Output as ShortCircuit>::Short) -> Self::Output,
+ Self::Output: ShortCircuit,
+ 'lt: 'wrap,
+ {
+ self.map(move |value| value.or_else(f))
+ }
+
+ fn demo(self)
+ where
+ Self: Effective<'lt, Output = (i32, i32)>,
+ {
+ self.map(|(a, b)| a + b);
+ }
+
+ fn as_ctx_or_else<'ctx: 'lt, 'wrap, N: Ss, U: Ss, F: Ss>(
+ self,
+ f: F,
+ ) -> ErasedEffective<'wrap, (N, 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 ()>,
+ '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!(),
+ },
+ )
+ }
+}
pub trait Effective<'lt>: Ss + 'lt {
fn into_erased<B>(self) -> ErasedEffective<'lt, Self::Output, Self::Effect, B>;
@@ -92,79 +277,37 @@ pub trait Effective<'lt>: Ss + 'lt {
/// Convert the effective into a general future for use in async.
fn into_future(self) -> Self::IntoFuture;
- type Loop<'ctx: 'a, 'a, T: Ss + 'a, F: Ss + 'a>: Effective<
- 'a,
- Output = (Self::Output, T),
- Effect = Self::Effect,
- >
- where
- F: for<'b> FnMut(
- &'b mut Self::Output,
- ) -> ErasedEffective<
- 'b,
- ControlFlow<T>,
- Self::Effect,
- (&'b mut Self::Output, &'ctx ()),
- >,
- 'lt: 'a;
-
- fn r#loop<'ctx: 'a, 'a, T: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::Loop<'ctx, 'a, T, F>
- where
- F: for<'b> FnMut(
- &'b mut Self::Output,
- ) -> ErasedEffective<
- 'b,
- ControlFlow<T>,
- Self::Effect,
- (&'b mut Self::Output, &'ctx ()),
- >,
- 'lt: 'a;
-
- type Map<'a, T: Ss + 'a, F: Ss + 'a>: Effective<'a, Output = T, Effect = Self::Effect>
- where
- F: FnOnce(Self::Output) -> T,
- 'lt: 'a;
-
- fn map<'a, T: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::Map<'a, T, F>
+ fn map<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect>
where
F: FnOnce(Self::Output) -> T,
- 'lt: 'a;
-
- type Then<'a, T: Ss + 'a, V: Ss + 'a, F: Ss + 'a>: Effective<
- 'a,
- Output = T,
- Effect = Self::Effect,
- >
- where
- F: FnOnce(Self::Output) -> V,
- V: Effective<'a, Output = T, Effect = Self::Effect>,
- 'lt: 'a;
+ 'lt: 'wrap;
- fn then<'a, T: Ss + 'a, V: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::Then<'a, T, V, F>
+ fn then<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect>
where
- F: FnOnce(Self::Output) -> V,
- V: Effective<'a, Output = T, Effect = Self::Effect>,
- 'lt: 'a;
-
- type AsCtx<'ctx: 'a, 'a, T: Ss + 'a, F: Ss + 'a>: Effective<
- 'a,
- Output = (Self::Output, T),
- Effect = Self::Effect,
- >
+ 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
- F: for<'b> FnOnce(
- &'b mut Self::Output,
- )
- -> ErasedEffective<'b, T, Self::Effect, (&'b mut Self::Output, &'ctx ())>,
- 'lt: 'a;
-
- fn as_ctx<'ctx: 'a, 'a, T: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::AsCtx<'ctx, 'a, T, F>
+ 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>(
+ self,
+ cb: F,
+ ) -> ErasedEffective<'wrap, (Self::Output, T), Self::Effect>
where
- F: for<'b> FnOnce(
+ F: for<'b> FnMut(
&'b mut Self::Output,
- )
- -> ErasedEffective<'b, T, Self::Effect, (&'b mut Self::Output, &'ctx ())>,
- 'lt: 'a;
+ ) -> ErasedEffective<'b, ControlFlow<T>, Self::Effect, &'ctx ()>,
+ 'lt: 'wrap;
}
pub trait TryEffective<'lt>: Effective<'lt, Output = Result<Self::Ok, Self::Err>> {
@@ -273,7 +416,7 @@ pub trait Joinable<'lt, E: Effect> {
}
impl<'lt, E: Effect> Joinable<'lt, E> for () {
- type Output = E::Ready<'lt, ()>;
+ type Output = ErasedEffective<'lt, (), E>;
fn join(self) -> Self::Output {
E::ready(())
@@ -327,7 +470,7 @@ pub trait TryJoinable<'lt, E: Effect> {
}
impl<'lt, E: Effect> TryJoinable<'lt, E> for () {
- type Output = E::Ready<'lt, Result<(), ()>>;
+ type Output = ErasedEffective<'lt, Result<(), ()>, E>;
fn join(self) -> Self::Output {
E::ready(Ok(()))
diff --git a/src/effect/async.rs b/src/effect/async.rs
index effcd08..1c0eb9d 100644
--- a/src/effect/async.rs
+++ b/src/effect/async.rs
@@ -40,7 +40,7 @@ pub enum BoxOrReady<'a, T> {
pub type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + Sync + 'a>>;
-impl<'a, T: Ss, O> ErasedForLt<'a, T, Async, &'a (T, O), O> for ErasedHrt<T> {
+impl<'a, T: Ss, O> ErasedForLt<'a, T, Async, &'a (T, O)> for ErasedHrt<T> {
type T = BoxOrReady<'a, T>;
}
diff --git a/src/effect/blocking.rs b/src/effect/blocking.rs
index 5913dda..11c3b7d 100644
--- a/src/effect/blocking.rs
+++ b/src/effect/blocking.rs
@@ -24,29 +24,29 @@ impl<T, B> Value<T, B> {
}
}
-impl<'lt, T: Ss, B: BlockOn, O> ErasedForLt<'lt, T, Blocking<B>, &'lt (T, O), O> for Value<T, B> {
- type T = Value<T, B>;
+impl<'lt, T: Ss, B: BlockOn, O> Erased::ForLt<'lt, T, Blocking<B>, &'lt (T, O)> for Value<T, B> {
+ type Effective = Value<T, B>;
}
-impl<T: Ss, B: BlockOn> ErasedHrt<T, Blocking<B>> for Value<T, B> {
- type T<O> = Self;
+impl<T: Ss, B: BlockOn> Erased::Hkt<T, Blocking<B>> for Value<T, B> {
+ type Hrt<O> = Self;
}
impl<B: BlockOn> Effect for Blocking<B> {
type Erased<T: Ss> = Value<T, B>;
- type Ready<'a, T: Ss + 'a> = Value<T, B>;
+ // type Ready<'a, T: Ss + 'a> = Value<T, B>;
- fn ready<'a, T: Ss + 'a>(value: T) -> Self::Ready<'a, T> {
+ 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;
+ // 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) -> Self::FromFuture<'a, F>
+ fn from_future<'a, F: Ss + 'a>(future: F) -> ErasedEffective<'a, F::Output, Self>
where
F: Future,
F::Output: Ss + 'a,
@@ -70,16 +70,18 @@ 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;
+ // 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: 'a, 'a, T: Ss + 'a, F: Ss + 'a>(self, mut cb: F) -> Self::Loop<'ctx, 'a, T, F>
+ fn r#loop<'ctx: 'lt, 'wrap, T: Ss, F: Ss>(
+ self,
+ mut cb: F,
+ ) -> ErasedEffective<'wrap, (Self::Output, T), Self::Effect>
where
F: for<'b> FnMut(&'b mut Self::Output) -> ErasedEffective<'b, ControlFlow<T>, Self::Effect>,
- 'lt: 'a,
{
let mut this = self.0;
@@ -90,50 +92,52 @@ impl<'lt, U: Ss + 'lt, B: BlockOn> Effective<'lt> for Value<U, B> {
}
}
- type Map<'a, T: Ss + 'a, F: Ss + 'a> = Value<T, B>
- where
- F: FnOnce(Self::Output) -> T,
- 'lt: 'a;
+ // type Map<'a, T: Ss + 'a, F: Ss + 'a> = Value<T, B>
+ // where
+ // F: FnOnce(Self::Output) -> T,
+ // 'lt: 'a;
- fn map<'a, T: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::Map<'a, T, F>
+ fn map<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect>
where
F: FnOnce(Self::Output) -> T,
- 'lt: 'a,
+ '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;
+ // 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;
- fn then<'a, T: Ss + 'a, V: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::Then<'a, T, V, F>
+ fn then<'a, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'a, T, Self::Effect>
where
- F: FnOnce(Self::Output) -> V,
- V: Effective<'a, Output = T, Effect = Self::Effect>,
+ F: FnOnce(Self::Output) -> ErasedEffective<'a, T, Self::Effect>,
'lt: 'a,
{
cb(self.0).into_erased::<()>()
}
- 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: 'a, 'a, T: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::AsCtx<'ctx, 'a, T, F>
- where
- F: for<'b> FnOnce(
- &'b mut Self::Output,
- )
- -> ErasedEffective<'b, T, Self::Effect, (&'b mut Self::Output, &'ctx ())>,
- 'lt: 'a,
+ // 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 = self.0;
- let result = cb(&mut this).0;
- Value((this, result), Default::default())
+ let (mut this, owned) = split(self.0);
+ let result = cb(&mut this, owned).0;
+ Value(after(this, result), Default::default())
}
}
diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs
index 2c13785..5053bd0 100644
--- a/src/protocol/visitor/tag.rs
+++ b/src/protocol/visitor/tag.rs
@@ -1,6 +1,6 @@
use crate::{
any::TypeName,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
higher_ranked_type,
hkt::Marker,
protocol::{
@@ -167,7 +167,7 @@ impl<E> TagError<E> {
#[inline(always)]
pub fn visit_tag<'a, 'ctx: 'a, K: TagKind, E: Effect, W: crate::Walker<'ctx, E> + 'a>(
kind: K,
- mut visitor: DynVisitor<'a, 'ctx>,
+ visitor: DynVisitor<'a, 'ctx>,
walker: W,
) -> ErasedEffective<'a, Result<VisitResult<W>, TagError<W::Error>>, E>
where
@@ -177,45 +177,62 @@ where
let walker = DynWalkerAdapter::new(walker);
E::ready((kind, visitor, walker))
- .as_ctx(|(kind, visitor, walker)| {
- let object = visitor.upcast_mut::<TagProto<K, E>>();
-
- E::ready((*kind, object, walker))
- .as_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(),
- })
- .map(|((_, _, _), value)| value)
- .into_erased()
- })
- .as_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>>();
+ .as_ctx(
+ all_ctx,
+ |(kind, visitor, walker), _| {
+ let object = visitor.upcast_mut::<TagProto<K, E>>();
E::ready((*kind, object, walker))
- .as_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(),
- })
+ .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)),
diff --git a/src/transform.rs b/src/transform.rs
index bd358bf..65b9887 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -2,9 +2,9 @@ use core::marker::PhantomData;
use crate::{
build::Builder,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{all_ctx, merge_ctx, Effect, Effective, EffectiveExt, ErasedEffective},
hkt::Marker,
- Walk, Walker, WalkerTypes,
+ BuilderTypes, Walk, Walker, WalkerTypes,
};
#[inline(always)]
@@ -14,7 +14,11 @@ 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(|builder| walker.walk(builder.as_visitor()).into_erased())
+ .as_ctx(
+ all_ctx,
+ |builder, _| walker.walk(builder.as_visitor()).into_erased(),
+ merge_ctx,
+ )
.then(|(builder, walker_result)| {
builder
.build()
diff --git a/src/walk.rs b/src/walk.rs
index 159e9ea..9f4a828 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -1,7 +1,7 @@
pub mod walkers;
use crate::{
- effect::{Effect, Effective, ErasedEffective},
+ effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
protocol::DynVisitor,
Flow,
};
@@ -121,25 +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(|(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()
- })
+ .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,
+ )
.map(|(_, value)| value)
.into_erased()
} else {
diff --git a/src/walk/walkers/core/key_value.rs b/src/walk/walkers/core/key_value.rs
index 731bb79..3c0f700 100644
--- a/src/walk/walkers/core/key_value.rs
+++ b/src/walk/walkers/core/key_value.rs
@@ -1,7 +1,7 @@
use core::marker::PhantomData;
use crate::{
- effect::{Effect, Effective, ErasedEffective},
+ effect::{all_ctx, merge_ctx, Effect, Effective, ErasedEffective},
never::Never,
protocol::{
visitor::{visit_tag, TagConst, TagError, TagKind, VisitResult},
@@ -59,18 +59,22 @@ where
#[inline(always)]
fn walk<'b: 'c, 'c>(
self,
- mut visitor: DynVisitor<'b, 'ctx>,
+ visitor: DynVisitor<'b, 'ctx>,
) -> ErasedEffective<'c, Result<Self::Output, Self::Error>, E> {
E::ready(visitor)
- .as_ctx(move |visitor| {
- self.value_walker
- .walk(visitor.cast())
- .map(|result| match result {
- Ok(_) => Ok::<_, Self::Error>(()),
- Err(_err) => todo!(),
- })
- .into_erased()
- })
+ .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()
diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs
index 88b597c..82e399d 100644
--- a/src/walk/walkers/core/struct.rs
+++ b/src/walk/walkers/core/struct.rs
@@ -3,7 +3,7 @@ use core::{any::TypeId, marker::PhantomData};
use crate::{
any::{AnyTrait, BorrowedStatic, BorrowedStaticHrt},
any_trait,
- effect::{Effect, Effective, ErasedEffective},
+ effect::{all_ctx, merge_ctx, Effect, Effective, EffectiveExt, ErasedEffective},
hkt::Marker,
never::Never,
protocol::{
@@ -13,8 +13,7 @@ use crate::{
SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown,
ValueProto, VisitResult,
},
- walker::hint::{Hint, MetaKnown},
- walker::hint::{HintMeta, HintProto, MetaHint},
+ walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown},
DynVisitor, DynWalker,
},
Flow, Status, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, TAG_TYPE_NAME,
@@ -131,11 +130,13 @@ where
{
E::ready((self, visitor))
.as_ctx(
+ all_ctx,
#[inline(always)]
- |(this, visitor)| {
+ |(this, visitor), _| {
RecoverableScope::<'ctx, E>::new_walk::<'_, '_, '_>(this, visitor.cast())
.into_erased()
},
+ merge_ctx,
)
.map(|((this, _), _)| match this.error {
Some(err) => Err(StructWalkError { kind: err }),
@@ -627,80 +628,108 @@ where
self.index = 0;
E::ready((self, visitor))
- .as_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()
- })
- .as_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()
- }
- })
- .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(|((this, visitor), result)| {
- if result.is_some() {
- E::ready(None).into_erased()
- } else {
- visit_value::<_, E>(visitor.cast(), BorrowedStatic(this.value))
+ .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,
+ )
+ .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(|((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(|((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>()),
- )
+ .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 {
- 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(())),
+ 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),
})
- .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,
diff --git a/tests/builder_struct.rs b/tests/builder_struct.rs
index c45a78f..b3502dd 100644
--- a/tests/builder_struct.rs
+++ b/tests/builder_struct.rs
@@ -298,7 +298,7 @@ pub mod demo {
use treaty::{
effect::{
blocking::{BlockOn, Blocking, Spin},
- r#async::Async,
+ // r#async::Async,
Effective as _,
},
transform, Build, DefaultMode,