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
//! 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::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; $( all_done &= $crate::core_reexport::future::Future::poll( unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }, cx).is_ready(); )* 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::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::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 } } }