Diffstat (limited to 'src/effect.rs')
-rw-r--r--src/effect.rs323
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(()))