use frunk_core::coproduct::{CNil, Coproduct};
use frunk_core::indices::{Here, There};
pub trait Effect {
type Resume<'r>;
fn shorten_resume<'a: 'b, 'b>(resume: Self::Resume<'a>) -> Self::Resume<'b>;
}
pub trait MapResume {
type Output<'r>;
#[doc(hidden)]
fn shorten_resumes<'a: 'b, 'b>(resumes: Self::Output<'a>) -> Self::Output<'b>;
}
impl MapResume for CNil {
type Output<'r> = CNil;
#[inline]
fn shorten_resumes<'a: 'b, 'b>(resumes: CNil) -> CNil {
resumes
}
}
impl<H: Effect, T: MapResume> MapResume for Coproduct<H, T> {
type Output<'r> = Coproduct<H::Resume<'r>, <T as MapResume>::Output<'r>>;
#[inline]
fn shorten_resumes<'a: 'b, 'b>(
resumes: Coproduct<H::Resume<'a>, T::Output<'a>>,
) -> Coproduct<H::Resume<'b>, T::Output<'b>> {
match resumes {
Coproduct::Inl(head) => Coproduct::Inl(H::shorten_resume(head)),
Coproduct::Inr(tail) => Coproduct::Inr(T::shorten_resumes(tail)),
}
}
}
pub trait Effects<'a>: MapResume + Send + Sync + 'a {}
impl<'a, E> Effects<'a> for E where E: MapResume + Send + Sync + 'a {}
pub type Resumes<'r, E> = <E as MapResume>::Output<'r>;
pub trait InjectResume<'a, E: Effect, Index>: MapResume {
fn inject_resume(r: E::Resume<'a>) -> Resumes<'a, Self>;
}
impl<'a, E: Effect, T: MapResume> InjectResume<'a, E, Here> for Coproduct<E, T> {
#[inline]
fn inject_resume(r: E::Resume<'a>) -> Resumes<'a, Self> {
Coproduct::Inl(r)
}
}
impl<'a, H: Effect, E: Effect, T: MapResume, TailIndex> InjectResume<'a, E, There<TailIndex>>
for Coproduct<H, T>
where
T: InjectResume<'a, E, TailIndex>,
{
#[inline]
fn inject_resume(r: E::Resume<'a>) -> Resumes<'a, Self> {
Coproduct::Inr(T::inject_resume(r))
}
}
#[derive(Copy, Clone, Debug)]
pub struct Start;
impl Effect for Start {
type Resume<'r> = Start;
#[inline]
fn shorten_resume<'a: 'b, 'b>(resume: Start) -> Start {
resume
}
}
pub type CanStart<Effs> = Coproduct<Start, Effs>;