added extension trait for effectives
| -rw-r--r-- | src/build/builders/core/struct.rs | 38 | ||||
| -rw-r--r-- | src/effect.rs | 323 | ||||
| -rw-r--r-- | src/effect/async.rs | 2 | ||||
| -rw-r--r-- | src/effect/blocking.rs | 98 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 91 | ||||
| -rw-r--r-- | src/transform.rs | 10 | ||||
| -rw-r--r-- | src/walk.rs | 44 | ||||
| -rw-r--r-- | src/walk/walkers/core/key_value.rs | 26 | ||||
| -rw-r--r-- | src/walk/walkers/core/struct.rs | 151 | ||||
| -rw-r--r-- | tests/builder_struct.rs | 2 |
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, |