use std::sync::{Mutex, MutexGuard};
#[derive(Default)]
pub struct CancelAtom {
state: Mutex<AtomState>,
}
#[derive(Default)]
struct AtomState {
cancelled: bool,
heard: bool,
}
fn lock(m: &Mutex<AtomState>) -> MutexGuard<'_, AtomState> {
m.lock().unwrap_or_else(|e| e.into_inner())
}
impl CancelAtom {
pub fn new() -> Self {
Self::default()
}
pub fn cancel(&self) {
lock(&self.state).cancelled = true;
}
pub fn is_cancelled(&self) -> bool {
let mut s = lock(&self.state);
if s.cancelled {
s.heard = true;
}
s.cancelled
}
pub fn heard_cancel(&self) -> bool {
lock(&self.state).heard
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fresh_atom_is_not_cancelled() {
let a = CancelAtom::new();
assert!(!a.is_cancelled());
assert!(!a.heard_cancel());
}
#[test]
fn cancel_sets_flag_and_reading_marks_heard() {
let a = CancelAtom::new();
a.cancel();
assert!(!a.heard_cancel(), "not heard until read");
assert!(a.is_cancelled());
assert!(a.heard_cancel(), "reading a set flag marks it heard");
}
#[test]
fn repeated_cancel_is_idempotent() {
let a = CancelAtom::new();
a.cancel();
a.cancel();
assert!(a.is_cancelled());
}
}