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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
//! This crate implements an event which executes registered event handlers //! concurrently. Additionally, each handler is assigned an ID with which it //! can be referenced after creation. This allows for associated state for each //! event handler. //! //! The system was setup to be resistant to adversarial code. In particular, //! IDs are assigned randomly with sufficiently many bits to be unfeasable to //! guess. As a consequence, efficiency may suffer. Particularly the IDs are //! larger than they would need to be if assigned sequentially. //! //! # Important Note //! //! We provide no guarantees as the security properties were not rigorously //! verified. Do not use in critical systems without further investigation! //! //! # Example //! //! This is a simple usage scenarion with a custom event handler. //! //! ``` //! use concurrent_event::Event; //! use concurrent_event::handler::EventHandler; //! //! struct Printer; //! //! impl EventHandler<&str> for Printer { //! fn on_event(&mut self, arg: &str) { //! print!("{}", arg); //! } //! } //! //! let mut event = Event::<&str, Printer>::new(); //! event.emit("Hello, World!"); //! ``` //! //! In the `handler` package, default implementation for stateless and stateful //! event handlers can be found, which take a closure at construction. use std::collections::HashMap; use std::marker::PhantomData; use crossbeam::thread; use crate::id::HandlerId; use crate::handler::EventHandler; pub mod id; pub mod handler; /// An event manages multiple handlers which can be registered. /// /// # Type Parameters /// /// * `A`: The type of event arguments which are distributed to the handlers. /// * `H`: The type of event handlers which can be registered with this event. /// To allow for different types, use `Box<dyn EventHandler<...>>`. pub struct Event<A: Copy + Send, H: EventHandler<A>> { arg_type: PhantomData<A>, handlers: HashMap<HandlerId, H> } impl<A: Copy + Send, H: EventHandler<A>> Event<A, H> { /// Creates a new event without handlers. pub fn new() -> Event<A, H> { Event { arg_type: PhantomData, handlers: HashMap::new() } } /// Emits an event, invoking all currently registered handlers in parallel. /// If all event handlers terminated without panicking, `true` is returned. /// If any event handler panics, `false` is returned. /// /// # Parameters /// /// * `arg`: The event argument to dispatch. pub fn emit(&mut self, arg: A) -> bool { thread::scope(|s| { for handler in self.handlers.values_mut() { s.spawn(move |_| handler.on_event(arg)); } }).is_ok() } /// Adds an event handler to notify for future events. A handler ID is /// returned, which can be used to identify the handler later. /// /// # Parameters /// /// * `handler`: The event handler to register. pub fn add_handler(&mut self, handler: H) -> HandlerId { let id = HandlerId::new(); self.handlers.insert(id, handler); id } /// Gets a reference to the event handler registered under the given ID /// wrapped in a `Some` option variant. If no such handler is registered, /// `None` is returned. /// /// # Parameters /// /// * `id`: The handler ID for which to get the associated event handler. pub fn get_handler(&self, id: HandlerId) -> Option<&H> { self.handlers.get(&id) } } impl<'a, A: Copy + Send> Event<A, Box<dyn EventHandler<A> + 'a>> { /// Adds an event handler wrapped into a box to this event. This is mainly /// syntactic sugar for `event.add_handler(Box::new(handler))`. /// /// # Parameters /// /// * `handler`: The event handler to wrap in a box and register with this /// event. pub fn add_handler_boxed(&'a mut self, handler: impl EventHandler<A> + 'a) -> HandlerId { self.add_handler(Box::new(handler)) } } #[cfg(test)] mod test;