Skip to main content

santui_core/
event.rs

1use std::collections::VecDeque;
2
3use crate::theme::Theme;
4
5/// Events that can be published through the application's [`EventBus`].
6#[derive(Clone, Debug, PartialEq)]
7pub enum Event {
8    /// The active theme changed (plugins should refresh their colours).
9    ThemeChanged(Theme),
10    /// Plugin-to-plugin message.  `from` and `to` are plugin ids.
11    PluginMessage {
12        from: String,
13        to: String,
14        action: String,
15        data: String,
16    },
17}
18
19/// A read-only observer registered via [`EventBus::subscribe`].
20pub type EventSubscriber = Box<dyn FnMut(&Event) + Send>;
21
22/// A simple in-app event bus for decoupling components.
23///
24/// Components emit events via [`EventBus::emit`] and the main loop drains the
25/// pending queue via [`EventBus::drain`] once per frame, forwarding them to
26/// [`PluginManager::process_events`](crate::app::plugin_manager::PluginManager).
27///
28/// External code can register read-only observers with [`EventBus::subscribe`]
29/// to react to events without consuming them (e.g. event logging, metrics).
30///
31/// The pending queue is capped at [`MAX_PENDING`] entries.  If full, the oldest
32/// event is dropped to make room for the newest, ensuring the bus never grows
33/// without bound.
34pub struct EventBus {
35    pending: VecDeque<Event>,
36    subscribers: Vec<EventSubscriber>,
37}
38
39const MAX_PENDING: usize = 1024;
40
41impl EventBus {
42    pub fn new() -> Self {
43        Self {
44            pending: VecDeque::new(),
45            subscribers: Vec::new(),
46        }
47    }
48
49    /// Register a read-only observer that is called for every emitted event.
50    ///
51    /// Subscribers are invoked synchronously inside [`EventBus::emit`] after the
52    /// event is pushed to the pending queue. They receive a shared reference and
53    /// cannot modify or consume the event.
54    pub fn subscribe(&mut self, f: EventSubscriber) {
55        self.subscribers.push(f);
56    }
57
58    /// Push an event onto the pending queue and notify all subscribers.
59    ///
60    /// If the queue is at capacity the oldest event is dropped.
61    pub fn emit(&mut self, event: Event) {
62        for sub in &mut self.subscribers {
63            sub(&event);
64        }
65        if self.pending.len() >= MAX_PENDING {
66            self.pending.pop_front();
67        }
68        self.pending.push_back(event);
69    }
70
71    /// Drain all pending events.
72    pub fn drain(&mut self) -> Vec<Event> {
73        std::mem::take(&mut self.pending).into_iter().collect()
74    }
75}
76
77impl std::fmt::Debug for EventBus {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        f.debug_struct("EventBus")
80            .field("pending", &self.pending)
81            .field(
82                "subscribers",
83                &format_args!("{} subscribers", self.subscribers.len()),
84            )
85            .finish()
86    }
87}
88
89impl Default for EventBus {
90    fn default() -> Self {
91        Self::new()
92    }
93}