async_event_rs/
lib.rs

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