Skip to main content

EventDispatcher

Struct EventDispatcher 

Source
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

Source

pub fn new() -> Self

Create a new event dispatcher.

Source

pub fn subscribe<T, F>(&self, listener: F) -> ListenerId
where T: Event + 'static, F: Fn(&T) -> Result<(), ListenerError> + Send + Sync + 'static,

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(())
});
Source

pub fn subscribe_with_priority<T, F>( &self, listener: F, priority: Priority, ) -> ListenerId
where T: Event + 'static, F: Fn(&T) -> Result<(), ListenerError> + Send + Sync + 'static,

Subscribe to an event with a specific priority.

Source

pub fn on<T, F>(&self, listener: F) -> ListenerId
where T: Event + 'static, F: Fn(&T) + Send + Sync + 'static,

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);
});
Source

pub fn subscribe_async<T, F, Fut>(&self, listener: F) -> ListenerId
where T: Event + 'static, F: Fn(&T) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<(), ListenerError>> + Send + 'static,

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(())
    }
});
Source

pub fn subscribe_async_with_priority<T, F, Fut>( &self, listener: F, priority: Priority, ) -> ListenerId
where T: Event + 'static, F: Fn(&T) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<(), ListenerError>> + Send + 'static,

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,
);
Source

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");
}
Source

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());
Source

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(),
});
Source

pub fn add_middleware<F>(&self, middleware: F)
where F: Fn(&dyn Event) -> bool + Send + Sync + 'static,

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
});
Source

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));
Source

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);
Source

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);
Source

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);
Source

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.

Trait Implementations§

Source§

impl Default for EventDispatcher

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.