metatrait 0.0.0-alpha.0

RPITIT Monads
Documentation
use std::{
    future::Future,
    marker::PhantomData,
    pin::Pin,
    task::{Context, Poll},
};

use either::Either;
use futures::future::Pending;
use pin_project::pin_project;

use crate::{Impl, Trait};

pub struct ToFuture<Tr: ?Sized>(Tr);

impl<Tr: ?Sized + Trait> Trait for ToFuture<Tr> {
    type Assocaited = Tr;
    type In<'out: 'tmp, 'tmp, Imp: 'tmp + Impl<Self>> =
        (Pin<&'tmp mut Imp>, &'tmp mut Context<'out>);
    type Out<'out, Imp: Impl<Self>> = Poll<Imp::Associated>;
    type Sample = Pending<Tr::Sample>;
    type Common<'a> = Pin<Box<dyn 'a + Future<Output = Tr::Common<'a>>>> where Self: 'a;

    fn union(x: Either<impl Impl<Self>, impl Impl<Self>>) -> impl Impl<Self> {
        async {
            Trait::union(match x {
                Either::Left(x) => Either::Left(x.to_future().await),
                Either::Right(x) => Either::Right(x.to_future().await),
            })
        }
    }

    fn common<'a>(x: impl 'a + Impl<Self>) -> Self::Common<'a>
    where
        Self: 'a,
    {
        Box::pin(async { Trait::common(x.to_future().await) })
    }
}

impl<F: Future<Output = Out>, Out: Impl<Tr>, Tr: ?Sized + Trait> Impl<ToFuture<Tr>> for F {
    type Associated = F::Output;

    fn method<'out: 'tmp, 'tmp>((this, cx): (Pin<&mut Self>, &mut Context<'_>)) -> Poll<F::Output> {
        this.poll(cx)
    }
}

#[pin_project]
struct TraitFuture<F, Tr: ?Sized>(#[pin] F, PhantomData<Tr>);

impl<F: Impl<ToFuture<Tr>>, Tr: ?Sized + Trait> Future for TraitFuture<F, Tr> {
    type Output = F::Associated;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        F::method((self.project().0, cx))
    }
}

pub trait ToFutureExt<Tr: ?Sized + Trait>: Impl<ToFuture<Tr>> {
    fn to_future(self) -> impl Future<Output = Self::Associated> {
        TraitFuture(self, PhantomData)
    }
}

impl<F: Impl<ToFuture<Tr>>, Tr: ?Sized + Trait> ToFutureExt<Tr> for F {}