]> git.feebdaed.xyz Git - 0xmirror/tokio.git/commitdiff
sync: add `DropGuardRef` for `CancellationToken` (#7407)
authoryanyuxing <yuxing.bitcapybara@gmail.com>
Wed, 18 Jun 2025 08:25:41 +0000 (16:25 +0800)
committerGitHub <noreply@github.com>
Wed, 18 Jun 2025 08:25:41 +0000 (10:25 +0200)
tokio-util/src/sync/cancellation_token.rs
tokio-util/src/sync/cancellation_token/guard_ref.rs [new file with mode: 0644]
tokio-util/src/sync/mod.rs

index 85305de47c692b326874d6b4cd50d59e43efdd7c..64cff21997850fd94668507e1d9ce090ca84d4d4 100644 (file)
@@ -1,6 +1,7 @@
 //! An asynchronously awaitable `CancellationToken`.
 //! The token allows to signal a cancellation request to one or more tasks.
 pub(crate) mod guard;
+pub(crate) mod guard_ref;
 mod tree_node;
 
 use crate::loom::sync::Arc;
@@ -10,6 +11,7 @@ use core::pin::Pin;
 use core::task::{Context, Poll};
 
 use guard::DropGuard;
+use guard_ref::DropGuardRef;
 use pin_project_lite::pin_project;
 
 /// A token which can be used to signal a cancellation request to one or more
@@ -242,6 +244,14 @@ impl CancellationToken {
         DropGuard { inner: Some(self) }
     }
 
+    /// Creates a `DropGuardRef` for this token.
+    ///
+    /// Returned guard will cancel this token (and all its children) on drop
+    /// unless disarmed.
+    pub fn drop_guard_ref(&self) -> DropGuardRef<'_> {
+        DropGuardRef { inner: Some(self) }
+    }
+
     /// Runs a future to completion and returns its result wrapped inside of an `Option`
     /// unless the `CancellationToken` is cancelled. In that case the function returns
     /// `None` and the future gets dropped.
diff --git a/tokio-util/src/sync/cancellation_token/guard_ref.rs b/tokio-util/src/sync/cancellation_token/guard_ref.rs
new file mode 100644 (file)
index 0000000..b48fd19
--- /dev/null
@@ -0,0 +1,29 @@
+use crate::sync::CancellationToken;
+
+/// A wrapper for cancellation token which automatically cancels
+/// it on drop. It is created using `drop_guard_ref` method on the `CancellationToken`.
+///
+/// This is a `ref` version of `DropGuard`
+#[derive(Debug)]
+pub struct DropGuardRef<'a> {
+    pub(super) inner: Option<&'a CancellationToken>,
+}
+
+impl<'a> DropGuardRef<'a> {
+    /// Returns stored cancellation token and removes this drop guard instance
+    /// (i.e. it will no longer cancel token). Other guards for this token
+    /// are not affected.
+    pub fn disarm(mut self) -> &'a CancellationToken {
+        self.inner
+            .take()
+            .expect("`inner` can be only None in a destructor")
+    }
+}
+
+impl Drop for DropGuardRef<'_> {
+    fn drop(&mut self) {
+        if let Some(inner) = self.inner {
+            inner.cancel();
+        }
+    }
+}
index 1ae1b7ee45271cc5d43d72d30551429a6de07dee..28f2fbd2d6bfb27c017798f7ee5f64fd5b58dcc0 100644 (file)
@@ -2,7 +2,8 @@
 
 mod cancellation_token;
 pub use cancellation_token::{
-    guard::DropGuard, CancellationToken, WaitForCancellationFuture, WaitForCancellationFutureOwned,
+    guard::DropGuard, guard_ref::DropGuardRef, CancellationToken, WaitForCancellationFuture,
+    WaitForCancellationFutureOwned,
 };
 
 mod mpsc;