use core::pin::Pin; use futures::FutureExt as _; use pin_project::pin_project; use crate::hkt::Marker; use self::blocking::Spin; use super::*; pub struct Async(Marker); pub struct ErasedFutureHrt(Marker<(T, B)>); enum ErasedFutureKind<'lt, T> { Boxed(Pin + Send + Sync + 'lt>>), Ready(T), } #[must_use] pub struct ErasedFuture<'lt, T, B> { kind: ErasedFutureKind<'lt, T>, _marker: Marker, } #[pin_project(project = EffectFutureKindProj)] enum EffectFutureKind<'lt, T> { Boxed(Pin + Send + Sync + 'lt>>), Ready(#[pin] ::core::future::Ready), } #[must_use] #[pin_project] pub struct EffectFuture<'lt, T> { #[pin] kind: EffectFutureKind<'lt, T>, } impl<'lt, T> Future for EffectFuture<'lt, T> { type Output = T; fn poll( self: Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> core::task::Poll { let this = self.project(); match this.kind.project() { EffectFutureKindProj::Boxed(fut) => fut.poll_unpin(cx), EffectFutureKindProj::Ready(fut) => fut.poll(cx), } } } impl<'lt, T: Ss, B: BlockOn, O> Erased::ForLt<'lt, T, Async, &'lt (T, O)> for ErasedFutureHrt { type Effective = ErasedFuture<'lt, T, B>; } impl Erased::Hkt> for ErasedFutureHrt { type Hrt = Self; } impl Effect for Async { type BlockOn = B; type Erased = ErasedFutureHrt; fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self> { ErasedFuture { kind: ErasedFutureKind::Ready(value), _marker: Default::default(), } } fn from_future<'a, F>(future: F) -> ErasedEffective<'a, F::Output, Self> where F: Future + Ss + 'a, F::Output: Ss + 'a, { ErasedFuture { kind: ErasedFutureKind::Boxed(Box::pin(future)), _marker: Default::default(), } } } impl<'lt, U: Ss + 'lt, B: BlockOn> Effective<'lt> for ErasedFuture<'lt, U, B> { fn cast<'wrap, X>(self) -> ErasedEffective<'wrap, Self::Output, Self::Effect, X> where 'lt: 'wrap, { self } type Effect = Async; type Output = U; type IntoFuture = EffectFuture<'lt, U>; fn into_future(self) -> Self::IntoFuture { EffectFuture { kind: match self.kind { ErasedFutureKind::Boxed(fut) => EffectFutureKind::Boxed(fut), ErasedFutureKind::Ready(value) => { EffectFutureKind::Ready(::core::future::ready(value)) } }, } } fn r#do< 'ctx: 'lt, 'wrap, Pre, Ctx, Owned, First, FirstOutput, FirstPost, Done, Extra, Repeat, RepeatOutput, RepeatPost, Post, Return, >( self, pre: Pre, first: First, first_post: FirstPost, mut repeat: Repeat, mut repeat_post: RepeatPost, post: Post, ) -> ErasedEffective<'wrap, Return, Self::Effect> where Pre: Ss + 'wrap + FnOnce(Self::Output) -> (Ctx, ControlFlow), First: Ss + 'wrap + for<'b> FnOnce( &'b mut Ctx, Owned, ) -> ErasedEffective<'b, FirstOutput, Self::Effect, &'wrap ()>, FirstPost: Ss + 'wrap + for<'b> FnOnce(&'b mut Ctx, FirstOutput) -> ControlFlow, Repeat: Ss + 'wrap + for<'b> FnMut( &'b mut Ctx, &'b mut Extra, ) -> ErasedEffective<'b, RepeatOutput, Self::Effect, &'wrap ()>, RepeatPost: Ss + 'wrap + for<'b> FnMut(&'b mut Ctx, &'b mut Extra, RepeatOutput) -> ControlFlow, Post: 'wrap + Ss + FnOnce(Ctx, Option, Done) -> Return, Return: Ss, FirstOutput: Ss, RepeatOutput: Ss, Owned: Ss, Done: Ss, Ctx: Ss, Extra: Ss, 'lt: 'wrap, { let fut = async move { let (ctx, done, extra) = match pre(self.into_future().await) { (mut ctx, ControlFlow::Continue(owned)) => { let first_output = first(&mut ctx, owned).into_future().await; let (done, extra) = match first_post(&mut ctx, first_output) { ControlFlow::Continue(mut extra) => loop { let repeat_output = repeat(&mut ctx, &mut extra).into_future().await; match repeat_post(&mut ctx, &mut extra, repeat_output) { ControlFlow::Continue(()) => {} ControlFlow::Break(done) => break (done, Some(extra)), } }, ControlFlow::Break(done) => (done, None), }; (ctx, done, extra) } (ctx, ControlFlow::Break(done)) => (ctx, done, None), }; post(ctx, extra, done) }; ErasedFuture { kind: ErasedFutureKind::Boxed(Box::pin(fut)), _marker: Default::default(), } } fn ready(value: Self::Output) -> Self { ErasedFuture { kind: ErasedFutureKind::Ready(value), _marker: Default::default(), } } } impl Join for Async { type Effect = Self; fn two<'a, T0, T1>( effectives: (T0, T1), ) -> ErasedEffective<'a, (T0::Output, T1::Output), Self::Effect> where T0: Ss + 'a + Effective<'a, Effect = Self::Effect>, T1: Ss + 'a + Effective<'a, Effect = Self::Effect>, { Self::from_future(async { let v0 = effectives.0.into_future().await; let v1 = effectives.1.into_future().await; (v0, v1) }) } fn three<'a, T0, T1, T2>( effectives: (T0, T1, T2), ) -> ErasedEffective<'a, (T0::Output, T1::Output, T2::Output), Self::Effect> where T0: Ss + 'a + Effective<'a, Effect = Self::Effect>, T1: Ss + 'a + Effective<'a, Effect = Self::Effect>, T2: Ss + 'a + Effective<'a, Effect = Self::Effect>, { Self::from_future(async { let v0 = effectives.0.into_future().await; let v1 = effectives.1.into_future().await; let v2 = effectives.2.into_future().await; (v0, v1, v2) }) } } impl TryJoin for Async { type Effect = Self; fn two<'a, T0, T1, F0, F1>( cb: (F0, F1), ) -> ErasedEffective<'a, Result<(T0::Ok, T1::Ok), T0::Err>, Self::Effect> where T0: Ss + 'a + TryEffective<'a, Effect = Self::Effect>, T1: Ss + 'a + TryEffective<'a, Err = T0::Err, Effect = Self::Effect>, F0: Ss + 'a + FnOnce() -> T0, F1: Ss + 'a + FnOnce() -> T1, { Self::from_future(async { let v0 = cb.0().into_future().await?; let v1 = cb.1().into_future().await?; Ok((v0, v1)) }) } fn three<'a, T0, T1, T2, F0, F1, F2>( cb: (F0, F1, F2), ) -> ErasedEffective<'a, Result<(T0::Ok, T1::Ok, T2::Ok), T0::Err>, Self::Effect> where T0: Ss + 'a + TryEffective<'a, Effect = Self::Effect>, T1: Ss + 'a + TryEffective<'a, Err = T0::Err, Effect = Self::Effect>, T2: Ss + 'a + TryEffective<'a, Err = T0::Err, Effect = Self::Effect>, F0: Ss + 'a + FnOnce() -> T0, F1: Ss + 'a + FnOnce() -> T1, F2: Ss + 'a + FnOnce() -> T2, { Self::from_future(async { let v0 = cb.0().into_future().await?; let v1 = cb.1().into_future().await?; let v2 = cb.2().into_future().await?; Ok((v0, v1, v2)) }) } }