1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! The `join` macro.

/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
///
/// While `join!(a, b)` is similar to `(await!(a), await!(b))`,
/// `join!` polls both futures concurrently and therefore is more efficent.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// ```
/// #![feature(async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{join, future};
///
/// let a = future::ready(1);
/// let b = future::ready(2);
///
/// assert_eq!(join!(a, b), (1, 2));
/// # });
/// ```
#[macro_export]
macro_rules! join {
    ($($fut:ident),*) => { {
        $(
            // Move future into a local so that it is pinned in one place and
            // is no longer accessible by the end user.
            let mut $fut = $crate::future::maybe_done($fut);
        )*
        await!($crate::future::poll_fn(move |cx| {
            let mut all_done = true;
            $(
                if $crate::core_reexport::future::Future::poll(
                    unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }, cx).is_pending()
                {
                    all_done = false;
                }
            )*
            if all_done {
                $crate::core_reexport::task::Poll::Ready(($(
                    unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }.take_output().unwrap(),
                )*))
            } else {
                $crate::core_reexport::task::Poll::Pending
            }
        }))
    } }
}

/// Polls multiple futures simultaneously, resolving to a [`Result`] containing
/// either a tuple of the successful outputs or an error.
///
/// `try_join!` is similar to [`join!`], but completes immediately if any of
/// the futures return an error.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// When used on multiple futures that return `Ok`, `try_join!` will return
/// `Ok` of a tuple of the values:
///
/// ```
/// #![feature(async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Ok::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Ok((1, 2)));
/// # });
/// ```
///
/// If one of the futures resolves to an error, `try_join!` will return
/// that error:
///
/// ```
/// #![feature(async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Err::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Err(2));
/// # });
/// ```
#[macro_export]
macro_rules! try_join {
    ($($fut:ident),*) => { {
        $(
            // Move future into a local so that it is pinned in one place and
            // is no longer accessible by the end user.
            let mut $fut = $crate::future::maybe_done($fut);
        )*

        let res: $crate::core_reexport::result::Result<_, _> = await!($crate::future::poll_fn(move |cx| {
            let mut all_done = true;
            $(
                if $crate::core_reexport::future::Future::poll(
                    unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }, cx).is_pending()
                {
                    all_done = false;
                } else if unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }.output_mut().unwrap().is_err() {
                    // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
                    // a `T: Debug` bound.
                    return $crate::core_reexport::task::Poll::Ready(
                        $crate::core_reexport::result::Result::Err(
                            unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }.take_output().unwrap().err().unwrap()
                        )
                    );
                }
            )*
            if all_done {
                $crate::core_reexport::task::Poll::Ready(
                    $crate::core_reexport::result::Result::Ok(($(
                        // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce
                        // an `E: Debug` bound.
                        unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }.take_output().unwrap().ok().unwrap(),
                    )*))
                )
            } else {
                $crate::core_reexport::task::Poll::Pending
            }
        }));

        res
    } }
}