task: stabilise JoinMap (#7075)

This commit is contained in:
Conrad Ludgate
2025-08-03 07:58:28 +00:00
committed by GitHub
parent 9741c90f9f
commit 416e36b0df
5 changed files with 37 additions and 36 deletions
+3 -4
View File
@@ -21,7 +21,7 @@ categories = ["asynchronous"]
default = []
# Shorthand for enabling everything
full = ["codec", "compat", "io-util", "time", "net", "rt"]
full = ["codec", "compat", "io-util", "time", "net", "rt", "join-map"]
net = ["tokio/net"]
compat = ["futures-io"]
@@ -29,7 +29,8 @@ codec = []
time = ["tokio/time", "slab"]
io = []
io-util = ["io", "tokio/rt", "tokio/io-util"]
rt = ["tokio/rt", "tokio/sync", "futures-util", "hashbrown"]
rt = ["tokio/rt", "tokio/sync", "futures-util"]
join-map = ["rt", "hashbrown"]
__docs_rs = ["futures-util"]
@@ -43,8 +44,6 @@ futures-util = { version = "0.3.0", optional = true }
pin-project-lite = "0.2.11"
slab = { version = "0.4.4", optional = true } # Backs `DelayQueue`
tracing = { version = "0.1.29", default-features = false, features = ["std"], optional = true }
[target.'cfg(tokio_unstable)'.dependencies]
hashbrown = { version = "0.15.0", default-features = false, optional = true }
[dev-dependencies]
+3 -1
View File
@@ -45,9 +45,11 @@ cfg_io! {
cfg_rt! {
pub mod context;
pub mod task;
}
#[cfg(feature = "rt")]
pub mod task;
cfg_time! {
pub mod time;
}
+9 -14
View File
@@ -29,10 +29,6 @@ use tokio::task::{AbortHandle, Id, JoinError, JoinSet, LocalSet};
///
/// When the `JoinMap` is dropped, all tasks in the `JoinMap` are immediately aborted.
///
/// **Note**: This type depends on Tokio's [unstable API][unstable]. See [the
/// documentation on unstable features][unstable] for details on how to enable
/// Tokio's unstable features.
///
/// # Examples
///
/// Spawn multiple tasks and wait for them:
@@ -96,11 +92,9 @@ use tokio::task::{AbortHandle, Id, JoinError, JoinSet, LocalSet};
/// ```
///
/// [`JoinSet`]: tokio::task::JoinSet
/// [unstable]: tokio#unstable-features
/// [abort]: fn@Self::abort
/// [abort_matching]: fn@Self::abort_matching
/// [contains]: fn@Self::contains_key
#[cfg_attr(docsrs, doc(cfg(all(feature = "rt", tokio_unstable))))]
pub struct JoinMap<K, V, S = RandomState> {
/// A map of the [`AbortHandle`]s of the tasks spawned on this `JoinMap`,
/// indexed by their keys.
@@ -541,9 +535,9 @@ where
/// assert!(!map.abort("goodbye universe"));
/// # }
/// ```
pub fn abort<Q: ?Sized>(&mut self, key: &Q) -> bool
pub fn abort<Q>(&mut self, key: &Q) -> bool
where
Q: Hash + Eq,
Q: ?Sized + Hash + Eq,
K: Borrow<Q>,
{
match self.get_by_key(key) {
@@ -638,9 +632,9 @@ where
/// call to [`join_next`], this method will still return `true`.
///
/// [`join_next`]: fn@Self::join_next
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
Q: Hash + Eq,
Q: ?Sized + Hash + Eq,
K: Borrow<Q>,
{
self.get_by_key(key).is_some()
@@ -744,9 +738,9 @@ where
}
/// Look up a task in the map by its key, returning the key and abort handle.
fn get_by_key<'map, Q: ?Sized>(&'map self, key: &Q) -> Option<&'map (K, AbortHandle)>
fn get_by_key<'map, Q>(&'map self, key: &Q) -> Option<&'map (K, AbortHandle)>
where
Q: Hash + Eq,
Q: ?Sized + Hash + Eq,
K: Borrow<Q>,
{
let hash_builder = self.hashes_by_task.hasher();
@@ -774,9 +768,10 @@ where
/// Returns the hash for a given key.
#[inline]
fn hash_one<S: BuildHasher, Q: ?Sized>(hash_builder: &S, key: &Q) -> u64
fn hash_one<S, Q>(hash_builder: &S, key: &Q) -> u64
where
Q: Hash,
Q: ?Sized + Hash,
S: BuildHasher,
{
let mut hasher = hash_builder.build_hasher();
key.hash(&mut hasher);
+17 -12
View File
@@ -1,16 +1,21 @@
//! Extra utilities for spawning tasks
//!
//! This module is only available when the `rt` feature is enabled. Note that enabling the
//! `join-map` feature will automatically also enable the `rt` feature.
#[cfg(tokio_unstable)]
cfg_rt! {
mod spawn_pinned;
pub use spawn_pinned::LocalPoolHandle;
pub mod task_tracker;
pub use task_tracker::TaskTracker;
mod abort_on_drop;
pub use abort_on_drop::AbortOnDropHandle;
}
#[cfg(feature = "join-map")]
mod join_map;
mod spawn_pinned;
pub use spawn_pinned::LocalPoolHandle;
#[cfg(tokio_unstable)]
#[cfg_attr(docsrs, doc(cfg(all(tokio_unstable, feature = "rt"))))]
#[cfg(feature = "join-map")]
#[cfg_attr(docsrs, doc(cfg(feature = "join-map")))]
pub use join_map::{JoinMap, JoinMapKeys};
pub mod task_tracker;
pub use task_tracker::TaskTracker;
mod abort_on_drop;
pub use abort_on_drop::AbortOnDropHandle;
+5 -5
View File
@@ -1,5 +1,5 @@
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "rt", tokio_unstable))]
#![cfg(feature = "join-map")]
use std::panic::AssertUnwindSafe;
@@ -26,7 +26,7 @@ async fn test_with_sleep() {
map.detach_all();
assert_eq!(map.len(), 0);
assert!(matches!(map.join_next().await, None));
assert!(map.join_next().await.is_none());
for i in 0..10 {
map.spawn(i, async move {
@@ -45,7 +45,7 @@ async fn test_with_sleep() {
for was_seen in &seen {
assert!(was_seen);
}
assert!(matches!(map.join_next().await, None));
assert!(map.join_next().await.is_none());
// Do it again.
for i in 0..10 {
@@ -64,7 +64,7 @@ async fn test_with_sleep() {
for was_seen in &seen {
assert!(was_seen);
}
assert!(matches!(map.join_next().await, None));
assert!(map.join_next().await.is_none());
}
#[tokio::test]
@@ -250,7 +250,7 @@ async fn join_map_coop() {
loop {
match map.join_next().now_or_never() {
Some(Some((key, Ok(i)))) => assert_eq!(key, i),
Some(Some((key, Err(err)))) => panic!("failed[{}]: {}", key, err),
Some(Some((key, Err(err)))) => panic!("failed[{key}]: {err}"),
None => {
coop_count += 1;
tokio::task::yield_now().await;