Skip to main content

k_event_system/
lib.rs

1/*!
2A very super simple event system, only three functions: subscribe, unsubscribe and publish. (and a singleton, never mind.)
3Supports async. (see `main-async` in examples)
4```rust
5let handle = event_system::EventSystem::singleton().subscribe(|x: &usize| println!("I am {}", x));
6event_system::EventSystem::singleton().publish(&4usize);
7
8event_system::EventSystem::singleton().subscribe(test);
9event_system::EventSystem::singleton().publish(&6usize);
10
11event_system::EventSystem::singleton().unsubscribe::<usize>(handle);
12event_system::EventSystem::singleton().publish(&8usize);
13
14event_system::EventSystem::singleton().subscribe(on_login);
15event_system::EventSystem::singleton().publish(&Login);
16
17fn test(i: &usize) {
18    println!("I am F {}", i);
19}
20
21// with no params, you have to create a struct to distinguish between events
22struct Login;
23
24fn on_login(_: &Login) {
25    println!("on login");
26}
27```
28```text
29Output:
30I am 4
31I am 6
32I am F 6
33I am F 8
34on login
35```
36*/
37
38use lazy_static::lazy_static;
39use lockfree::map::Map;
40use std::any::*;
41use std::sync::atomic::AtomicUsize;
42use std::sync::atomic::Ordering;
43use std::sync::{Arc, Mutex};
44
45struct Event {
46    id: usize,
47    pub(crate) callback: Arc<dyn Fn(&(dyn Any + Send + Sync)) + Send + Sync + 'static>,
48}
49
50pub struct EventSystem {
51    idx: AtomicUsize,
52    events: Map<TypeId, Mutex<Vec<Event>>>,
53}
54
55impl EventSystem {
56    pub fn singleton() -> &'static Self {
57        lazy_static! {
58            static ref SINGLETON: EventSystem = EventSystem {
59                idx: AtomicUsize::new(0),
60                events: Map::new()
61            };
62        };
63
64        &*SINGLETON
65    }
66
67    /// returns the id of the callback for unsubscribing
68    pub fn subscribe<T, F>(&self, callback: F) -> usize
69    where
70        T: 'static + Send + Sync,
71        F: Fn(&T) + Send + Sync + 'static,
72    {
73        let type_id = TypeId::of::<T>();
74        let list = if let Some(list) = self.events.get(&type_id) {
75            list
76        } else {
77            self.events.insert(type_id, Mutex::new(Vec::new()));
78            self.events.get(&type_id).unwrap()
79        };
80
81        let event = Event {
82            id: self.idx.fetch_add(1, Ordering::SeqCst),
83            callback: Arc::new(move |x: &(dyn Any + Send + Sync)| {
84                if let Some(val) = x.downcast_ref::<T>() {
85                    callback(val);
86                } else {
87                    println!(
88                        "Wrong type for callback {:?}, expect {:?}",
89                        type_name_of_val(x),
90                        type_name::<T>()
91                    );
92                }
93            }),
94        };
95        let id = event.id;
96        list.val().lock().unwrap().push(event);
97
98        id
99    }
100
101    pub fn unsubscribe<T>(&self, id: usize)
102    where
103        T: 'static + Send + Sync,
104    {
105        let type_id = TypeId::of::<T>();
106        if let Some(callbacks) = self.events.get(&type_id) {
107            callbacks.val().lock().unwrap().retain(|x| x.id != id);
108        }
109    }
110
111    pub fn publish<T: 'static + Send + Sync>(&self, arg: &T) {
112        let type_id = TypeId::of::<T>();
113        if let Some(callbacks) = self.events.get(&type_id) {
114            for event in callbacks.val().lock().unwrap().iter() {
115                (*event.callback)(arg);
116            }
117        } else {
118            println!("No callbacks for event {:?}", type_id);
119        }
120    }
121}