async_event_rs/
lib.rs

1use futures::future::{FutureExt, JoinAll, LocalBoxFuture, join_all};
2use slab::Slab;
3use std::future::Future;
4
5/// Type alias for asynchronous event handlers.
6///
7/// This represents a boxed function that takes a reference to event arguments
8/// and returns a boxed local future that resolves to ().
9pub type AsyncEventHandler<'a, TEventArgs> = Box<dyn Fn(TEventArgs) -> LocalBoxFuture<'a, ()> + 'a>;
10
11/// An asynchronous event that can have multiple handlers attached to it.
12///
13/// This is similar to C#'s `event` keyword but designed for async/await patterns.
14/// Handlers are stored in a slab storage for efficient access by index.
15///
16/// # Examples
17///
18/// ```
19/// use async_event_rs::AsyncEvent;
20///
21/// #[derive(Debug, Copy, Clone, Eq, PartialEq)]
22/// struct EventArgs<'a> {
23///     id: u32,
24///     message: &'a str,
25/// }
26///
27/// # futures::executor::block_on(async {
28/// let mut event = AsyncEvent::<EventArgs>::new();
29/// event.add(|args| async move {
30///     println!("Event triggered with args: {:?}", args);
31///     assert_eq!(args, EventArgs {id: 0, message: ""});
32/// });
33///
34/// let arg = EventArgs {id: 0, message: ""};
35/// event.invoke_async(arg).await;
36/// # });
37/// ```
38pub struct AsyncEvent<'a, TEventArgs> {
39    handlers: Slab<AsyncEventHandler<'a, TEventArgs>>,
40}
41
42impl<'a, TEventArgs> Default for AsyncEvent<'a, TEventArgs> {
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48impl<'a, TEventArgs> AsyncEvent<'a, TEventArgs> {
49    /// Creates a new, empty AsyncEvent
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// use async_event_rs::AsyncEvent;
55    ///
56    /// # futures::executor::block_on(async {
57    /// let mut event: AsyncEvent<(i32, &str)> = AsyncEvent::new();
58    /// event.add(|args| async move {
59    ///     println!("Event triggered with args: {:?}", args);
60    ///     assert_eq!(args, (0, ""));
61    /// });
62    ///
63    /// event.invoke_async((0, "")).await;
64    /// # });
65    /// ```
66    pub fn new() -> Self {
67        Self {
68            handlers: Slab::new(),
69        }
70    }
71
72    /// Adds an event handler to the event.
73    ///
74    /// The handler should be a closure that accepts a reference to the event arguments
75    /// and returns a future. The future will be executed when the event is triggered.
76    ///
77    /// Returns a handle that can be used to remove the handler later.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use async_event_rs::AsyncEvent;
83    ///
84    /// # futures::executor::block_on(async {
85    /// let mut event = AsyncEvent::<()>::new();
86    /// let handle = event.add(|args| async move {
87    ///     println!("Event triggered");
88    /// });
89    /// # });
90    /// ```
91    pub fn add<F, Fut>(&mut self, handler: F) -> usize
92    where
93        F: Fn(TEventArgs) -> Fut + 'a,
94        Fut: Future<Output = ()> + 'a,
95    {
96        self.handlers
97            .insert(Box::new(move |arg| handler(arg).boxed_local()))
98    }
99
100    /// Removes an event handler using its handle.
101    ///
102    /// Returns `true` if the handler was found and removed, `false` otherwise.
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use async_event_rs::AsyncEvent;
108    ///
109    /// # futures::executor::block_on(async {
110    /// let mut event = AsyncEvent::<()>::new();
111    /// let handle = event.add(|args| async move {
112    ///     println!("Event triggered");
113    /// });
114    ///
115    /// assert!(event.remove(handle));
116    /// assert!(!event.remove(handle)); // Already removed
117    /// # });
118    /// ```
119    pub fn remove(&mut self, handle: usize) -> bool {
120        self.handlers.try_remove(handle).is_some()
121    }
122
123    /// Removes all event handlers.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use async_event_rs::AsyncEvent;
129    ///
130    /// # futures::executor::block_on(async {
131    /// let mut event = AsyncEvent::<()>::new();
132    /// event.add(|args| async move { println!("Handler 1"); });
133    /// event.add(|args| async move { println!("Handler 2"); });
134    ///
135    /// event.clear(); // Remove all handlers
136    /// # });
137    /// ```
138    pub fn clear(&mut self) {
139        self.handlers.clear();
140    }
141
142    /// Invokes all event handlers sequentially (one after another).
143    ///
144    /// Each handler is awaited before the next one is executed.
145    ///
146    /// # Examples
147    ///
148    /// ```
149    /// use async_event_rs::AsyncEvent;
150    ///
151    /// # futures::executor::block_on(async {
152    /// let mut event = AsyncEvent::new();
153    /// event.add(|args| async move { println!("Handler 1"); });
154    /// event.add(|args| async move { println!("Handler 2"); });
155    ///
156    /// event.invoke_async(()).await; // Execute all handlers in order
157    /// # });
158    /// ```
159    pub async fn invoke_async(&self, arg: TEventArgs)
160    where
161        TEventArgs: Clone,
162    {
163        for (_, handler) in self.handlers.iter() {
164            handler(arg.clone()).await;
165        }
166    }
167
168    /// Invokes all event handlers in parallel.
169    ///
170    /// All handlers are spawned concurrently and executed simultaneously.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// use async_event_rs::AsyncEvent;
176    ///
177    /// # futures::executor::block_on(async {
178    /// let mut event = AsyncEvent::new();
179    /// event.add(|args| async move { println!("Handler 1"); });
180    /// event.add(|args| async move { println!("Handler 2"); });
181    ///
182    /// event.invoke_parallel_async(()).await; // Execute all handlers in parallel
183    /// # });
184    /// ```
185    pub fn invoke_parallel_async(&self, arg: TEventArgs) -> JoinAll<impl Future<Output = ()> + 'a>
186    where
187        TEventArgs: Clone,
188    {
189        join_all(
190            self.handlers
191                .iter()
192                .map(|(_, handler)| handler(arg.clone())),
193        )
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200    use std::cell::RefCell;
201    use std::rc::Rc;
202
203    #[tokio::test]
204    async fn test_invoke_async() {
205        let counter = Rc::new(RefCell::new(0));
206        let mut event = AsyncEvent::new();
207
208        event.invoke_async(()).await;
209
210        event.add(|_| {
211            let counter = Rc::clone(&counter);
212            async move {
213                *counter.borrow_mut() += 1;
214            }
215        });
216
217        event.add(|_| {
218            let counter = Rc::clone(&counter);
219            async move {
220                *counter.borrow_mut() += 1;
221            }
222        });
223
224        event.invoke_async(()).await;
225        assert_eq!(*counter.borrow(), 2);
226    }
227
228    #[tokio::test]
229    async fn test_invoke_parallel_async() {
230        let log = Rc::new(RefCell::new(vec![]));
231        let mut event = AsyncEvent::new();
232
233        event.invoke_parallel_async(()).await;
234
235        for i in 0..3 {
236            let log = Rc::clone(&log);
237            event.add(move |_| {
238                let log = Rc::clone(&log);
239                async move {
240                    log.borrow_mut().push(i);
241                }
242            });
243        }
244
245        event.invoke_parallel_async(()).await;
246
247        let result = log.borrow().clone();
248        assert_eq!(result.len(), 3);
249        for i in 0..3 {
250            assert!(result.contains(&i));
251        }
252    }
253
254    #[tokio::test]
255    async fn test_remove_handler() {
256        let counter = Rc::new(RefCell::new(0));
257        let mut event = AsyncEvent::new();
258
259        let handle = event.add(|_| {
260            let counter = Rc::clone(&counter);
261            async move {
262                *counter.borrow_mut() += 1;
263            }
264        });
265
266        assert!(event.remove(handle));
267        event.invoke_async(()).await;
268
269        assert_eq!(*counter.borrow(), 0);
270    }
271
272    #[tokio::test]
273    async fn test_clear_handlers() {
274        let counter = Rc::new(RefCell::new(0));
275        let mut event = AsyncEvent::new();
276
277        for _ in 0..5 {
278            event.add(|_| {
279                let counter = Rc::clone(&counter);
280                async move {
281                    *counter.borrow_mut() += 1;
282                }
283            });
284        }
285
286        event.clear();
287        event.invoke_async(()).await;
288
289        assert_eq!(*counter.borrow(), 0);
290    }
291
292    #[tokio::test]
293    async fn test_add_handler_twice() {
294        let counter = Rc::new(RefCell::new(0));
295        let mut event = AsyncEvent::new();
296
297        let handler = |_| {
298            let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
299            async move {
300                *counter.borrow_mut() += 1;
301            }
302        };
303
304        event.add(handler);
305        event.add(handler);
306
307        event.invoke_async(()).await;
308        assert_eq!(*counter.borrow(), 2);
309    }
310
311    #[tokio::test]
312    async fn test_remove_handler_twice() {
313        let counter = Rc::new(RefCell::new(0));
314        let mut event = AsyncEvent::new();
315
316        let handle = event.add(|_| {
317            let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
318            async move {
319                *counter.borrow_mut() += 1;
320            }
321        });
322
323        assert!(event.remove(handle));
324        assert!(!event.remove(handle));
325
326        event.invoke_async(()).await;
327        assert_eq!(*counter.borrow(), 0);
328    }
329}