concurrent_event/lib.rs
1//! This crate implements an event which executes registered event handlers
2//! concurrently. Additionally, each handler is assigned an ID with which it
3//! can be referenced after creation. This allows for associated state for each
4//! event handler.
5//!
6//! The system was setup to be resistant to adversarial code. In particular,
7//! IDs are assigned randomly with sufficiently many bits to be unfeasable to
8//! guess. As a consequence, efficiency may suffer. Particularly the IDs are
9//! larger than they would need to be if assigned sequentially.
10//!
11//! # Important Note
12//!
13//! We provide no guarantees as the security properties were not rigorously
14//! verified. Do not use in critical systems without further investigation!
15//!
16//! # Example
17//!
18//! This is a simple usage scenarion with a custom event handler.
19//!
20//! ```
21//! use concurrent_event::Event;
22//! use concurrent_event::handler::EventHandler;
23//!
24//! struct Printer;
25//!
26//! impl EventHandler<&str> for Printer {
27//! fn on_event(&mut self, arg: &str) {
28//! print!("{}", arg);
29//! }
30//! }
31//!
32//! let mut event = Event::<&str, Printer>::new();
33//! event.emit("Hello, World!");
34//! ```
35//!
36//! In the `handler` package, default implementation for stateless and stateful
37//! event handlers can be found, which take a closure at construction.
38
39use std::collections::HashMap;
40use std::marker::PhantomData;
41
42use crossbeam::thread;
43
44use crate::id::HandlerId;
45use crate::handler::EventHandler;
46
47pub mod id;
48pub mod handler;
49
50/// An event manages multiple handlers which can be registered.
51///
52/// # Type Parameters
53///
54/// * `A`: The type of event arguments which are distributed to the handlers.
55/// * `H`: The type of event handlers which can be registered with this event.
56/// To allow for different types, use `Box<dyn EventHandler<...>>`.
57pub struct Event<A: Copy + Send, H: EventHandler<A>> {
58 arg_type: PhantomData<A>,
59 handlers: HashMap<HandlerId, H>
60}
61
62impl<A: Copy + Send, H: EventHandler<A>> Event<A, H> {
63
64 /// Creates a new event without handlers.
65 pub fn new() -> Event<A, H> {
66 Event {
67 arg_type: PhantomData,
68 handlers: HashMap::new()
69 }
70 }
71
72 /// Emits an event, invoking all currently registered handlers in parallel.
73 /// If all event handlers terminated without panicking, `true` is returned.
74 /// If any event handler panics, `false` is returned.
75 ///
76 /// # Parameters
77 ///
78 /// * `arg`: The event argument to dispatch.
79 pub fn emit(&mut self, arg: A) -> bool {
80 thread::scope(|s| {
81 for handler in self.handlers.values_mut() {
82 s.spawn(move |_| handler.on_event(arg));
83 }
84 }).is_ok()
85 }
86
87 /// Adds an event handler to notify for future events. A handler ID is
88 /// returned, which can be used to identify the handler later.
89 ///
90 /// # Parameters
91 ///
92 /// * `handler`: The event handler to register.
93 pub fn add_handler(&mut self, handler: H) -> HandlerId {
94 let id = HandlerId::new();
95 self.handlers.insert(id, handler);
96 id
97 }
98
99 /// Gets a reference to the event handler registered under the given ID
100 /// wrapped in a `Some` option variant. If no such handler is registered,
101 /// `None` is returned.
102 ///
103 /// # Parameters
104 ///
105 /// * `id`: The handler ID for which to get the associated event handler.
106 pub fn get_handler(&self, id: HandlerId) -> Option<&H> {
107 self.handlers.get(&id)
108 }
109}
110
111impl<'a, A: Copy + Send> Event<A, Box<dyn EventHandler<A> + 'a>> {
112
113 /// Adds an event handler wrapped into a box to this event. This is mainly
114 /// syntactic sugar for `event.add_handler(Box::new(handler))`.
115 ///
116 /// # Parameters
117 ///
118 /// * `handler`: The event handler to wrap in a box and register with this
119 /// event.
120 pub fn add_handler_boxed(&'a mut self, handler: impl EventHandler<A> + 'a) -> HandlerId {
121 self.add_handler(Box::new(handler))
122 }
123}
124
125#[cfg(test)]
126mod test;