#![allow(non_snake_case)]
use core::fmt;
use core::mem;
use {Future, Poll, IntoFuture, Async};
macro_rules! generate {
($(
$(#[$doc:meta])*
($Join:ident, $new:ident, <A, $($B:ident),*>),
)*) => ($(
$(#[$doc])*
#[must_use = "futures do nothing unless polled"]
pub struct $Join<A, $($B),*>
where A: Future,
$($B: Future<Error=A::Error>),*
{
a: MaybeDone<A>,
$($B: MaybeDone<$B>,)*
}
impl<A, $($B),*> fmt::Debug for $Join<A, $($B),*>
where A: Future + fmt::Debug,
A::Item: fmt::Debug,
$(
$B: Future<Error=A::Error> + fmt::Debug,
$B::Item: fmt::Debug
),*
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct(stringify!($Join))
.field("a", &self.a)
$(.field(stringify!($B), &self.$B))*
.finish()
}
}
pub fn $new<A, $($B),*>(a: A, $($B: $B),*) -> $Join<A, $($B),*>
where A: Future,
$($B: Future<Error=A::Error>),*
{
$Join {
a: MaybeDone::NotYet(a),
$($B: MaybeDone::NotYet($B)),*
}
}
impl<A, $($B),*> $Join<A, $($B),*>
where A: Future,
$($B: Future<Error=A::Error>),*
{
fn erase(&mut self) {
self.a = MaybeDone::Gone;
$(self.$B = MaybeDone::Gone;)*
}
}
impl<A, $($B),*> Future for $Join<A, $($B),*>
where A: Future,
$($B: Future<Error=A::Error>),*
{
type Item = (A::Item, $($B::Item),*);
type Error = A::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut all_done = match self.a.poll() {
Ok(done) => done,
Err(e) => {
self.erase();
return Err(e)
}
};
$(
all_done = match self.$B.poll() {
Ok(done) => all_done && done,
Err(e) => {
self.erase();
return Err(e)
}
};
)*
if all_done {
Ok(Async::Ready((self.a.take(), $(self.$B.take()),*)))
} else {
Ok(Async::NotReady)
}
}
}
impl<A, $($B),*> IntoFuture for (A, $($B),*)
where A: IntoFuture,
$(
$B: IntoFuture<Error=A::Error>
),*
{
type Future = $Join<A::Future, $($B::Future),*>;
type Item = (A::Item, $($B::Item),*);
type Error = A::Error;
fn into_future(self) -> Self::Future {
match self {
(a, $($B),+) => {
$new(
IntoFuture::into_future(a),
$(IntoFuture::into_future($B)),+
)
}
}
}
}
)*)
}
generate! {
(Join, new, <A, B>),
(Join3, new3, <A, B, C>),
(Join4, new4, <A, B, C, D>),
(Join5, new5, <A, B, C, D, E>),
}
#[derive(Debug)]
enum MaybeDone<A: Future> {
NotYet(A),
Done(A::Item),
Gone,
}
impl<A: Future> MaybeDone<A> {
fn poll(&mut self) -> Result<bool, A::Error> {
let res = match *self {
MaybeDone::NotYet(ref mut a) => a.poll()?,
MaybeDone::Done(_) => return Ok(true),
MaybeDone::Gone => panic!("cannot poll Join twice"),
};
match res {
Async::Ready(res) => {
*self = MaybeDone::Done(res);
Ok(true)
}
Async::NotReady => Ok(false),
}
}
fn take(&mut self) -> A::Item {
match mem::replace(self, MaybeDone::Gone) {
MaybeDone::Done(a) => a,
_ => panic!(),
}
}
}