concinnity_engine/
shutdown.rs1use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8#[derive(Debug, Clone, Default)]
11pub struct ShutdownToken(Arc<AtomicBool>);
12
13impl ShutdownToken {
14 pub fn new() -> Self {
16 Self::default()
17 }
18
19 pub fn cancel(&self) {
21 self.0.store(true, Ordering::Release);
22 }
23
24 pub fn is_cancelled(&self) -> bool {
26 self.0.load(Ordering::Acquire)
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 #[test]
35 fn starts_uncancelled_and_sticks_once_cancelled() {
36 let token = ShutdownToken::new();
37 assert!(!token.is_cancelled());
38 token.cancel();
39 assert!(token.is_cancelled());
40 token.cancel();
41 assert!(token.is_cancelled());
42 }
43
44 #[test]
45 fn clones_share_the_flag() {
46 let token = ShutdownToken::new();
47 let clone = token.clone();
48 clone.cancel();
49 assert!(token.is_cancelled());
50 }
51
52 #[test]
53 fn cancel_crosses_threads() {
54 let token = ShutdownToken::new();
55 let clone = token.clone();
56 std::thread::spawn(move || clone.cancel())
57 .join()
58 .expect("cancel thread panicked");
59 assert!(token.is_cancelled());
60 }
61}