1use std::sync::Arc;
4use std::sync::atomic::{AtomicBool, Ordering};
5
6use crate::cancel::CancelToken;
7
8pub struct StopSignal(Box<dyn Fn() -> bool + Send>);
11
12impl StopSignal {
13 pub fn never() -> Self {
15 Self(Box::new(|| false))
16 }
17
18 pub fn from_fn(should_stop: impl Fn() -> bool + Send + 'static) -> Self {
19 Self(Box::new(should_stop))
20 }
21
22 pub fn should_stop(&self) -> bool {
23 (self.0)()
24 }
25}
26
27impl From<CancelToken> for StopSignal {
28 fn from(cancel: CancelToken) -> Self {
29 Self::from_fn(move || cancel.is_cancelled())
30 }
31}
32
33impl From<Stopper> for StopSignal {
34 fn from(stopper: Stopper) -> Self {
35 Self::from_fn(move || stopper.is_stopped())
36 }
37}
38
39#[derive(Clone, Debug, Default)]
42pub struct Stopper(Arc<AtomicBool>);
43
44impl Stopper {
45 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn stop(&self) {
50 self.0.store(true, Ordering::Release);
51 }
52
53 pub fn is_stopped(&self) -> bool {
54 self.0.load(Ordering::Acquire)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn never_stays_quiet() {
64 assert!(!StopSignal::never().should_stop());
65 }
66
67 #[test]
68 fn a_stopper_reaches_the_signal_through_a_clone() {
69 let stopper = Stopper::new();
70 let signal = StopSignal::from(stopper.clone());
71
72 assert!(!signal.should_stop());
73 stopper.stop();
74 assert!(signal.should_stop());
75 }
76
77 #[test]
78 fn a_cancel_token_reads_through() {
79 let cancel = CancelToken::new();
80 let signal = StopSignal::from(cancel.clone());
81
82 assert!(!signal.should_stop());
83 cancel.cancel();
84 assert!(signal.should_stop());
85 }
86}