Repository: tokio-rs/tokio
File: tokio/src/task/join_set.rs (Rust)

Code before:
            }
        }
    }

    /// Aborts all tasks and waits for them to finish shutting down.
    ///
    /// Calling this method is equivalent to calling [`abort_all`] and then calling [`join_next`] in
    /// a loop until it returns `None`.
    ///
    /// This method ignores any panics in the tasks shutting down. When this call returns, the
    /// `JoinSet` will be empty.
    ///
    /// [`abort_all`]: fn@Self::abort_all
    /// [`join_next`]: fn@Self::join_next
    pub async fn shutdown(&mut self) {
        self.abort_all();
        while self.join_next().await.is_some() {}
    }

    /// Awaits the completion of all tasks on this `JoinSet`, returning a Vector of their results.
    ///
    /// If any task on this `JoinSet` errors or panics, this will panic and cancel all
    /// tasks on this `JoinSet`.
    ///
    /// For specific error handling of individual tasks, you should call `join_next`
    /// in a loop with your desired handling.
    pub async fn join_all(mut self) -> Vec<T> {
        let mut output = Vec::new();

        while let Some(res) = self.join_next().await {
            match res {
                Ok(t) => output.push(t),
                Err(err) if err.is_panic() => panic::resume_unwind(err.into_panic()),
                Err(err) => panic!("{err}"),
            }
        }
        output
    }

    /// Aborts all tasks on this `JoinSet`.
    ///
    /// This does not remove the tasks from the `JoinSet`. To wait for the tasks to complete
    /// cancellation, you should call `join_next` in a loop until the `JoinSet` is empty.
    pub fn abort_all(&mut self) {
        self.inner.for_each(|jh| jh.abort());
    }

    /// Removes all tasks from this `JoinSet` without aborting them.
    ///
    /// The tasks removed by this call will continue to run in the background even if the `JoinSet`
    /// is dropped.

Review comment (bug):
I think the wording could be improved a bit. For example:
```suggestion
    /// This a convenience method that is equivalent to calling [`join_next`] in
    /// a loop. If any tasks on the `JoinSet` fail with an error, then this call
    /// to `join_all` will panic and all remaining tasks on the `JoinSet` are
    /// [cancelled]. To handle errors in any other way, manually call `join_next`
    /// in a loop.
    ///
    /// [`join_next`]: Self::join_next
    /// [cancelled]: crate::task#cancellation
```
It would also be nice with an example. For example, you could adjust one of the examples from the top of this file to use `join_all`. I also think we should have an example that shows a manual loop using `join_next`, explaining that `join_all` is equivalent to that loop.


Code after:
            }
        }
    }

    /// Aborts all tasks and waits for them to finish shutting down.
    ///
    /// Calling this method is equivalent to calling [`abort_all`] and then calling [`join_next`] in
    /// a loop until it returns `None`.
    ///
    /// This method ignores any panics in the tasks shutting down. When this call returns, the
    /// `JoinSet` will be empty.
    ///
    /// [`abort_all`]: fn@Self::abort_all
    /// [`join_next`]: fn@Self::join_next
    pub async fn shutdown(&mut self) {
        self.abort_all();
        while self.join_next().await.is_some() {}
    }

    /// Awaits the completion of all tasks in this `JoinSet`, returning a vector of their results.
    ///
    /// The results will be stored in the order they completed not the order they were spawned.
    /// This is a convenience method that is equivalent to calling [`join_next`] in
    /// a loop. If any tasks on the `JoinSet` fail with an [`JoinError`], then this call
    /// to `join_all` will panic and all remaining tasks on the `JoinSet` are
    /// cancelled. To handle errors in any other way, manually call [`join_next`]
    /// in a loop.
    ///
    /// # Examples
    ///
    /// Spawn multiple tasks and `join_all` them.
    ///
    /// ```
    /// use tokio::task::JoinSet;
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let mut set = JoinSet::new();
    ///
    ///     for i in 0..3 {
    ///        set.spawn(async move {
    ///            tokio::time::sleep(Duration::from_secs(3 - i)).await;
    ///            i
    ///        });
    ///     }   
    ///
    ///     let output = set.join_all().await;  
    ///     assert_eq!(output, vec![2, 1, 0]);
    /// }
    /// ```