1use std::sync::atomic::{AtomicBool, Ordering};
2use std::sync::{Arc, Condvar, Mutex};
3
4#[derive(Clone, Debug)]
5pub struct Cancellation(Arc<State>);
6
7#[derive(Debug)]
8struct State {
9 cancelled: AtomicBool,
10 event: Condvar,
11 lock: Mutex<()>,
12}
13
14impl Cancellation {
15 pub fn new() -> Self {
16 Self(Arc::new(State {
17 cancelled: AtomicBool::new(false),
18 event: Condvar::new(),
19 lock: Mutex::new(()),
20 }))
21 }
22
23 pub fn cancel(&self) {
24 let _guard = self.0.lock.lock().unwrap();
25 if !self.0.cancelled.swap(true, Ordering::Release) {
26 self.0.event.notify_all();
27 }
28 }
29
30 pub fn is_cancelled(&self) -> bool {
31 self.0.cancelled.load(Ordering::Acquire)
32 }
33
34 pub fn wait(&self) {
35 let guard = self.0.lock.lock().unwrap();
36 drop(
37 self.0
38 .event
39 .wait_while(guard, |_| !self.is_cancelled())
40 .unwrap(),
41 );
42 }
43
44 pub fn check(&self) -> crate::Result<()> {
45 if self.is_cancelled() {
46 Err(crate::Error::Cancelled)
47 } else {
48 Ok(())
49 }
50 }
51}
52
53impl Default for Cancellation {
54 fn default() -> Self {
55 Self::new()
56 }
57}