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 invoked 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    /// let mut event: AsyncEvent<()> = AsyncEvent::new();
57    /// ```
58    pub fn new() -> Self {
59        Self {
60            handlers: Slab::new(),
61        }
62    }
63
64    /// Adds an event handler to the event.
65    ///
66    /// The handler should be a closure that accepts a reference to the event arguments
67    /// and returns a future. The future will be executed when the event is invoked.
68    ///
69    /// Returns a handle that can be used to remove the handler later.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use async_event_rs::AsyncEvent;
75    ///
76    /// # futures::executor::block_on(async {
77    /// let mut event = AsyncEvent::<()>::new();
78    /// let handle = event.add(|args| async move {
79    ///     println!("Event invoked");
80    /// });
81    /// # });
82    /// ```
83    pub fn add<F, Fut>(&mut self, handler: F) -> usize
84    where
85        F: Fn(TEventArgs) -> Fut + 'a,
86        Fut: Future<Output = ()> + 'a,
87    {
88        self.handlers
89            .insert(Box::new(move |arg| handler(arg).boxed_local()))
90    }
91
92    /// Removes an event handler using its handle.
93    ///
94    /// Returns `true` if the handler was found and removed, `false` otherwise.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// use async_event_rs::AsyncEvent;
100    ///
101    /// # futures::executor::block_on(async {
102    /// let mut event = AsyncEvent::<()>::new();
103    /// let handle = event.add(|args| async move {
104    ///     println!("Event invoked");
105    /// });
106    ///
107    /// assert!(event.remove(handle));
108    /// assert!(!event.remove(handle)); // Already removed
109    /// # });
110    /// ```
111    pub fn remove(&mut self, handle: usize) -> bool {
112        self.handlers.try_remove(handle).is_some()
113    }
114
115    /// Removes all event handlers.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use async_event_rs::AsyncEvent;
121    ///
122    /// # futures::executor::block_on(async {
123    /// let mut event = AsyncEvent::<()>::new();
124    /// event.add(|args| async move { println!("Handler 1"); });
125    /// event.add(|args| async move { println!("Handler 2"); });
126    ///
127    /// event.clear(); // Remove all handlers
128    /// # });
129    /// ```
130    pub fn clear(&mut self) {
131        self.handlers.clear();
132    }
133
134    /// Invokes all event handlers sequentially (one after another).
135    ///
136    /// Each handler is awaited before the next one is executed.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use async_event_rs::AsyncEvent;
142    ///
143    /// # futures::executor::block_on(async {
144    /// let mut event = AsyncEvent::new();
145    /// event.add(|args| async move { println!("Handler 1"); });
146    /// event.add(|args| async move { println!("Handler 2"); });
147    ///
148    /// event.invoke_async(()).await; // Execute all handlers in order
149    /// # });
150    /// ```
151    pub async fn invoke_async(&self, arg: TEventArgs)
152    where
153        TEventArgs: Clone,
154    {
155        for (_, handler) in self.handlers.iter() {
156            handler(arg.clone()).await;
157        }
158    }
159
160    /// Invokes all event handlers in parallel.
161    ///
162    /// All handlers are spawned concurrently and executed simultaneously.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use async_event_rs::AsyncEvent;
168    ///
169    /// # futures::executor::block_on(async {
170    /// let mut event = AsyncEvent::new();
171    /// event.add(|args| async move { println!("Handler 1"); });
172    /// event.add(|args| async move { println!("Handler 2"); });
173    ///
174    /// event.invoke_parallel_async(()).await; // Execute all handlers in parallel
175    /// # });
176    /// ```
177    pub fn invoke_parallel_async(&self, arg: TEventArgs) -> JoinAll<impl Future<Output = ()> + 'a>
178    where
179        TEventArgs: Clone,
180    {
181        join_all(
182            self.handlers
183                .iter()
184                .map(|(_, handler)| handler(arg.clone())),
185        )
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192    use std::cell::RefCell;
193    use std::rc::Rc;
194
195    #[tokio::test]
196    async fn test_invoke_async() {
197        let counter = Rc::new(RefCell::new(0));
198        let mut event = AsyncEvent::new();
199
200        event.invoke_async(()).await;
201
202        event.add(|_| {
203            let counter = Rc::clone(&counter);
204            async move {
205                *counter.borrow_mut() += 1;
206            }
207        });
208
209        event.add(|_| {
210            let counter = Rc::clone(&counter);
211            async move {
212                *counter.borrow_mut() += 1;
213            }
214        });
215
216        event.invoke_async(()).await;
217        event.invoke_async(()).await;
218        assert_eq!(*counter.borrow(), 4);
219    }
220
221    #[tokio::test]
222    async fn test_invoke_parallel_async() {
223        let log = Rc::new(RefCell::new(vec![]));
224        let mut event = AsyncEvent::new();
225
226        event.invoke_parallel_async(()).await;
227
228        for i in 0..3 {
229            let log = Rc::clone(&log);
230            event.add(move |_| {
231                let log = Rc::clone(&log);
232                async move {
233                    log.borrow_mut().push(i);
234                }
235            });
236        }
237
238        event.invoke_parallel_async(()).await;
239
240        let result = log.borrow().clone();
241        assert_eq!(result.len(), 3);
242        for i in 0..3 {
243            assert!(result.contains(&i));
244        }
245    }
246
247    #[tokio::test]
248    async fn test_remove_handler() {
249        let counter = Rc::new(RefCell::new(0));
250        let mut event = AsyncEvent::new();
251
252        let handle = event.add(|_| {
253            let counter = Rc::clone(&counter);
254            async move {
255                *counter.borrow_mut() += 1;
256            }
257        });
258
259        assert!(event.remove(handle));
260        event.invoke_async(()).await;
261
262        assert_eq!(*counter.borrow(), 0);
263    }
264
265    #[tokio::test]
266    async fn test_clear_handlers() {
267        let counter = Rc::new(RefCell::new(0));
268        let mut event = AsyncEvent::new();
269
270        for _ in 0..5 {
271            event.add(|_| {
272                let counter = Rc::clone(&counter);
273                async move {
274                    *counter.borrow_mut() += 1;
275                }
276            });
277        }
278
279        event.clear();
280        event.invoke_async(()).await;
281
282        assert_eq!(*counter.borrow(), 0);
283    }
284
285    #[tokio::test]
286    async fn test_add_handler_twice() {
287        let counter = Rc::new(RefCell::new(0));
288        let mut event = AsyncEvent::new();
289
290        let handler = |_| {
291            let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
292            async move {
293                *counter.borrow_mut() += 1;
294            }
295        };
296
297        event.add(handler);
298        event.add(handler);
299
300        event.invoke_async(()).await;
301        assert_eq!(*counter.borrow(), 2);
302    }
303
304    #[tokio::test]
305    async fn test_remove_handler_twice() {
306        let counter = Rc::new(RefCell::new(0));
307        let mut event = AsyncEvent::new();
308
309        let handle = event.add(|_| {
310            let counter: Rc<RefCell<i32>> = Rc::clone(&counter);
311            async move {
312                *counter.borrow_mut() += 1;
313            }
314        });
315
316        assert!(event.remove(handle));
317        assert!(!event.remove(handle));
318
319        event.invoke_async(()).await;
320        assert_eq!(*counter.borrow(), 0);
321    }
322}