#![no_std]
#![forbid(unsafe_code)]
use core::{
convert::Infallible,
future::Future,
pin::Pin,
task::{Context, Poll},
};
use futures_core::{future::FusedFuture, ready};
use pin_project::pin_project;
#[pin_project]
#[derive(Debug, Clone, Default)]
pub struct TryForegroundBackground<F, B> {
#[pin]
foreground: F,
#[pin]
background: B,
}
impl<F, B, E> Future for TryForegroundBackground<F, B>
where
F: Future,
B: Future<Output = Result<(), E>> + FusedFuture,
{
type Output = Result<F::Output, E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match this.foreground.poll(cx) {
Poll::Ready(value) => Poll::Ready(Ok(value)),
Poll::Pending if this.background.is_terminated() => Poll::Pending,
Poll::Pending => match ready!(this.background.poll(cx)) {
Ok(()) => Poll::Pending,
Err(err) => Poll::Ready(Err(err)),
},
}
}
}
#[pin_project]
#[derive(Debug, Clone, Default)]
struct NeverError<F> {
#[pin]
fut: F,
}
impl<F: Future> Future for NeverError<F> {
type Output = Result<F::Output, Infallible>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.project().fut.poll(cx).map(Ok)
}
}
impl<F: FusedFuture> FusedFuture for NeverError<F> {
fn is_terminated(&self) -> bool {
self.fut.is_terminated()
}
}
#[pin_project]
#[derive(Debug, Clone, Default)]
pub struct ForegroundBackground<F, B> {
#[pin]
inner: TryForegroundBackground<F, NeverError<B>>,
}
impl<F, B> Future for ForegroundBackground<F, B>
where
F: Future,
B: Future<Output = ()> + FusedFuture,
{
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.project().inner.poll(cx).map(|res| match res {
Ok(value) => value,
Err(infallible) => match infallible {},
})
}
}
pub trait FutureExt: Sized + Future {
#[must_use = "futures do nothing unless you `.await` or poll them"]
fn with_background<B>(self, background: B) -> ForegroundBackground<Self, B>
where
B: Future<Output = ()> + FusedFuture,
{
ForegroundBackground {
inner: self.with_try_background(NeverError { fut: background }),
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
fn with_try_background<B, E>(self, background: B) -> TryForegroundBackground<Self, B>
where
B: Future<Output = Result<(), E>>,
{
TryForegroundBackground {
foreground: self,
background,
}
}
}
impl<F: Future> FutureExt for F {}