1use std::fmt;
2use std::sync::Arc;
3
4pub struct Callback<T: 'static> {
12 f: Arc<dyn Fn(T) + Send + Sync>,
13}
14
15impl<T: 'static> Callback<T> {
16 pub fn new(f: impl Fn(T) + Send + Sync + 'static) -> Self {
18 Self { f: Arc::new(f) }
19 }
20
21 pub fn call(&self, arg: T) {
23 (self.f)(arg);
24 }
25}
26
27impl<T: 'static> Clone for Callback<T> {
28 fn clone(&self) -> Self {
29 Self {
30 f: Arc::clone(&self.f),
31 }
32 }
33}
34
35impl<T: 'static> fmt::Debug for Callback<T> {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.write_str("Callback(..)")
38 }
39}
40
41impl<T: 'static> PartialEq for Callback<T> {
42 fn eq(&self, other: &Self) -> bool {
43 Arc::ptr_eq(&self.f, &other.f)
44 }
45}
46
47pub type ActionCallback = Callback<()>;
49
50pub type BoolCallback = Callback<bool>;
52
53pub type StringCallback = Callback<String>;
55
56pub type IndexCallback = Callback<usize>;
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use std::sync::atomic::{AtomicBool, Ordering};
63
64 #[test]
65 fn callback_call() {
66 let called = Arc::new(AtomicBool::new(false));
67 let called_clone = Arc::clone(&called);
68
69 let cb = Callback::new(move |_: ()| {
70 called_clone.store(true, Ordering::SeqCst);
71 });
72
73 cb.call(());
74 assert!(called.load(Ordering::SeqCst));
75 }
76
77 #[test]
78 fn callback_clone() {
79 let cb = Callback::new(|x: i32| {
80 let _ = x;
81 });
82 let cb2 = cb.clone();
83 assert_eq!(cb, cb2);
84 }
85
86 #[test]
87 fn callback_debug() {
88 let cb = Callback::new(|_: ()| {});
89 assert_eq!(format!("{:?}", cb), "Callback(..)");
90 }
91
92 #[test]
93 fn callback_with_value() {
94 let received = Arc::new(std::sync::Mutex::new(String::new()));
95 let received_clone = Arc::clone(&received);
96
97 let cb = StringCallback::new(move |val: String| {
98 *received_clone.lock().unwrap() = val;
99 });
100
101 cb.call("hello".to_string());
102 assert_eq!(*received.lock().unwrap(), "hello");
103 }
104}