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(pin, 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 |lw| { let mut all_done = true; $( if $crate::core_reexport::future::Future::poll( unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }, lw).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(pin, 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(pin, 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 |lw| { let mut all_done = true; $( if $crate::core_reexport::future::Future::poll( unsafe { $crate::core_reexport::pin::Pin::new_unchecked(&mut $fut) }, lw).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 } } }