Documentation
use std::future::Future;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;

#[derive(Clone, Copy, Debug)]
#[pin_project::pin_project(project = ProjectedMaybe)]
pub enum Maybe<F, O> {
    Future(#[pin] F),
    Ready(Option<O>),
}

impl<F, O> Maybe<F, O> {
    #[inline]
    pub const fn ready(value: O) -> Maybe<F, O> {
        Maybe::Ready(Some(value))
    }
}

impl<F, O> Future for Maybe<F, O>
where
    F: Future<Output = O>,
{
    type Output = O;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match self.project() {
            ProjectedMaybe::Future(fut) => Future::poll(fut, cx),
            ProjectedMaybe::Ready(out) => match out.take() {
                None => unreachable!("polled after ready"),
                Some(out) => Poll::Ready(out),
            },
        }
    }
}

#[derive(Clone, Copy, Debug)]
#[pin_project::pin_project(project = ProjectedEither)]
pub enum Either<L, R> {
    Left(#[pin] L),
    Right(#[pin] R),
}

impl<L, R, O> Future for Either<L, R>
where
    L: Future<Output = O>,
    R: Future<Output = O>,
{
    type Output = O;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match self.project() {
            ProjectedEither::Left(fut) => Future::poll(fut, cx),
            ProjectedEither::Right(fut) => Future::poll(fut, cx),
        }
    }
}