use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
#[derive(Clone, Debug, Default)]
pub struct CancelToken {
flag: Arc<AtomicBool>,
}
impl CancelToken {
pub fn new() -> Self {
Self {
flag: Arc::new(AtomicBool::new(false)),
}
}
pub fn cancel(&self) {
self.flag.store(true, Ordering::SeqCst);
}
pub fn is_cancelled(&self) -> bool {
self.flag.load(Ordering::SeqCst)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fresh_token_is_not_cancelled() {
let token = CancelToken::new();
assert!(!token.is_cancelled());
}
#[test]
fn cancel_is_observed() {
let token = CancelToken::new();
token.cancel();
assert!(token.is_cancelled());
}
#[test]
fn cancel_is_idempotent() {
let token = CancelToken::new();
token.cancel();
token.cancel();
assert!(token.is_cancelled());
}
#[test]
fn clones_share_the_same_flag() {
let token = CancelToken::new();
let clone = token.clone();
clone.cancel();
assert!(token.is_cancelled());
}
#[test]
fn cancel_crosses_thread_boundary() {
let token = CancelToken::new();
let remote = token.clone();
let handle = std::thread::spawn(move || {
remote.cancel();
});
handle.join().expect("canceller thread joins");
assert!(token.is_cancelled());
}
}