pub struct EventDispatcher { /* private fields */ }Expand description
High-performance event dispatcher
The main component of the Mod Events system. Thread-safe and optimized for high-performance event dispatch with minimal overhead.
§Example
use mod_events::{EventDispatcher, Event};
#[derive(Debug, Clone)]
struct MyEvent {
message: String,
}
impl Event for MyEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
let dispatcher = EventDispatcher::new();
dispatcher.on(|event: &MyEvent| {
println!("Received: {}", event.message);
});
dispatcher.emit(MyEvent {
message: "Hello, World!".to_string(),
});Implementations§
Source§impl EventDispatcher
impl EventDispatcher
Sourcepub fn subscribe<T, F>(&self, listener: F) -> ListenerId
pub fn subscribe<T, F>(&self, listener: F) -> ListenerId
Subscribe to an event with a closure that can return errors.
§Example
use mod_events::{EventDispatcher, Event};
#[derive(Debug, Clone)]
struct MyEvent {
message: String,
}
impl Event for MyEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
let dispatcher = EventDispatcher::new();
dispatcher.subscribe(|event: &MyEvent| {
if event.message.is_empty() {
return Err("Message cannot be empty".into());
}
println!("Message: {}", event.message);
Ok(())
});Sourcepub fn subscribe_with_priority<T, F>(
&self,
listener: F,
priority: Priority,
) -> ListenerId
pub fn subscribe_with_priority<T, F>( &self, listener: F, priority: Priority, ) -> ListenerId
Subscribe to an event with a specific priority.
Sourcepub fn on<T, F>(&self, listener: F) -> ListenerId
pub fn on<T, F>(&self, listener: F) -> ListenerId
Subscribe to an event with simple closure (no error handling).
This is the most convenient method for simple event handling.
§Example
use mod_events::{EventDispatcher, Event};
#[derive(Debug, Clone)]
struct MyEvent {
message: String,
}
impl Event for MyEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
let dispatcher = EventDispatcher::new();
dispatcher.on(|event: &MyEvent| {
println!("Received: {}", event.message);
});Sourcepub fn subscribe_async<T, F, Fut>(&self, listener: F) -> ListenerId
pub fn subscribe_async<T, F, Fut>(&self, listener: F) -> ListenerId
Subscribe an async listener at Priority::Normal (requires the
async feature).
The listener receives a borrowed event and returns a future that
resolves to Result<(), ListenerError>.
§Example
use mod_events::{Event, EventDispatcher};
#[derive(Debug, Clone)]
struct EmailSent { to: String }
impl Event for EmailSent {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
dispatcher.subscribe_async(|event: &EmailSent| {
let to = event.to.clone();
async move {
println!("delivered to {}", to);
Ok(())
}
});Sourcepub fn subscribe_async_with_priority<T, F, Fut>(
&self,
listener: F,
priority: Priority,
) -> ListenerId
pub fn subscribe_async_with_priority<T, F, Fut>( &self, listener: F, priority: Priority, ) -> ListenerId
Subscribe an async listener at a specific priority (requires the
async feature).
Higher-priority listeners are awaited first within a single
Self::dispatch_async call.
§Example
use mod_events::{Event, EventDispatcher, Priority};
#[derive(Debug, Clone)]
struct EmailSent { to: String }
impl Event for EmailSent {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
dispatcher.subscribe_async_with_priority(
|_event: &EmailSent| async move {
// logged before any other listener
Ok(())
},
Priority::High,
);Sourcepub fn dispatch<T: Event>(&self, event: T) -> DispatchResult
pub fn dispatch<T: Event>(&self, event: T) -> DispatchResult
Dispatch an event synchronously.
Returns a DispatchResult containing per-listener outcomes.
§Example
use mod_events::{EventDispatcher, Event};
#[derive(Debug, Clone)]
struct MyEvent {
message: String,
}
impl Event for MyEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
let dispatcher = EventDispatcher::new();
let result = dispatcher.dispatch(MyEvent {
message: "Hello".to_string(),
});
if result.all_succeeded() {
println!("All listeners handled the event successfully");
}Sourcepub async fn dispatch_async<T: Event>(&self, event: T) -> DispatchResult
pub async fn dispatch_async<T: Event>(&self, event: T) -> DispatchResult
Dispatch an event asynchronously and await every async listener
in priority order (requires the async feature).
Listeners are awaited sequentially in descending priority
order. This preserves the priority contract — a high-priority
listener completes (or errors) before the next listener is
polled. Concurrent execution would lose ordering. If you want
true concurrent execution, drive spawn (e.g. tokio::spawn,
async_std::task::spawn) from inside each listener and return
Ok(()) immediately.
Each listener future is wrapped in catch_unwind, mirroring
the panic-safety guarantee of the sync Self::dispatch
path. A panic during .await becomes a ListenerError in
DispatchResult::errors with the prefix
"listener panicked: ". Subsequent listeners still run.
Sync listeners registered via Self::on / Self::subscribe
are not invoked here; only listeners registered through
Self::subscribe_async / Self::subscribe_async_with_priority
are awaited.
§Example
use mod_events::{Event, EventDispatcher};
#[derive(Debug, Clone)]
struct OrderShipped { order_id: u64 }
impl Event for OrderShipped {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
dispatcher.subscribe_async(|event: &OrderShipped| {
let id = event.order_id;
async move {
println!("notifying customer about order {}", id);
Ok(())
}
});
let result = dispatcher
.dispatch_async(OrderShipped { order_id: 42 })
.await;
assert!(result.all_succeeded());Sourcepub fn emit<T: Event>(&self, event: T)
pub fn emit<T: Event>(&self, event: T)
Fire and forget — dispatch without inspecting the result.
Use this when listeners’ success or failure is not actionable at
the call site (logging, fanout to passive observers). The errors
returned by failing listeners are discarded; if you need them,
call Self::dispatch instead.
§Example
use mod_events::{EventDispatcher, Event};
#[derive(Debug, Clone)]
struct MyEvent {
message: String,
}
impl Event for MyEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
let dispatcher = EventDispatcher::new();
dispatcher.emit(MyEvent {
message: "Fire and forget".to_string(),
});Sourcepub fn add_middleware<F>(&self, middleware: F)
pub fn add_middleware<F>(&self, middleware: F)
Add middleware that can block events.
Middleware functions receive events and return true to allow
processing or false to block the event.
§Example
use mod_events::{EventDispatcher, Event};
let dispatcher = EventDispatcher::new();
dispatcher.add_middleware(|event: &dyn Event| {
println!("Processing event: {}", event.event_name());
true // Allow all events
});Sourcepub fn unsubscribe(&self, listener_id: ListenerId) -> bool
pub fn unsubscribe(&self, listener_id: ListenerId) -> bool
Remove a previously registered listener.
Returns true if the listener was found and removed, false
if no listener with that id was registered (already removed,
never registered, or registered against a different event type).
§Example
use mod_events::{Event, EventDispatcher};
#[derive(Debug, Clone)]
struct Tick;
impl Event for Tick {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
let id = dispatcher.on(|_: &Tick| {});
assert!(dispatcher.unsubscribe(id));
// Subsequent removals of the same id return false.
assert!(!dispatcher.unsubscribe(id));Sourcepub fn listener_count<T: Event + 'static>(&self) -> usize
pub fn listener_count<T: Event + 'static>(&self) -> usize
Get the total number of listeners (sync + async, when the
async feature is enabled) registered for an event type.
§Example
use mod_events::{Event, EventDispatcher};
#[derive(Debug, Clone)]
struct Tick;
impl Event for Tick {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
assert_eq!(dispatcher.listener_count::<Tick>(), 0);
let _ = dispatcher.on(|_: &Tick| {});
let _ = dispatcher.on(|_: &Tick| {});
assert_eq!(dispatcher.listener_count::<Tick>(), 2);Sourcepub fn metrics(&self) -> HashMap<TypeId, EventMetadata>
pub fn metrics(&self) -> HashMap<TypeId, EventMetadata>
Get a snapshot of per-event-type EventMetadata keyed by
TypeId.
The returned map is a fresh snapshot. Subsequent dispatches do
not mutate it, but the snapshot may be slightly behind the live
counters because dispatch_count is read independently of
last_dispatch.
§Example
use mod_events::{Event, EventDispatcher};
use std::any::TypeId;
#[derive(Debug, Clone)]
struct Tick;
impl Event for Tick {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
let _ = dispatcher.on(|_: &Tick| {});
dispatcher.emit(Tick);
dispatcher.emit(Tick);
let snapshot = dispatcher.metrics();
let meta = snapshot.get(&TypeId::of::<Tick>()).unwrap();
assert_eq!(meta.dispatch_count, 2);Sourcepub fn clear(&self)
pub fn clear(&self)
Drop every registered listener, both sync and async.
Middleware and accumulated metrics are unaffected. Use
Self::clear_middleware if you also need to drop the
middleware chain.
§Example
use mod_events::{Event, EventDispatcher};
#[derive(Debug, Clone)]
struct Tick;
impl Event for Tick {
fn as_any(&self) -> &dyn std::any::Any { self }
}
let dispatcher = EventDispatcher::new();
let _ = dispatcher.on(|_: &Tick| {});
dispatcher.clear();
assert_eq!(dispatcher.listener_count::<Tick>(), 0);Sourcepub fn clear_middleware(&self)
pub fn clear_middleware(&self)
Drop every registered middleware function.
Listeners and accumulated metrics are unaffected. Useful in test setup/teardown when you want to reset the middleware chain between cases without rebuilding the dispatcher.