pub mod r#async;
pub mod blocking;
use core::{future::Future, ops::ControlFlow};
use crate::{higher_ranked_trait, higher_ranked_type};
// 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.
//
// Escaping the effect wrapper requires knowing the concrete context or transforming in the more
// general form which is a Future.
// Async operations cannot be made blocking without issues.
//
// Async and blocking can perform loops. In async the loop will yield between iterations.
// The effective value becomes the loop context. This operation can encode arbitrary folds which
// gives a fully powerful loop construct. The callback effective is allowed to reference the
// context, but the returned value is not.
//
// Async and blocking can perform maps. This is a blocking transform of the value from one form to
// another.
//
// A map that returns an effective for the callback is a then.
//
// The special operation is as_ctx which allows a effective value to be referenced temporarily
// during the operation. This is basically a loop that happens onces.
//
// All effectives can be converted to the effect's erased effective.
//
// An effective can be made from a value.
//
// An effective can be made from a future.
//
// Multiple effectives can be joined together.
//
// E::join((
// || A,
// || B
// ))
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 Ready<'a, T: Ss + 'a>: Effective<'a, Output = T, Effect = Self>;
fn ready<'a, T: Ss + 'a>(value: T) -> Self::Ready<'a, T>;
type FromFuture<'a, F: Ss + 'a>: Effective<'a, Output = F::Output, Effect = Self>
where
F: Future,
F::Output: Ss + 'a;
fn from_future<'a, F: Ss + 'a>(future: F) -> Self::FromFuture<'a, F>
where
F: Future,
F::Output: Ss + 'a;
}
pub trait ErasedForLt<'a, T: Ss + 'a, E: Effect, Bound: 'a, O: 'a> {
type T: Effective<'a, Output = T, Effect = E>;
}
pub trait ErasedHrt<T: Ss, E: Effect> {
type T<B>: for<'a> ErasedForLt<'a, T, E, &'a (T, B), B>;
}
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 Effective<'lt>: Ss + 'lt {
fn into_erased<B>(self) -> ErasedEffective<'lt, Self::Output, Self::Effect, B>;
/// The effect the effective belongs to.
type Effect: Effect;
/// The type of the effective's output value.
type Output: Ss + 'lt;
/// Future that resolves to the same value as the effective.
type IntoFuture: Ss + Future<Output = Self::Output>;
/// 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>
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;
fn then<'a, T: Ss + 'a, V: Ss + 'a, F: Ss + 'a>(self, cb: F) -> Self::Then<'a, T, V, F>
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,
>
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;
}
pub trait TryEffective<'lt>: Effective<'lt, Output = Result<Self::Ok, Self::Err>> {
type Ok: Ss + 'lt;
type Err: Ss + 'lt;
}
impl<'lt, T, Ok, Err> TryEffective<'lt> for T
where
T: Effective<'lt, Output = Result<Ok, Err>>,
Ok: Ss + 'lt,
Err: Ss + 'lt,
{
type Ok = Ok;
type Err = Err;
}
pub trait Join {
type Effect: Effect;
type Two<'a, T0: Ss + 'a, T1: Ss + 'a>: Effective<
'a,
Output = (T0::Output, T1::Output),
Effect = Self::Effect,
>
where
T0: Effective<'a, Effect = Self::Effect>,
T1: Effective<'a, Effect = Self::Effect>;
type Three<'a, T0: Ss + 'a, T1: Ss + 'a, T2: Ss + 'a>: Effective<
'a,
Output = (T0::Output, T1::Output, T2::Output),
Effect = Self::Effect,
>
where
T0: Effective<'a, Effect = Self::Effect>,
T1: Effective<'a, Effect = Self::Effect>,
T2: Effective<'a, Effect = Self::Effect>;
fn two<'a, T0: Ss + 'a, T1: Ss + 'a>(effectives: (T0, T1)) -> Self::Two<'a, T0, T1>
where
T0: Effective<'a, Effect = Self::Effect>,
T1: Effective<'a, Effect = Self::Effect>;
fn three<'a, T0: Ss + 'a, T1: Ss + 'a, T2: Ss + 'a>(
effectives: (T0, T1, T2),
) -> Self::Three<'a, T0, T1, T2>
where
T0: Effective<'a, Effect = Self::Effect>,
T1: Effective<'a, Effect = Self::Effect>,
T2: Effective<'a, Effect = Self::Effect>;
}
pub trait TryJoin {
type Effect: Effect;
type Two<'a, T0: Ss + 'a, T1: Ss + 'a>: Effective<
'a,
Output = Result<(T0::Ok, T1::Ok), T0::Err>,
Effect = Self::Effect,
>
where
T0: TryEffective<'a, Effect = Self::Effect>,
T1: TryEffective<'a, Err = T0::Err, Effect = Self::Effect>;
type Three<'a, T0: Ss + 'a, T1: Ss + 'a, T2: Ss + 'a>: Effective<
'a,
Output = Result<(T0::Ok, T1::Ok, T2::Ok), T0::Err>,
Effect = Self::Effect,
>
where
T0: TryEffective<'a, Effect = Self::Effect>,
T1: TryEffective<'a, Err = T0::Err, Effect = Self::Effect>,
T2: TryEffective<'a, Err = T0::Err, Effect = Self::Effect>;
fn two<'a, T0: Ss + 'a, T1: Ss + 'a, F0: Ss + 'a, F1: Ss + 'a>(
cb: (F0, F1),
) -> Self::Two<'a, T0, T1>
where
T0: TryEffective<'a, Effect = Self::Effect>,
T1: TryEffective<'a, Err = T0::Err, Effect = Self::Effect>,
F0: FnOnce() -> T0,
F1: FnOnce() -> T1;
fn three<'a, T0: Ss + 'a, T1: Ss + 'a, T2: Ss + 'a, F0: Ss + 'a, F1: Ss + 'a, F2: Ss + 'a>(
cb: (F0, F1, F2),
) -> Self::Three<'a, T0, T1, T2>
where
T0: TryEffective<'a, Effect = Self::Effect>,
T1: TryEffective<'a, Err = T0::Err, Effect = Self::Effect>,
T2: TryEffective<'a, Err = T0::Err, Effect = Self::Effect>,
F0: FnOnce() -> T0,
F1: FnOnce() -> T1,
F2: FnOnce() -> T2;
}
pub fn join<'lt, E: Effect, T: Joinable<'lt, E>>(x: T) -> T::Output {
x.join()
}
pub trait Joinable<'lt, E: Effect> {
type Output: Effective<'lt, Effect = E>;
fn join(self) -> Self::Output;
}
impl<'lt, E: Effect> Joinable<'lt, E> for () {
type Output = E::Ready<'lt, ()>;
fn join(self) -> Self::Output {
E::ready(())
}
}
impl<'lt, E: Effect, T0> Joinable<'lt, E> for (T0,)
where
T0: Effective<'lt, Effect = E>,
{
type Output = T0;
fn join(self) -> Self::Output {
self.0
}
}
impl<'lt, E: Effect, T0, T1> Joinable<'lt, E> for (T0, T1)
where
T0: Effective<'lt, Effect = E>,
T1: Effective<'lt, Effect = E>,
{
type Output = <E as Join>::Two<'lt, T0, T1>;
fn join(self) -> Self::Output {
<E as Join>::two(self)
}
}
impl<'lt, E: Effect, T0, T1, T2> Joinable<'lt, E> for (T0, T1, T2)
where
T0: Effective<'lt, Effect = E>,
T1: Effective<'lt, Effect = E>,
T2: Effective<'lt, Effect = E>,
{
type Output = <E as Join>::Three<'lt, T0, T1, T2>;
fn join(self) -> Self::Output {
<E as Join>::three(self)
}
}
pub fn try_join<'lt, E: Effect, T: TryJoinable<'lt, E>>(x: T) -> T::Output {
x.join()
}
pub trait TryJoinable<'lt, E: Effect> {
type Output: TryEffective<'lt, Effect = E>;
fn join(self) -> Self::Output;
}
impl<'lt, E: Effect> TryJoinable<'lt, E> for () {
type Output = E::Ready<'lt, Result<(), ()>>;
fn join(self) -> Self::Output {
E::ready(Ok(()))
}
}
impl<'lt, E: Effect, F0, T0> TryJoinable<'lt, E> for (F0,)
where
F0: FnOnce() -> T0,
T0: TryEffective<'lt, Effect = E>,
{
type Output = T0;
fn join(self) -> Self::Output {
self.0()
}
}
impl<'lt, E: Effect, F0, F1, T0, T1> TryJoinable<'lt, E> for (F0, F1)
where
F0: FnOnce() -> T0 + Ss + 'lt,
F1: FnOnce() -> T1 + Ss + 'lt,
T0: TryEffective<'lt, Effect = E>,
T1: TryEffective<'lt, Err = T0::Err, Effect = E>,
{
type Output = <E as TryJoin>::Two<'lt, T0, T1>;
fn join(self) -> Self::Output {
<E as TryJoin>::two(self)
}
}