use tokio_util::sync::CancellationToken;
pub use tokio_util::sync::WaitForCancellationFuture;
#[derive(Clone, Debug, Default)]
pub struct Cancellation {
token: CancellationToken,
}
impl Cancellation {
pub fn new() -> Self {
Self::default()
}
pub fn child(&self) -> Self {
Self {
token: self.token.child_token(),
}
}
pub fn cancel(&self) {
self.token.cancel();
}
pub fn is_cancelled(&self) -> bool {
self.token.is_cancelled()
}
pub fn cancelled(&self) -> WaitForCancellationFuture<'_> {
self.token.cancelled()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cancel_marks_token_as_cancelled() {
let cancellation = Cancellation::new();
cancellation.cancel();
assert!(cancellation.is_cancelled());
cancellation.cancel();
assert!(cancellation.is_cancelled());
}
#[tokio::test]
async fn cancelled_on_already_cancelled_completes_immediately() {
let cancellation = Cancellation::new();
cancellation.cancel();
cancellation.cancelled().await;
}
#[test]
fn child_cancel_does_not_affect_parent() {
let parent = Cancellation::new();
let child = parent.child();
child.cancel();
assert!(child.is_cancelled());
assert!(!parent.is_cancelled());
}
#[test]
fn child_cancelled_by_parent() {
let parent = Cancellation::new();
let child = parent.child();
parent.cancel();
assert!(parent.is_cancelled());
assert!(child.is_cancelled());
}
#[test]
fn child_outlives_dropped_parent() {
let child = {
let parent = Cancellation::new();
let child = parent.child();
parent.cancel();
child
};
assert!(child.is_cancelled());
}
#[test]
fn deeply_nested_children_propagate() {
let root = Cancellation::new();
let level1 = root.child();
let level2 = level1.child();
let level3 = level2.child();
root.cancel();
assert!(root.is_cancelled());
assert!(level1.is_cancelled());
assert!(level2.is_cancelled());
assert!(level3.is_cancelled());
}
#[test]
fn default_creates_uncancelled_token() {
let cancellation = Cancellation::default();
assert!(!cancellation.is_cancelled());
}
#[test]
fn new_creates_uncancelled_token() {
let cancellation = Cancellation::new();
assert!(!cancellation.is_cancelled());
}
#[test]
fn trait_send() {
fn assert_send<T: Send>() {}
assert_send::<Cancellation>();
}
#[test]
fn trait_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Cancellation>();
}
#[test]
fn trait_unpin() {
fn assert_unpin<T: Unpin>() {}
assert_unpin::<Cancellation>();
}
}