#![allow(non_snake_case)]
use crate::future::{TryMaybeDone, try_maybe_done};
use core::fmt;
use core::pin::Pin;
use futures_core::future::{Future, TryFuture};
use futures_core::task::{Context, Poll};
use pin_project::pin_project;
macro_rules! generate {
($(
$(#[$doc:meta])*
($Join:ident, <Fut1, $($Fut:ident),*>),
)*) => ($(
$(#[$doc])*
#[pin_project]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct $Join<Fut1: TryFuture, $($Fut: TryFuture),*> {
#[pin] Fut1: TryMaybeDone<Fut1>,
$(#[pin] $Fut: TryMaybeDone<$Fut>,)*
}
impl<Fut1, $($Fut),*> fmt::Debug for $Join<Fut1, $($Fut),*>
where
Fut1: TryFuture + fmt::Debug,
Fut1::Ok: fmt::Debug,
Fut1::Error: fmt::Debug,
$(
$Fut: TryFuture + fmt::Debug,
$Fut::Ok: fmt::Debug,
$Fut::Error: fmt::Debug,
)*
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct(stringify!($Join))
.field("Fut1", &self.Fut1)
$(.field(stringify!($Fut), &self.$Fut))*
.finish()
}
}
impl<Fut1, $($Fut),*> $Join<Fut1, $($Fut),*>
where
Fut1: TryFuture,
$(
$Fut: TryFuture<Error=Fut1::Error>
),*
{
fn new(Fut1: Fut1, $($Fut: $Fut),*) -> $Join<Fut1, $($Fut),*> {
$Join {
Fut1: try_maybe_done(Fut1),
$($Fut: try_maybe_done($Fut)),*
}
}
}
impl<Fut1, $($Fut),*> Future for $Join<Fut1, $($Fut),*>
where
Fut1: TryFuture,
$(
$Fut: TryFuture<Error=Fut1::Error>
),*
{
type Output = Result<(Fut1::Ok, $($Fut::Ok),*), Fut1::Error>;
fn poll(
self: Pin<&mut Self>, cx: &mut Context<'_>
) -> Poll<Self::Output> {
let mut all_done = true;
let mut futures = self.project();
all_done &= futures.Fut1.as_mut().poll(cx)?.is_ready();
$(
all_done &= futures.$Fut.as_mut().poll(cx)?.is_ready();
)*
if all_done {
Poll::Ready(Ok((
futures.Fut1.take_output().unwrap(),
$(
futures.$Fut.take_output().unwrap()
),*
)))
} else {
Poll::Pending
}
}
}
)*)
}
generate! {
(TryJoin, <Fut1, Fut2>),
(TryJoin3, <Fut1, Fut2, Fut3>),
(TryJoin4, <Fut1, Fut2, Fut3, Fut4>),
(TryJoin5, <Fut1, Fut2, Fut3, Fut4, Fut5>),
}
pub fn try_join<Fut1, Fut2>(future1: Fut1, future2: Fut2) -> TryJoin<Fut1, Fut2>
where
Fut1: TryFuture,
Fut2: TryFuture<Error = Fut1::Error>,
{
TryJoin::new(future1, future2)
}
pub fn try_join3<Fut1, Fut2, Fut3>(
future1: Fut1,
future2: Fut2,
future3: Fut3,
) -> TryJoin3<Fut1, Fut2, Fut3>
where
Fut1: TryFuture,
Fut2: TryFuture<Error = Fut1::Error>,
Fut3: TryFuture<Error = Fut1::Error>,
{
TryJoin3::new(future1, future2, future3)
}
pub fn try_join4<Fut1, Fut2, Fut3, Fut4>(
future1: Fut1,
future2: Fut2,
future3: Fut3,
future4: Fut4,
) -> TryJoin4<Fut1, Fut2, Fut3, Fut4>
where
Fut1: TryFuture,
Fut2: TryFuture<Error = Fut1::Error>,
Fut3: TryFuture<Error = Fut1::Error>,
Fut4: TryFuture<Error = Fut1::Error>,
{
TryJoin4::new(future1, future2, future3, future4)
}
pub fn try_join5<Fut1, Fut2, Fut3, Fut4, Fut5>(
future1: Fut1,
future2: Fut2,
future3: Fut3,
future4: Fut4,
future5: Fut5,
) -> TryJoin5<Fut1, Fut2, Fut3, Fut4, Fut5>
where
Fut1: TryFuture,
Fut2: TryFuture<Error = Fut1::Error>,
Fut3: TryFuture<Error = Fut1::Error>,
Fut4: TryFuture<Error = Fut1::Error>,
Fut5: TryFuture<Error = Fut1::Error>,
{
TryJoin5::new(future1, future2, future3, future4, future5)
}