Diffstat (limited to 'src/effect.rs')
| -rw-r--r-- | src/effect.rs | 473 |
1 files changed, 351 insertions, 122 deletions
diff --git a/src/effect.rs b/src/effect.rs index 0f85ee3..458ed8a 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -3,7 +3,7 @@ pub mod blocking; use core::{future::Future, ops::ControlFlow}; -use crate::{higher_ranked_trait, higher_ranked_type, hkt::Marker}; +use crate::{higher_ranked_trait, higher_ranked_type, hkt::Marker, never::Never}; // 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. @@ -106,164 +106,364 @@ pub trait Effect: Join<Effect = Self> + TryJoin<Effect = Self> + Ss + Sized + 's F::Output: Ss + 'a; } -pub fn all_ctx<T>(x: T) -> (T, ()) { - (x, ()) +pub trait ReadyExt<'lt, Eff: Effective<'lt, Output = Self>>: Ss + Sized { + fn ready(self) -> Eff; } -pub fn merge_ctx<C, T>(ctx: C, x: T) -> (C, T) { - (ctx, x) +impl<'lt, Eff: Effective<'lt, Output = T>, T: Ss> ReadyExt<'lt, Eff> for T { + fn ready(self) -> Eff { + Eff::ready(self) + } +} + +pub trait ConvertShort<T> { + fn convert_short(short: Self) -> T; } -pub trait ShortCircuit { - type Normal: Ss; +pub trait FromShort<S = <Self as ShortCircuit>::Short> { + fn from_short(short: S) -> Self; +} - type Short: Ss; +impl<T, S> FromShort<S> for T +where + S: ConvertShort<T>, +{ + fn from_short(short: S) -> Self { + S::convert_short(short) + } +} - type NormalWith<T: Ss>: ShortCircuit<Normal = T, Short = Self::Short> + Ss; +pub trait ShortCircuit: FromShort { + type Output; + type Short; - fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R> - where - F: FnOnce(Self::Normal) -> R; + fn from_output(output: Self::Output) -> Self; + fn branch(self) -> ControlFlow<Self::Short, Self::Output>; +} - fn or_else<F>(self, f: F) -> Self - where - F: FnOnce(Self::Short) -> Self; +pub fn effective_from_short<'lt, Eff, S>(short: S) -> Eff +where + Eff: Effective<'lt>, + Eff::Output: FromShort<S>, +{ + Eff::ready(FromShort::from_short(short)) +} + +impl<T> ConvertShort<Option<T>> for Option<Never> { + fn convert_short(short: Option<Never>) -> Option<T> { + match short { + None => None, + Some(_) => unreachable!(), + } + } } -impl<T: Ss> ShortCircuit for Option<T> { - type Normal = T; +impl<T> ShortCircuit for Option<T> { + type Output = T; - type Short = (); + type Short = Option<Never>; - type NormalWith<U: Ss> = Option<U>; + fn branch(self) -> ControlFlow<Self::Short, Self::Output> { + match self { + Some(v) => ControlFlow::Continue(v), + None => ControlFlow::Break(None), + } + } - fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R> - where - F: FnOnce(Self::Normal) -> R, - { - Option::map(self, f) + fn from_output(output: Self::Output) -> Self { + Some(output) } +} - fn or_else<F>(self, f: F) -> Self - where - F: FnOnce(Self::Short) -> Self, - { - Option::or_else(self, || f(())) +impl<T, E> ConvertShort<Result<T, E>> for Result<Never, E> { + fn convert_short(short: Result<Never, E>) -> Result<T, E> { + match short { + Err(err) => Err(err), + Ok(_) => unreachable!(), + } } } -impl<T: Ss, E: Ss> ShortCircuit for Result<T, E> { - type Normal = T; +impl<T, E> ShortCircuit for Result<T, E> { + type Output = T; + + type Short = Result<Never, E>; + + fn branch(self) -> ControlFlow<Self::Short, Self::Output> { + match self { + Ok(v) => ControlFlow::Continue(v), + Err(err) => ControlFlow::Break(Err(err)), + } + } + + fn from_output(output: Self::Output) -> Self { + Ok(output) + } +} - type Short = E; +#[macro_export] +macro_rules! tri { + ($expr:expr $(,)?) => { + match $crate::effect::ShortCircuit::branch($expr) { + ::core::ops::ControlFlow::Continue(val) => val, + ::core::ops::ControlFlow::Break(short) => { + return $crate::effect::effective_from_short(short); + } + } + }; +} +pub use tri; - type NormalWith<U: Ss> = Result<U, E>; +pub trait EffectExt: Effect { + fn repeat_map<'ctx, 'wrap, I: Ss + 'wrap, U: Ss, F: Ss>( + input: I, + f: F, + ) -> ErasedEffective<'wrap, U, Self> + where + F: for<'temp> FnMut(&'temp mut I) -> ErasedEffective<'temp, ControlFlow<U>, Self, &'ctx ()>, + 'ctx: 'wrap, + { + Self::ready(input).repeat_map(f) + } - fn map<F, R: Ss>(self, f: F) -> Self::NormalWith<R> + #[inline(always)] + fn as_ctx<'ctx, 'wrap, I: Ss + 'wrap, U: Ss, F: Ss>( + input: I, + f: F, + ) -> ErasedEffective<'wrap, (I, U), Self> where - F: FnOnce(Self::Normal) -> R, + F: for<'temp> FnOnce(&'temp mut I) -> ErasedEffective<'temp, U, Self, &'ctx ()>, + 'ctx: 'wrap, { - Result::map(self, f) + Self::ready(input).as_ctx(f) } - fn or_else<F>(self, f: F) -> Self + fn as_ctx_map<'ctx, 'wrap, I: Ss + 'wrap, U: Ss, F: Ss>( + input: I, + f: F, + ) -> ErasedEffective<'wrap, U, Self> where - F: FnOnce(Self::Short) -> Self, + F: for<'temp> FnOnce(&'temp mut I) -> ErasedEffective<'temp, U, Self, &'ctx ()>, + 'ctx: 'wrap, { - Result::or_else(self, f) + Self::ready(input).as_ctx_map(f) } } +impl<T: Effect> EffectExt for 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> + fn remove_ctx<'wrap, Ctx: Ss, T: Ss>(self) -> ErasedEffective<'wrap, T, Self::Effect> where - F: FnOnce(<Self::Output as ShortCircuit>::Normal) -> R, - Self::Output: ShortCircuit, - 'lt: 'wrap; + Self: Effective<'lt, Output = (Ctx, T)>, + 'lt: 'wrap, + { + self.map(|(_, value)| value) + } - fn or_else<'wrap, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Self::Output, Self::Effect> + fn map<'wrap, U: Ss, F: Ss>(self, f: F) -> ErasedEffective<'wrap, U, Self::Effect> where - F: FnOnce(<Self::Output as ShortCircuit>::Short) -> Self::Output, - Self::Output: ShortCircuit, - 'lt: 'wrap; + F: FnOnce(Self::Output) -> U, + 'lt: 'wrap, + { + self.r#do( + |v| ((), ControlFlow::<_, Never>::Break(f(v))), + |_, _| unreachable!(), + |_, _: Never| unreachable!(), + |_, _: &mut Never| unreachable!(), + |_, _, _: Never| unreachable!(), + |_, _, v| v, + ) + } - fn demo(self) + fn then<'wrap, U: Ss, F: Ss>(self, f: F) -> ErasedEffective<'wrap, U, Self::Effect> where - Self: Effective<'lt, Output = (i32, i32)>; + F: FnOnce(Self::Output) -> ErasedEffective<'wrap, U, Self::Effect>, + 'lt: 'wrap, + { + self.r#do( + |v| ((), ControlFlow::Continue(v)), + |_, v| f(v).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |_, _, v| v, + ) + } - fn as_ctx_or_else<'ctx: 'lt, 'wrap, T: Ss, U: Ss, F: Ss>( - self, - f: F, - ) -> ErasedEffective<'wrap, (T, Option<U>), Self::Effect> + fn or_else<'wrap, U: Ss, F: Ss>(self, f: F) -> ErasedEffective<'wrap, 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; -} + Self: Effective<'lt, Output = Option<U>>, + F: FnOnce() -> ErasedEffective<'wrap, Option<U>, Self::Effect>, + 'lt: 'wrap, + { + self.r#do( + |v| { + ( + (), + match v { + Some(v) => ControlFlow::Break(Some(v)), + None => ControlFlow::Continue(()), + }, + ) + }, + |_, _| f().cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |_, _, v| v, + ) + } -impl<'lt, T: Effective<'lt>> EffectiveExt<'lt> for T { - fn map_normal<'wrap, F: Ss, R: Ss>( + #[inline(always)] + fn as_ctx<'ctx: 'lt, 'wrap, U: Ss, F: Ss>( self, f: F, - ) -> ErasedEffective<'wrap, <Self::Output as ShortCircuit>::NormalWith<R>, Self::Effect> + ) -> ErasedEffective<'wrap, (Self::Output, U), Self::Effect> where - F: FnOnce(<Self::Output as ShortCircuit>::Normal) -> R, - Self::Output: ShortCircuit, + F: for<'temp> FnOnce( + &'temp mut Self::Output, + ) -> ErasedEffective<'temp, U, Self::Effect, &'ctx ()>, 'lt: 'wrap, { - self.map(move |value| value.map(f)) + self.r#do( + |ctx| (ctx, ControlFlow::Continue(())), + #[inline(always)] + |ctx, _| f(ctx).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |ctx, _, v| (ctx, v), + ) } - fn or_else<'wrap, F: Ss>(self, f: F) -> ErasedEffective<'wrap, Self::Output, Self::Effect> + fn as_ctx_map<'ctx: 'lt, 'wrap, U: Ss, F: Ss>( + self, + f: F, + ) -> ErasedEffective<'wrap, U, Self::Effect> where - F: FnOnce(<Self::Output as ShortCircuit>::Short) -> Self::Output, - Self::Output: ShortCircuit, + F: for<'temp> FnOnce( + &'temp mut Self::Output, + ) -> ErasedEffective<'temp, U, Self::Effect, &'ctx ()>, 'lt: 'wrap, { - self.map(move |value| value.or_else(f)) + self.r#do( + |ctx| (ctx, ControlFlow::Continue(())), + |ctx, _| f(ctx).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |_, _, v| v, + ) } - fn demo(self) + fn as_ctx_or_else<'ctx: 'lt, 'wrap, Ctx: Ss, U: Ss, F: Ss>( + self, + f: F, + ) -> ErasedEffective<'wrap, (Ctx, Option<U>), Self::Effect> where - Self: Effective<'lt, Output = (i32, i32)>, + Self: Effective<'lt, Output = (Ctx, Option<U>)>, + F: for<'temp> FnOnce( + &'temp mut Ctx, + ) -> ErasedEffective<'temp, Option<U>, Self::Effect, &'ctx ()>, + 'lt: 'wrap, { - self.map(|(a, b)| a + b); + self.r#do( + |(ctx, v)| { + ( + ctx, + match v { + Some(v) => ControlFlow::Break(Some(v)), + None => ControlFlow::Continue(()), + }, + ) + }, + |ctx, ()| f(ctx).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |ctx, _, v| (ctx, v), + ) } - fn as_ctx_or_else<'ctx: 'lt, 'wrap, N: Ss, U: Ss, F: Ss>( + fn as_ctx_or_else_map<'ctx: 'lt, 'wrap, Ctx: Ss, U: Ss, F: Ss>( self, f: F, - ) -> ErasedEffective<'wrap, (N, Option<U>), Self::Effect> + ) -> ErasedEffective<'wrap, 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 ()>, + Self: Effective<'lt, Output = (Ctx, Option<U>)>, + F: for<'temp> FnOnce( + &'temp mut Ctx, + ) -> ErasedEffective<'temp, 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!(), + self.r#do( + |(ctx, v)| { + ( + ctx, + match v { + Some(v) => ControlFlow::Break(Some(v)), + None => ControlFlow::Continue(()), + }, + ) }, + |ctx, ()| f(ctx).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |_, _, v| v, + ) + } + + fn repeat<'ctx: 'lt, 'wrap, U: Ss, F: Ss>( + self, + mut f: F, + ) -> ErasedEffective<'wrap, (Self::Output, U), Self::Effect> + where + F: for<'temp> FnMut( + &'temp mut Self::Output, + ) + -> ErasedEffective<'temp, ControlFlow<U>, Self::Effect, &'ctx ()>, + 'lt: 'wrap, + { + self.r#do( + |ctx| (ctx, ControlFlow::Continue(())), + |_, _| <Self::Effect as Effect>::ready(()).cast(), + |_, _| ControlFlow::Continue(()), + |ctx, _| f(ctx).cast(), + |_, _, v| v, + |ctx, _, v| (ctx, v), + ) + } + + fn repeat_map<'ctx: 'lt, 'wrap, U: Ss, F: Ss>( + self, + mut f: F, + ) -> ErasedEffective<'wrap, U, Self::Effect> + where + F: for<'temp> FnMut( + &'temp mut Self::Output, + ) + -> ErasedEffective<'temp, ControlFlow<U>, Self::Effect, &'ctx ()>, + 'lt: 'wrap, + { + self.r#do( + |ctx| (ctx, ControlFlow::Continue(())), + |_, _| <Self::Effect as Effect>::ready(()).cast(), + |_, _| ControlFlow::Continue(()), + |ctx, _| f(ctx).cast(), + |_, _, v| v, + |_, _, v| v, ) } } -pub trait Effective<'lt>: Ss + 'lt { - fn into_erased<B>(self) -> ErasedEffective<'lt, Self::Output, Self::Effect, B>; +impl<'lt, T: Effective<'lt>> EffectiveExt<'lt> for T {} + +pub trait Effective<'lt>: Sized + Ss + 'lt { + fn cast<'wrap, B>(self) -> ErasedEffective<'wrap, Self::Output, Self::Effect, B> + where + 'lt: 'wrap; /// The effect the effective belongs to. type Effect: Effect; @@ -277,36 +477,49 @@ pub trait Effective<'lt>: Ss + 'lt { /// Convert the effective into a general future for use in async. fn into_future(self) -> Self::IntoFuture; - fn map<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect> - where - F: FnOnce(Self::Output) -> T, - 'lt: 'wrap; - - fn then<'wrap, T: Ss, F: Ss>(self, cb: F) -> ErasedEffective<'wrap, T, Self::Effect> - where - 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 - 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>( + fn ready(value: Self::Output) -> Self; + + fn r#do< + 'ctx: 'lt, + 'wrap, + Pre: Ss, + Ctx: Ss, + Owned: Ss, + First: Ss, + FirstOutput: Ss, + FirstPost: Ss, + Done: Ss, + Extra: Ss, + Repeat: Ss, + RepeatOutput: Ss, + RepeatPost: Ss, + Post: Ss, + Return: Ss, + >( self, - cb: F, - ) -> ErasedEffective<'wrap, (Self::Output, T), Self::Effect> + pre: Pre, + first: First, + first_post: FirstPost, + repeat: Repeat, + repeat_post: RepeatPost, + post: Post, + ) -> ErasedEffective<'wrap, Return, Self::Effect> where - F: for<'b> FnMut( - &'b mut Self::Output, - ) -> ErasedEffective<'b, ControlFlow<T>, Self::Effect, &'ctx ()>, + Pre: FnOnce(Self::Output) -> (Ctx, ControlFlow<Done, Owned>), + First: for<'temp> FnOnce( + &'temp mut Ctx, + Owned, + ) + -> ErasedEffective<'temp, FirstOutput, Self::Effect, &'wrap ()>, + FirstPost: for<'temp> FnOnce(&'temp mut Ctx, FirstOutput) -> ControlFlow<Done, Extra>, + Repeat: for<'temp> FnMut( + &'temp mut Ctx, + &'temp mut Extra, + ) + -> ErasedEffective<'temp, RepeatOutput, Self::Effect, &'wrap ()>, + RepeatPost: + for<'temp> FnMut(&'temp mut Ctx, &'temp mut Extra, RepeatOutput) -> ControlFlow<Done>, + Post: FnOnce(Ctx, Option<Extra>, Done) -> Return, 'lt: 'wrap; } @@ -502,3 +715,19 @@ where <E as TryJoin>::two(self) } } + +impl<'lt, E: Effect, F0, F1, F2, T0, T1, T2> TryJoinable<'lt, E> for (F0, F1, F2) +where + F0: FnOnce() -> T0 + Ss + 'lt, + F1: FnOnce() -> T1 + Ss + 'lt, + F2: FnOnce() -> T2 + Ss + 'lt, + T0: TryEffective<'lt, Effect = E>, + T1: TryEffective<'lt, Err = T0::Err, Effect = E>, + T2: TryEffective<'lt, Err = T0::Err, Effect = E>, +{ + type Output = <E as TryJoin>::Three<'lt, T0, T1, T2>; + + fn join(self) -> Self::Output { + <E as TryJoin>::three(self) + } +} |