use core::pin::Pin;
use futures::FutureExt as _;
use pin_project::pin_project;
use crate::hkt::Marker;
use super::*;
pub enum Async {}
pub struct ErasedFutureHrt<T>(Marker<T>);
enum ErasedFutureKind<'lt, T> {
Boxed(Pin<Box<dyn Future<Output = T> + Send + Sync + 'lt>>),
Ready(T),
}
#[must_use]
pub struct ErasedFuture<'lt, T> {
kind: ErasedFutureKind<'lt, T>,
}
#[pin_project(project = EffectFutureKindProj)]
enum EffectFutureKind<'lt, T> {
Boxed(Pin<Box<dyn Future<Output = T> + Send + Sync + 'lt>>),
Ready(#[pin] ::core::future::Ready<T>),
}
#[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<Self::Output> {
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, O> Erased::ForLt<'lt, T, Async, &'lt (T, O)> for ErasedFutureHrt<T> {
type Effective = ErasedFuture<'lt, T>;
}
impl<T: Ss> Erased::Hkt<T, Async> for ErasedFutureHrt<T> {
type Hrt<O> = Self;
}
impl Effect for Async {
type Erased<T: Ss> = ErasedFutureHrt<T>;
fn ready<'a, T: Ss + 'a>(value: T) -> ErasedEffective<'a, T, Self> {
ErasedFuture {
kind: ErasedFutureKind::Ready(value),
}
}
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)),
}
}
}
impl<'lt, U: Ss + 'lt> Effective<'lt> for ErasedFuture<'lt, U> {
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<Done, Owned>),
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<Done, Extra>,
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<Done>,
Post: 'wrap + Ss + FnOnce(Ctx, Option<Extra>, 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)),
}
}
fn ready(value: Self::Output) -> Self {
ErasedFuture {
kind: ErasedFutureKind::Ready(value),
}
}
}
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))
})
}
}