1 /// Wait on multiple concurrent branches, returning when **all** branches
2 /// complete with `Ok(_)` or on the first `Err(_)`.
3 ///
4 /// The `try_join!` macro must be used inside of async functions, closures, and
5 /// blocks.
6 ///
7 /// Similar to [`join!`], the `try_join!` macro takes a list of async
8 /// expressions and evaluates them concurrently on the same task. Each async
9 /// expression evaluates to a future and the futures from each expression are
10 /// multiplexed on the current task. The `try_join!` macro returns when **all**
11 /// branches return with `Ok` or when the **first** branch returns with `Err`.
12 ///
13 /// [`join!`]: macro@join
14 ///
15 /// # Notes
16 ///
17 /// The supplied futures are stored inline and does not require allocating a
18 /// `Vec`.
19 ///
20 /// ### Runtime characteristics
21 ///
22 /// By running all async expressions on the current task, the expressions are
23 /// able to run **concurrently** but not in **parallel**. This means all
24 /// expressions are run on the same thread and if one branch blocks the thread,
25 /// all other expressions will be unable to continue. If parallelism is
26 /// required, spawn each async expression using [`tokio::spawn`] and pass the
27 /// join handle to `try_join!`.
28 ///
29 /// [`tokio::spawn`]: crate::spawn
30 ///
31 /// # Examples
32 ///
33 /// Basic try_join with two branches.
34 ///
35 /// ```
36 /// async fn do_stuff_async() -> Result<(), &'static str> {
37 ///     // async work
38 /// # Ok(())
39 /// }
40 ///
41 /// async fn more_async_work() -> Result<(), &'static str> {
42 ///     // more here
43 /// # Ok(())
44 /// }
45 ///
46 /// #[tokio::main]
47 /// async fn main() {
48 ///     let res = tokio::try_join!(
49 ///         do_stuff_async(),
50 ///         more_async_work());
51 ///
52 ///     match res {
53 ///          Ok((first, second)) => {
54 ///              // do something with the values
55 ///          }
56 ///          Err(err) => {
57 ///             println!("processing failed; error = {}", err);
58 ///          }
59 ///     }
60 /// }
61 /// ```
62 #[macro_export]
63 #[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
64 macro_rules! try_join {
65     (@ {
66         // One `_` for each branch in the `try_join!` macro. This is not used once
67         // normalization is complete.
68         ( $($count:tt)* )
69 
70         // Normalized try_join! branches
71         $( ( $($skip:tt)* ) $e:expr, )*
72 
73     }) => {{
74         use $crate::macros::support::{maybe_done, poll_fn, Future, Pin};
75         use $crate::macros::support::Poll::{Ready, Pending};
76 
77         // Safety: nothing must be moved out of `futures`. This is to satisfy
78         // the requirement of `Pin::new_unchecked` called below.
79         let mut futures = ( $( maybe_done($e), )* );
80 
81         poll_fn(move |cx| {
82             let mut is_pending = false;
83 
84             $(
85                 // Extract the future for this branch from the tuple.
86                 let ( $($skip,)* fut, .. ) = &mut futures;
87 
88                 // Safety: future is stored on the stack above
89                 // and never moved.
90                 let mut fut = unsafe { Pin::new_unchecked(fut) };
91 
92                 // Try polling
93                 if fut.as_mut().poll(cx).is_pending() {
94                     is_pending = true;
95                 } else if fut.as_mut().output_mut().expect("expected completed future").is_err() {
96                     return Ready(Err(fut.take_output().expect("expected completed future").err().unwrap()))
97                 }
98             )*
99 
100             if is_pending {
101                 Pending
102             } else {
103                 Ready(Ok(($({
104                     // Extract the future for this branch from the tuple.
105                     let ( $($skip,)* fut, .. ) = &mut futures;
106 
107                     // Safety: future is stored on the stack above
108                     // and never moved.
109                     let mut fut = unsafe { Pin::new_unchecked(fut) };
110 
111                     fut
112                         .take_output()
113                         .expect("expected completed future")
114                         .ok()
115                         .expect("expected Ok(_)")
116                 },)*)))
117             }
118         }).await
119     }};
120 
121     // ===== Normalize =====
122 
123     (@ { ( $($s:tt)* ) $($t:tt)* } $e:expr, $($r:tt)* ) => {
124         $crate::try_join!(@{ ($($s)* _) $($t)* ($($s)*) $e, } $($r)*)
125     };
126 
127     // ===== Entry point =====
128 
129     ( $($e:expr),* $(,)?) => {
130         $crate::try_join!(@{ () } $($e,)*)
131     };
132 }
133