Skip to main content

ignis_events/
event.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3use std::sync::Mutex;
4
5type Callback<T> = dyn Fn(&T) + Send + Sync + 'static;
6
7#[derive(Default)]
8struct EventInner<T> {
9    callbacks: Mutex<HashMap<usize, Arc<Callback<T>>>>,
10    next_id: Mutex<usize>,
11}
12
13/// A struct which represents some event.
14///
15/// Generic parameter `T` is a type of argument which callbacks accept.
16#[derive(Clone, Default)]
17pub struct Event<T> {
18    inner: Arc<EventInner<T>>,
19}
20
21impl<T> Event<T> {
22    /// Creates a new instance of an event.
23    pub fn new() -> Self {
24        Self {
25            inner: Arc::new(EventInner {
26                callbacks: Mutex::new(HashMap::new()),
27                next_id: Mutex::new(0),
28            }),
29        }
30    }
31
32    /// Registers the provided callback to invoke when the event is emitted.
33    ///
34    /// Returns an ID which can be used to unregister the callback using
35    /// [`disconnect`][Self::disconnect].
36    pub fn connect<F>(&self, callback: F) -> usize
37    where
38        F: Fn(&T) + Send + Sync + 'static,
39    {
40        let callback_id = {
41            let mut next_id = self.inner.next_id.lock().unwrap();
42            let id = *next_id;
43            *next_id += 1;
44            id
45        };
46
47        self.inner
48            .callbacks
49            .lock()
50            .unwrap()
51            .insert(callback_id, Arc::new(callback));
52
53        callback_id
54    }
55
56    /// Emits the event.
57    ///
58    /// It calls all callbacks with `&T` as the argument.
59    pub fn emit(&self, value: &T) {
60        let callbacks = {
61            let map = self.inner.callbacks.lock().unwrap();
62            map.values().cloned().collect::<Vec<_>>()
63        };
64
65        for callback in callbacks {
66            callback(value)
67        }
68    }
69
70    /// Unregister the callback by its ID.
71    pub fn disconnect(&self, handle: usize) {
72        self.inner.callbacks.lock().unwrap().remove(&handle);
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn test_emit() {
82        let event = Event::new();
83        let received = Arc::new(Mutex::new(None));
84
85        let received_clone = Arc::clone(&received);
86
87        event.connect(move |value: &i32| {
88            *received_clone.lock().unwrap() = Some(*value);
89        });
90
91        event.emit(&67);
92
93        assert_eq!(*received.lock().unwrap(), Some(67));
94    }
95}