use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use tokio::sync::Notify;
#[derive(Clone, Debug, Default)]
pub struct CancelToken {
inner: Arc<Inner>,
}
#[derive(Debug)]
struct Inner {
cancelled: AtomicBool,
notify: Notify,
}
impl Default for Inner {
fn default() -> Self {
Self {
cancelled: AtomicBool::new(false),
notify: Notify::new(),
}
}
}
impl CancelToken {
#[must_use]
pub fn new() -> Self {
Self {
inner: Arc::new(Inner::default()),
}
}
pub fn cancel(&self) {
if !self.inner.cancelled.swap(true, Ordering::Relaxed) {
self.inner.notify.notify_waiters();
}
}
#[must_use]
pub fn is_cancelled(&self) -> bool {
self.inner.cancelled.load(Ordering::Relaxed)
}
pub fn cancelled(&self) -> impl std::future::Future<Output = ()> + Send + 'static {
let token = self.clone();
async move {
if token.is_cancelled() {
return;
}
loop {
token.inner.notify.notified().await;
if token.is_cancelled() {
return;
}
}
}
}
}