1#![allow(non_snake_case)]
2
3use super::assert_future;
4use crate::future::{maybe_done, MaybeDone};
5use core::fmt;
6use core::pin::Pin;
7use futures_core::future::{FusedFuture, Future};
8use futures_core::task::{Context, Poll};
9use pin_project_lite::pin_project;
10
11macro_rules! generate {
12    ($(
13        $(#[$doc:meta])*
14        ($Join:ident, <$($Fut:ident),*>),
15    )*) => ($(
16        pin_project! {
17            $(#[$doc])*
18            #[must_use = "futures do nothing unless you `.await` or poll them"]
19            pub struct $Join<$($Fut: Future),*> {
20                $(#[pin] $Fut: MaybeDone<$Fut>,)*
21            }
22        }
23
24        impl<$($Fut),*> fmt::Debug for $Join<$($Fut),*>
25        where
26            $(
27                $Fut: Future + fmt::Debug,
28                $Fut::Output: fmt::Debug,
29            )*
30        {
31            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32                f.debug_struct(stringify!($Join))
33                    $(.field(stringify!($Fut), &self.$Fut))*
34                    .finish()
35            }
36        }
37
38        impl<$($Fut: Future),*> $Join<$($Fut),*> {
39            fn new($($Fut: $Fut),*) -> Self {
40                Self {
41                    $($Fut: maybe_done($Fut)),*
42                }
43            }
44        }
45
46        impl<$($Fut: Future),*> Future for $Join<$($Fut),*> {
47            type Output = ($($Fut::Output),*);
48
49            fn poll(
50                self: Pin<&mut Self>, cx: &mut Context<'_>
51            ) -> Poll<Self::Output> {
52                let mut all_done = true;
53                let mut futures = self.project();
54                $(
55                    all_done &= futures.$Fut.as_mut().poll(cx).is_ready();
56                )*
57
58                if all_done {
59                    Poll::Ready(($(futures.$Fut.take_output().unwrap()), *))
60                } else {
61                    Poll::Pending
62                }
63            }
64        }
65
66        impl<$($Fut: FusedFuture),*> FusedFuture for $Join<$($Fut),*> {
67            fn is_terminated(&self) -> bool {
68                $(
69                    self.$Fut.is_terminated()
70                ) && *
71            }
72        }
73    )*)
74}
75
76generate! {
77    (Join, <Fut1, Fut2>),
79
80    (Join3, <Fut1, Fut2, Fut3>),
82
83    (Join4, <Fut1, Fut2, Fut3, Fut4>),
85
86    (Join5, <Fut1, Fut2, Fut3, Fut4, Fut5>),
88}
89
90pub fn join<Fut1, Fut2>(future1: Fut1, future2: Fut2) -> Join<Fut1, Fut2>
112where
113    Fut1: Future,
114    Fut2: Future,
115{
116    let f = Join::new(future1, future2);
117    assert_future::<(Fut1::Output, Fut2::Output), _>(f)
118}
119
120pub fn join3<Fut1, Fut2, Fut3>(
137    future1: Fut1,
138    future2: Fut2,
139    future3: Fut3,
140) -> Join3<Fut1, Fut2, Fut3>
141where
142    Fut1: Future,
143    Fut2: Future,
144    Fut3: Future,
145{
146    let f = Join3::new(future1, future2, future3);
147    assert_future::<(Fut1::Output, Fut2::Output, Fut3::Output), _>(f)
148}
149
150pub fn join4<Fut1, Fut2, Fut3, Fut4>(
168    future1: Fut1,
169    future2: Fut2,
170    future3: Fut3,
171    future4: Fut4,
172) -> Join4<Fut1, Fut2, Fut3, Fut4>
173where
174    Fut1: Future,
175    Fut2: Future,
176    Fut3: Future,
177    Fut4: Future,
178{
179    let f = Join4::new(future1, future2, future3, future4);
180    assert_future::<(Fut1::Output, Fut2::Output, Fut3::Output, Fut4::Output), _>(f)
181}
182
183pub fn join5<Fut1, Fut2, Fut3, Fut4, Fut5>(
202    future1: Fut1,
203    future2: Fut2,
204    future3: Fut3,
205    future4: Fut4,
206    future5: Fut5,
207) -> Join5<Fut1, Fut2, Fut3, Fut4, Fut5>
208where
209    Fut1: Future,
210    Fut2: Future,
211    Fut3: Future,
212    Fut4: Future,
213    Fut5: Future,
214{
215    let f = Join5::new(future1, future2, future3, future4, future5);
216    assert_future::<(Fut1::Output, Fut2::Output, Fut3::Output, Fut4::Output, Fut5::Output), _>(f)
217}