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}