1use std::fmt;
9use std::sync::Arc;
10
11pub struct Hook<A>(Option<Callback<A>>);
13
14type Callback<A> = Arc<dyn Fn(&A) + Send + Sync>;
15
16impl<A> Hook<A> {
17 pub const fn none() -> Self {
19 Self(None)
20 }
21
22 pub fn set(&mut self, f: Option<impl Fn(&A) + Send + Sync + 'static>) {
24 self.0 = f.map(|f| Arc::new(f) as Callback<A>);
25 }
26
27 pub fn is_set(&self) -> bool {
29 self.0.is_some()
30 }
31
32 pub fn fire(&self, arg: &A) {
34 if let Some(f) = &self.0 {
35 f(arg);
36 }
37 }
38}
39
40impl<A> Default for Hook<A> {
41 fn default() -> Self {
42 Self::none()
43 }
44}
45
46impl<A> Clone for Hook<A> {
47 fn clone(&self) -> Self {
48 Self(self.0.clone())
49 }
50}
51
52impl<A> fmt::Debug for Hook<A> {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 f.write_str(if self.0.is_some() {
55 "Hook(set)"
56 } else {
57 "Hook(none)"
58 })
59 }
60}
61
62#[derive(Clone, Debug, PartialEq, Eq)]
65pub struct SwitchFailure {
66 pub name: String,
68 pub message: String,
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use std::sync::atomic::{AtomicU32, Ordering};
76
77 #[test]
78 fn hook_fires_until_removed() {
79 let n = Arc::new(AtomicU32::new(0));
80 let mut h = Hook::<u32>::none();
81 h.fire(&1);
82 let n2 = n.clone();
83 h.set(Some(move |v: &u32| {
84 n2.fetch_add(*v, Ordering::SeqCst);
85 }));
86 let copy = h.clone();
87 h.fire(&2);
88 copy.fire(&3);
89 assert_eq!(n.load(Ordering::SeqCst), 5);
90 h.set(None::<fn(&u32)>);
91 h.fire(&10);
92 assert_eq!(n.load(Ordering::SeqCst), 5);
93 }
94}