picoserve 0.18.0

An async no_std HTTP server suitable for bare-metal environments
Documentation
use core::future::Future;

pub enum Either<A, B> {
    First(A),
    Second(B),
}

impl<A> Either<A, core::convert::Infallible> {
    pub fn ignore_never_b(self) -> A {
        match self {
            Self::First(a) => a,
            Self::Second(b) => match b {},
        }
    }
}

impl<B> Either<core::convert::Infallible, B> {
    pub fn ignore_never_a(self) -> B {
        match self {
            Self::First(a) => match a {},
            Self::Second(b) => b,
        }
    }
}

impl<A, B> Either<A, B> {
    pub fn first_is_error(self) -> Result<B, A> {
        match self {
            Either::First(a) => Err(a),
            Either::Second(b) => Ok(b),
        }
    }
}

pub(crate) async fn select_either<A: Future, B: Future>(
    a: A,
    b: B,
) -> Either<A::Output, B::Output> {
    let mut a = core::pin::pin!(a);
    let mut b = core::pin::pin!(b);

    core::future::poll_fn(|cx| {
        use core::task::Poll;

        match a.as_mut().poll(cx) {
            Poll::Ready(output) => return Poll::Ready(Either::First(output)),
            Poll::Pending => (),
        }

        match b.as_mut().poll(cx) {
            Poll::Ready(output) => return Poll::Ready(Either::Second(output)),
            Poll::Pending => (),
        }

        Poll::Pending
    })
    .await
}

pub(crate) async fn select<A: Future, B: Future<Output = A::Output>>(a: A, b: B) -> A::Output {
    match select_either(a, b).await {
        Either::First(output) | Either::Second(output) => output,
    }
}

#[cfg(test)]
mod tests {
    use core::future::pending;

    use futures_util::FutureExt;

    use super::select;

    struct Success;

    #[test]
    #[ntest::timeout(1000)]
    fn select_first() {
        let Success = select(async { Success }, pending())
            .now_or_never()
            .expect("Future must resolve");
    }

    #[test]
    #[ntest::timeout(1000)]
    fn select_second() {
        let Success = select(pending(), async { Success })
            .now_or_never()
            .expect("Future must resolve");
    }

    #[test]
    #[ntest::timeout(1000)]
    fn select_neither() {
        enum Never {}

        assert!(select(pending::<Never>(), pending::<Never>())
            .now_or_never()
            .is_none());
    }
}