diff --git a/src/runnable.rs b/src/runnable.rs index b72c067..a2efe6c 100644 --- a/src/runnable.rs +++ b/src/runnable.rs @@ -720,6 +720,32 @@ impl Runnable { &self.header_with_metadata().metadata } + /// Returns `true` if the [`Task`] handle has been dropped or cancelled. + /// + /// # Examples + /// + /// ``` + /// // A function that schedules the task when it gets woken up. + /// let (s, r) = flume::unbounded(); + /// let schedule = move |runnable| s.send(runnable).unwrap(); + /// + /// // Create a task with a simple future and the schedule function. + /// let (runnable, task) = async_task::spawn(async { 1 + 2 }, schedule); + /// + /// // The task is not cancelled initially. + /// assert!(!runnable.is_cancelled()); + /// + /// // Drop the `Task` handle to cancel the task. + /// drop(task); + /// + /// // The task is now cancelled. + /// assert!(runnable.is_cancelled()); + /// # runnable.run(); + /// ``` + pub fn is_cancelled(&self) -> bool { + self.header().state.load(Ordering::Acquire) & CLOSED != 0 + } + /// Schedules the task. /// /// This is a convenience method that passes the [`Runnable`] to the schedule function. diff --git a/tests/is_cancelled.rs b/tests/is_cancelled.rs new file mode 100644 index 0000000..428c48c --- /dev/null +++ b/tests/is_cancelled.rs @@ -0,0 +1,24 @@ +use std::pin::pin; + +use smol::future; + +#[test] +fn cancelled_after_task_drop() { + let f = async {}; + let (runnable, task) = async_task::spawn(f, |_| {}); + assert!(!runnable.is_cancelled()); + drop(task); + assert!(runnable.is_cancelled()); +} + +#[test] +fn cancelled_after_task_cancel() { + let f = async {}; + let (runnable, task) = async_task::spawn(f, |_| {}); + + assert!(!runnable.is_cancelled()); + + let mut cancel_fut = pin!(task.cancel()); + assert!(future::block_on(future::poll_once(&mut cancel_fut)).is_none()); + assert!(runnable.is_cancelled()); +}