1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use std::any::Any; use std::collections::HashMap; #[derive(Default)] pub struct EventBus<'a> { pub events: HashMap<&'a str, (&'a str, Box<dyn Fn(&mut dyn Any)>)> } unsafe impl<'a> Sync for EventBus<'a> {} unsafe impl<'a> Send for EventBus<'a> {} impl<'a> EventBus<'a> { pub fn subscribe<H, T>(&mut self, subscription_id: &'a str, kind: &'a str, handle: H) where H: Fn(&mut T) + 'static, T: Any, { let handle = Box::new(move |erased_data: &mut dyn Any| { let actual_data = erased_data .downcast_mut() .expect("Woops, I broke my invariant"); handle(actual_data); }); self.events.insert(subscription_id, (kind, handle)); } pub fn unsubscribe(&mut self, subscription_id: &str) -> Option<(&str, Box<dyn Fn(&mut dyn Any)>)> { self.events.remove(subscription_id) } pub fn unsubscribe_every(&mut self, kind: &str) { self.events.retain(|k, _| { k == &kind }); } pub fn publish(&self, kind: &str, data: &mut dyn Any) { for (lookup_event, lookup_handler) in self.events.values() { if lookup_event == &kind { lookup_handler(data); } } } pub fn publish_single(&self, subscription_id: &str, data: &mut dyn Any) -> bool { let res = self.events.get(subscription_id); if res.is_none() { return false; } let event_tuple = res.unwrap(); event_tuple.1(data); return true; } } #[cfg(test)] mod test { use super::*; struct TestEventData<'a> { cancelled: bool, message: &'a str, } #[test] fn test_subscribe() { let mut bus = EventBus::default(); bus.subscribe("test_sub", "test", |d: &mut TestEventData| { if !d.cancelled { println!("Message from the spaceport: {}", d.message); } }); bus.publish("test", &mut TestEventData { cancelled: false, message: "no enemy ships detected!" }); } }