Diffstat (limited to 'src/effect.rs')
| -rw-r--r-- | src/effect.rs | 323 |
1 files changed, 233 insertions, 90 deletions
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(())) |