Skip to main content

scarab_plugin_api/events/
registry.rs

1//! Event registry for managing and dispatching events
2//!
3//! **DEPRECATED**: This legacy mutex-based registry is being replaced by pure Bevy ECS events.
4//!
5//! # Migration Path
6//!
7//! The `EventRegistry` pattern using `Arc<Mutex<EventRegistry>>` is deprecated in favor
8//! of typed Bevy events defined in `scarab-client/src/events/bevy_events.rs`.
9//!
10//! **Old pattern (deprecated):**
11//! ```ignore
12//! let registry = Arc::new(Mutex::new(EventRegistry::new()));
13//! registry.lock().unwrap().register(EventType::Bell, 100, "plugin", handler);
14//! registry.lock().unwrap().dispatch(&args);
15//! ```
16//!
17//! **New pattern (Bevy ECS):**
18//! ```ignore
19//! // In plugin setup:
20//! app.add_event::<BellEvent>();
21//!
22//! // In handler system:
23//! fn handle_bell(mut events: EventReader<BellEvent>) {
24//!     for event in events.read() {
25//!         // Handle bell event
26//!     }
27//! }
28//! ```
29//!
30//! See `crates/scarab-client/src/events/bevy_events.rs` for all available typed events.
31
32use super::{EventArgs, EventHandler, EventResult, EventType, HandlerEntry};
33use std::collections::HashMap;
34use std::sync::atomic::{AtomicU64, Ordering};
35
36/// Central registry for event handlers
37///
38/// **DEPRECATED**: Use Bevy ECS events instead. See module documentation for migration guide.
39///
40/// This registry uses `Arc<Mutex<>>` for thread synchronization, which is incompatible
41/// with Bevy's lock-free ECS architecture. The daemon still uses this for plugin-side
42/// event handling, but client-side code should use typed Bevy events.
43///
44/// # Migration Path
45///
46/// - **Daemon plugins**: Continue using `DaemonEventDispatcher` which wraps this registry
47/// - **Client code**: Use typed events from `scarab-client/src/events/bevy_events.rs`
48/// - **New code**: Always prefer Bevy events over this registry
49///
50/// # Thread Safety
51///
52/// The registry is NOT thread-safe by default. Wrap it in a `Mutex` or `RwLock`
53/// for concurrent access from multiple threads.
54#[deprecated(
55    since = "0.1.0",
56    note = "Use Bevy ECS events (scarab-client/src/events/bevy_events.rs) instead of Arc<Mutex<EventRegistry>>. \
57            See crates/scarab-plugin-api/src/events/registry.rs module docs for migration guide."
58)]
59pub struct EventRegistry {
60    /// Handlers for standard event types
61    handlers: HashMap<EventType, Vec<HandlerEntry>>,
62
63    /// Handlers for custom event types (by custom name)
64    custom_handlers: HashMap<String, Vec<HandlerEntry>>,
65
66    /// Next available handler ID (atomic for thread-safe ID generation)
67    next_handler_id: AtomicU64,
68}
69
70#[allow(deprecated)]
71impl EventRegistry {
72    /// Create a new empty event registry
73    pub fn new() -> Self {
74        Self {
75            handlers: HashMap::new(),
76            custom_handlers: HashMap::new(),
77            next_handler_id: AtomicU64::new(1),
78        }
79    }
80
81    /// Register a new event handler
82    ///
83    /// # Arguments
84    ///
85    /// * `event_type` - Type of event to listen for
86    /// * `priority` - Handler priority (higher values = called first)
87    /// * `plugin_name` - Name of the plugin registering this handler
88    /// * `handler` - The handler function
89    ///
90    /// # Returns
91    ///
92    /// A unique handler ID that can be used to unregister the handler later.
93    ///
94    /// # Example
95    ///
96    /// ```ignore
97    /// let id = registry.register(
98    ///     EventType::Bell,
99    ///     100,
100    ///     "my-plugin",
101    ///     Box::new(|args| {
102    ///         println!("Bell rang!");
103    ///         EventResult::Continue
104    ///     })
105    /// );
106    /// ```
107    pub fn register(
108        &mut self,
109        event_type: EventType,
110        priority: i32,
111        plugin_name: &str,
112        handler: EventHandler,
113    ) -> u64 {
114        let id = self.next_handler_id.fetch_add(1, Ordering::SeqCst);
115        let entry = HandlerEntry::new(id, plugin_name, priority, handler);
116
117        match event_type {
118            EventType::Custom(ref name) => {
119                let name = name.clone();
120                let handlers = self.custom_handlers.entry(name).or_insert_with(Vec::new);
121                handlers.push(entry);
122
123                // Sort by priority (descending)
124                handlers.sort_by(|a, b| b.priority.cmp(&a.priority));
125            }
126            _ => {
127                let handlers = self.handlers.entry(event_type).or_insert_with(Vec::new);
128                handlers.push(entry);
129
130                // Sort by priority (descending)
131                handlers.sort_by(|a, b| b.priority.cmp(&a.priority));
132            }
133        }
134
135        id
136    }
137
138    /// Unregister a handler by ID
139    ///
140    /// # Returns
141    ///
142    /// `true` if a handler was removed, `false` if no handler with that ID was found.
143    pub fn unregister(&mut self, handler_id: u64) -> bool {
144        // Search in standard handlers
145        for handlers in self.handlers.values_mut() {
146            if let Some(pos) = handlers.iter().position(|h| h.id == handler_id) {
147                handlers.remove(pos);
148                return true;
149            }
150        }
151
152        // Search in custom handlers
153        for handlers in self.custom_handlers.values_mut() {
154            if let Some(pos) = handlers.iter().position(|h| h.id == handler_id) {
155                handlers.remove(pos);
156                return true;
157            }
158        }
159
160        false
161    }
162
163    /// Unregister all handlers for a specific plugin
164    ///
165    /// # Returns
166    ///
167    /// The number of handlers removed.
168    pub fn unregister_plugin(&mut self, plugin_name: &str) -> usize {
169        let mut count = 0;
170
171        // Remove from standard handlers
172        for handlers in self.handlers.values_mut() {
173            let before = handlers.len();
174            handlers.retain(|h| h.plugin_name != plugin_name);
175            count += before - handlers.len();
176        }
177
178        // Remove from custom handlers
179        for handlers in self.custom_handlers.values_mut() {
180            let before = handlers.len();
181            handlers.retain(|h| h.plugin_name != plugin_name);
182            count += before - handlers.len();
183        }
184
185        count
186    }
187
188    /// Dispatch an event to all registered handlers
189    ///
190    /// Handlers are called in priority order (highest first). If any handler
191    /// returns `EventResult::Stop`, subsequent handlers are not called.
192    ///
193    /// # Returns
194    ///
195    /// A vector of all results returned by handlers (may be empty if no handlers
196    /// are registered or if an early handler stopped processing).
197    pub fn dispatch(&self, args: &EventArgs) -> Vec<EventResult> {
198        let handlers = match &args.event_type {
199            EventType::Custom(name) => self.custom_handlers.get(name).map(|h| h.as_slice()),
200            _ => self.handlers.get(&args.event_type).map(|h| h.as_slice()),
201        };
202
203        let Some(handlers) = handlers else {
204            return Vec::new();
205        };
206
207        let mut results = Vec::with_capacity(handlers.len());
208
209        for handler_entry in handlers {
210            let result = handler_entry.call(args);
211
212            // Check if we should stop processing
213            let should_stop = result.is_stop();
214            results.push(result);
215
216            if should_stop {
217                break;
218            }
219        }
220
221        results
222    }
223
224    /// Get all handlers for a specific event type
225    ///
226    /// Returns an empty slice if no handlers are registered for that event.
227    pub fn get_handlers(&self, event_type: &EventType) -> &[HandlerEntry] {
228        match event_type {
229            EventType::Custom(name) => self
230                .custom_handlers
231                .get(name)
232                .map(|h| h.as_slice())
233                .unwrap_or(&[]),
234            _ => self
235                .handlers
236                .get(event_type)
237                .map(|h| h.as_slice())
238                .unwrap_or(&[]),
239        }
240    }
241
242    /// Get the number of registered handlers for an event type
243    pub fn handler_count(&self, event_type: &EventType) -> usize {
244        self.get_handlers(event_type).len()
245    }
246
247    /// Get the total number of registered handlers across all events
248    pub fn total_handler_count(&self) -> usize {
249        let standard_count: usize = self.handlers.values().map(|v| v.len()).sum();
250        let custom_count: usize = self.custom_handlers.values().map(|v| v.len()).sum();
251        standard_count + custom_count
252    }
253
254    /// Clear all handlers for a specific event type
255    pub fn clear_event(&mut self, event_type: &EventType) {
256        match event_type {
257            EventType::Custom(name) => {
258                self.custom_handlers.remove(name);
259            }
260            _ => {
261                self.handlers.remove(event_type);
262            }
263        }
264    }
265
266    /// Clear all handlers from the registry
267    pub fn clear_all(&mut self) {
268        self.handlers.clear();
269        self.custom_handlers.clear();
270    }
271
272    /// Get a list of all event types that have registered handlers
273    pub fn registered_events(&self) -> Vec<EventType> {
274        let mut events: Vec<EventType> = self.handlers.keys().cloned().collect();
275
276        for custom_name in self.custom_handlers.keys() {
277            events.push(EventType::Custom(custom_name.clone()));
278        }
279
280        events
281    }
282}
283
284#[allow(deprecated)]
285impl Default for EventRegistry {
286    fn default() -> Self {
287        Self::new()
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294    use std::sync::{Arc, Mutex};
295
296    #[test]
297    fn test_registry_creation() {
298        let registry = EventRegistry::new();
299        assert_eq!(registry.total_handler_count(), 0);
300    }
301
302    #[test]
303    fn test_register_and_dispatch() {
304        let mut registry = EventRegistry::new();
305        let called = Arc::new(Mutex::new(false));
306        let called_clone = Arc::clone(&called);
307
308        let id = registry.register(
309            EventType::Bell,
310            100,
311            "test-plugin",
312            Box::new(move |_| {
313                *called_clone.lock().unwrap() = true;
314                EventResult::Continue
315            }),
316        );
317
318        assert_eq!(id, 1);
319        assert_eq!(registry.handler_count(&EventType::Bell), 1);
320
321        let args = EventArgs::new(EventType::Bell);
322        let results = registry.dispatch(&args);
323
324        assert_eq!(results.len(), 1);
325        assert!(results[0].is_continue());
326        assert!(*called.lock().unwrap());
327    }
328
329    #[test]
330    fn test_priority_ordering() {
331        let mut registry = EventRegistry::new();
332        let order = Arc::new(Mutex::new(Vec::new()));
333
334        for (i, priority) in [10, 50, 30].iter().enumerate() {
335            let order_clone = Arc::clone(&order);
336            registry.register(
337                EventType::Bell,
338                *priority,
339                &format!("plugin-{}", i),
340                Box::new(move |_| {
341                    order_clone.lock().unwrap().push(*priority);
342                    EventResult::Continue
343                }),
344            );
345        }
346
347        let args = EventArgs::new(EventType::Bell);
348        registry.dispatch(&args);
349
350        // Should be called in descending priority order: 50, 30, 10
351        let order = order.lock().unwrap();
352        assert_eq!(*order, vec![50, 30, 10]);
353    }
354
355    #[test]
356    fn test_stop_processing() {
357        let mut registry = EventRegistry::new();
358        let call_count = Arc::new(Mutex::new(0));
359
360        for i in 0..3 {
361            let call_count_clone = Arc::clone(&call_count);
362            registry.register(
363                EventType::Bell,
364                100 - i,
365                &format!("plugin-{}", i),
366                Box::new(move |_| {
367                    *call_count_clone.lock().unwrap() += 1;
368                    if i == 1 {
369                        EventResult::Stop
370                    } else {
371                        EventResult::Continue
372                    }
373                }),
374            );
375        }
376
377        let args = EventArgs::new(EventType::Bell);
378        let results = registry.dispatch(&args);
379
380        // Only first two handlers should be called (second one stops)
381        assert_eq!(*call_count.lock().unwrap(), 2);
382        assert_eq!(results.len(), 2);
383        assert!(results[1].is_stop());
384    }
385
386    #[test]
387    fn test_unregister() {
388        let mut registry = EventRegistry::new();
389
390        let id = registry.register(
391            EventType::Bell,
392            100,
393            "test",
394            Box::new(|_| EventResult::Continue),
395        );
396
397        assert_eq!(registry.handler_count(&EventType::Bell), 1);
398        assert!(registry.unregister(id));
399        assert_eq!(registry.handler_count(&EventType::Bell), 0);
400        assert!(!registry.unregister(id)); // Already removed
401    }
402
403    #[test]
404    fn test_unregister_plugin() {
405        let mut registry = EventRegistry::new();
406
407        registry.register(
408            EventType::Bell,
409            100,
410            "plugin-a",
411            Box::new(|_| EventResult::Continue),
412        );
413        registry.register(
414            EventType::Bell,
415            90,
416            "plugin-b",
417            Box::new(|_| EventResult::Continue),
418        );
419        registry.register(
420            EventType::TabCreated,
421            100,
422            "plugin-a",
423            Box::new(|_| EventResult::Continue),
424        );
425
426        assert_eq!(registry.total_handler_count(), 3);
427
428        let removed = registry.unregister_plugin("plugin-a");
429        assert_eq!(removed, 2);
430        assert_eq!(registry.total_handler_count(), 1);
431    }
432
433    #[test]
434    fn test_custom_events() {
435        let mut registry = EventRegistry::new();
436        let called = Arc::new(Mutex::new(false));
437        let called_clone = Arc::clone(&called);
438
439        registry.register(
440            EventType::Custom("my-event".to_string()),
441            100,
442            "test",
443            Box::new(move |_| {
444                *called_clone.lock().unwrap() = true;
445                EventResult::Continue
446            }),
447        );
448
449        let args = EventArgs::new(EventType::Custom("my-event".to_string()));
450        registry.dispatch(&args);
451
452        assert!(*called.lock().unwrap());
453    }
454
455    #[test]
456    fn test_clear_operations() {
457        let mut registry = EventRegistry::new();
458
459        registry.register(
460            EventType::Bell,
461            100,
462            "test",
463            Box::new(|_| EventResult::Continue),
464        );
465        registry.register(
466            EventType::TabCreated,
467            100,
468            "test",
469            Box::new(|_| EventResult::Continue),
470        );
471
472        assert_eq!(registry.total_handler_count(), 2);
473
474        registry.clear_event(&EventType::Bell);
475        assert_eq!(registry.total_handler_count(), 1);
476
477        registry.clear_all();
478        assert_eq!(registry.total_handler_count(), 0);
479    }
480
481    #[test]
482    fn test_registered_events() {
483        let mut registry = EventRegistry::new();
484
485        registry.register(
486            EventType::Bell,
487            100,
488            "test",
489            Box::new(|_| EventResult::Continue),
490        );
491        registry.register(
492            EventType::Custom("test".to_string()),
493            100,
494            "test",
495            Box::new(|_| EventResult::Continue),
496        );
497
498        let events = registry.registered_events();
499        assert_eq!(events.len(), 2);
500        assert!(events.contains(&EventType::Bell));
501        assert!(events.contains(&EventType::Custom("test".to_string())));
502    }
503
504    #[test]
505    fn test_modified_result() {
506        let mut registry = EventRegistry::new();
507
508        registry.register(
509            EventType::Output,
510            100,
511            "test",
512            Box::new(|_| EventResult::Modified(vec![1, 2, 3])),
513        );
514
515        let args = EventArgs::new(EventType::Output);
516        let results = registry.dispatch(&args);
517
518        assert_eq!(results.len(), 1);
519        assert_eq!(results[0].as_modified(), Some(&[1, 2, 3][..]));
520    }
521}