Skip to content

Commit e4a39d2

Browse files
authored
sync: add CancellationToken::run_until_cancelled_owned (#7081)
1 parent afd3678 commit e4a39d2

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

tokio-util/src/sync/cancellation_token.rs

+16
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,22 @@ impl CancellationToken {
287287
}
288288
.await
289289
}
290+
291+
/// Runs a future to completion and returns its result wrapped inside of an `Option`
292+
/// unless the `CancellationToken` is cancelled. In that case the function returns
293+
/// `None` and the future gets dropped.
294+
///
295+
/// The function takes self by value and returns a future that owns the token.
296+
///
297+
/// # Cancel safety
298+
///
299+
/// This method is only cancel safe if `fut` is cancel safe.
300+
pub async fn run_until_cancelled_owned<F>(self, fut: F) -> Option<F::Output>
301+
where
302+
F: Future,
303+
{
304+
self.run_until_cancelled(fut).await
305+
}
290306
}
291307

292308
// ===== impl WaitForCancellationFuture =====

tokio-util/tests/sync_cancellation_token.rs

+55
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,58 @@ fn run_until_cancelled_test() {
493493
);
494494
}
495495
}
496+
497+
#[test]
498+
fn run_until_cancelled_owned_test() {
499+
let (waker, _) = new_count_waker();
500+
501+
{
502+
let token = CancellationToken::new();
503+
let to_cancel = token.clone();
504+
505+
let takes_ownership = move |token: CancellationToken| {
506+
token.run_until_cancelled_owned(std::future::pending::<()>())
507+
};
508+
509+
let fut = takes_ownership(token);
510+
pin!(fut);
511+
512+
assert_eq!(
513+
Poll::Pending,
514+
fut.as_mut().poll(&mut Context::from_waker(&waker))
515+
);
516+
517+
to_cancel.cancel();
518+
519+
assert_eq!(
520+
Poll::Ready(None),
521+
fut.as_mut().poll(&mut Context::from_waker(&waker))
522+
);
523+
}
524+
525+
{
526+
let (tx, rx) = oneshot::channel::<()>();
527+
528+
let token = CancellationToken::new();
529+
let takes_ownership = move |token: CancellationToken, rx: oneshot::Receiver<()>| {
530+
token.run_until_cancelled_owned(async move {
531+
rx.await.unwrap();
532+
42
533+
})
534+
};
535+
let fut = takes_ownership(token, rx);
536+
pin!(fut);
537+
538+
assert_eq!(
539+
Poll::Pending,
540+
fut.as_mut().poll(&mut Context::from_waker(&waker))
541+
);
542+
543+
tx.send(()).unwrap();
544+
545+
assert_eq!(
546+
Poll::Ready(Some(42)),
547+
fut.as_mut().poll(&mut Context::from_waker(&waker))
548+
);
549+
}
550+
}

0 commit comments

Comments
 (0)