mod-events 0.2.1

A high-performance, zero-overhead event dispatcher library for Rust
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
<h1 align="center">
        <img width="108px" height="auto" src="https://raw.githubusercontent.com/jamesgober/jamesgober/main/media/icons/hexagon-3.svg" alt="Triple Hexagon">
    <br>
    <strong>Mod Events</strong>
    <sup><br><sup>API REFERENCE</sup></sup>
</h1>

Complete API documentation for mod-events.

## Table of Contents

- [Core Traits]#core-traits
- [EventDispatcher]#eventdispatcher
- [Priority System]#priority-system
- [Event Listeners]#event-listeners
- [Results and Metrics]#results-and-metrics
- [Middleware]#middleware
- [Type Aliases]#type-aliases
- [Feature Flags]#feature-flags
- [Thread Safety]#thread-safety
- [Performance Characteristics]#performance-characteristics
- [Error Handling]#error-handling — including [`ListenerError`]#listenererror

## Core Traits

### Event

The fundamental trait that all events must implement.

```rust
pub trait Event: Any + Send + Sync + fmt::Debug {
    fn as_any(&self) -> &dyn Any;
    fn type_id(&self) -> TypeId { ... }
    fn event_name(&self) -> &'static str { ... }
}
```

#### Required Methods

- **`as_any(&self) -> &dyn Any`** - Returns the event as `Any` for downcasting

#### Provided Methods

- **`type_id(&self) -> TypeId`** - Returns a unique identifier for this event type
- **`event_name(&self) -> &'static str`** - Returns the event name for debugging

#### Example

```rust
use mod_events::Event;

#[derive(Debug, Clone)]
struct MyEvent {
    message: String,
}

impl Event for MyEvent {
    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}
```

## EventDispatcher

The main component for dispatching events to listeners.

```rust
pub struct EventDispatcher { /* private fields */ }
```

### Creation

#### `new() -> Self`

Creates a new event dispatcher.

```rust
let dispatcher = EventDispatcher::new();
```

### Event Subscription

#### `on<T, F>(&self, listener: F) -> ListenerId`

Subscribe to an event with a simple closure (no error handling).

**Parameters:**
- `T: Event + 'static` - The event type
- `F: Fn(&T) + Send + Sync + 'static` - The listener function

**Returns:** `ListenerId` - Unique identifier for the listener

```rust
let id = dispatcher.on(|event: &MyEvent| {
    println!("Received: {}", event.message);
});
```

#### `subscribe<T, F>(&self, listener: F) -> ListenerId`

Subscribe to an event with error handling.

**Parameters:**
- `T: Event + 'static` - The event type
- `F: Fn(&T) -> Result<(), ListenerError> + Send + Sync + 'static` - The listener function

**Returns:** `ListenerId` - Unique identifier for the listener

```rust
let id = dispatcher.subscribe(|event: &MyEvent| {
    if event.message.is_empty() {
        return Err("Message cannot be empty".into());
    }
    println!("Message: {}", event.message);
    Ok(())
});
```

#### `subscribe_with_priority<T, F>(&self, listener: F, priority: Priority) -> ListenerId`

Subscribe to an event with a specific priority.

**Parameters:**
- `T: Event + 'static` - The event type
- `F: Fn(&T) -> Result<(), ListenerError> + Send + Sync + 'static` - The listener function
- `priority: Priority` - The priority level

**Returns:** `ListenerId` - Unique identifier for the listener

```rust
let id = dispatcher.subscribe_with_priority(|event: &MyEvent| {
    println!("High priority handler");
    Ok(())
}, Priority::High);
```

### Async Event Subscription

*Available with the `async` feature*

#### `subscribe_async<T, F, Fut>(&self, listener: F) -> ListenerId`

Subscribe to an event with an async handler.

**Parameters:**
- `T: Event + 'static` - The event type
- `F: Fn(&T) -> Fut + Send + Sync + 'static` - The async listener function
- `Fut: Future<Output = Result<(), ListenerError>> + Send + 'static` - The future type

**Returns:** `ListenerId` - Unique identifier for the listener

```rust
let id = dispatcher.subscribe_async(|event: &MyEvent| async {
    // Async processing
    tokio::time::sleep(Duration::from_millis(100)).await;
    println!("Async handler completed");
    Ok(())
});
```

#### `subscribe_async_with_priority<T, F, Fut>(&self, listener: F, priority: Priority) -> ListenerId`

Subscribe to an event with an async handler and specific priority.

**Parameters:**
- `T: Event + 'static` - The event type
- `F: Fn(&T) -> Fut + Send + Sync + 'static` - The async listener function
- `Fut: Future<Output = Result<(), ListenerError>> + Send + 'static` - The future type
- `priority: Priority` - The priority level

**Returns:** `ListenerId` - Unique identifier for the listener

```rust
let id = dispatcher.subscribe_async_with_priority(|event: &MyEvent| async {
    // High priority async processing
    Ok(())
}, Priority::High);
```

### Event Dispatching

#### `emit<T: Event>(&self, event: T)`

Fire and forget event dispatch - fastest method.

**Parameters:**
- `event: T` - The event to dispatch

```rust
dispatcher.emit(MyEvent {
    message: "Hello World".to_string(),
});
```

#### `dispatch<T: Event>(&self, event: T) -> DispatchResult`

Dispatch an event and return results.

**Parameters:**
- `event: T` - The event to dispatch

**Returns:** `DispatchResult` - Information about the dispatch

```rust
let result = dispatcher.dispatch(MyEvent {
    message: "Hello".to_string(),
});

if result.all_succeeded() {
    println!("All handlers succeeded");
}
```

#### `dispatch_async<T: Event>(&self, event: T) -> impl Future<Output = DispatchResult>`

*Available with the `async` feature*

Dispatch an event asynchronously.

**Parameters:**
- `event: T` - The event to dispatch

**Returns:** `Future<Output = DispatchResult>` - Future resolving to dispatch results

```rust
let result = dispatcher.dispatch_async(MyEvent {
    message: "Async Hello".to_string(),
}).await;
```

### Listener Management

#### `unsubscribe(&self, listener_id: ListenerId) -> bool`

Remove a listener.

**Parameters:**
- `listener_id: ListenerId` - The listener to remove

**Returns:** `bool` - `true` if the listener was found and removed

```rust
let id = dispatcher.on(|event: &MyEvent| {
    println!("Handler");
});

let removed = dispatcher.unsubscribe(id);
assert!(removed);
```

#### `listener_count<T: Event + 'static>(&self) -> usize`

Get the number of listeners for an event type.

**Parameters:**
- `T: Event + 'static` - The event type

**Returns:** `usize` - Number of listeners

```rust
let count = dispatcher.listener_count::<MyEvent>();
println!("Listeners: {}", count);
```

#### `clear(&self)`

Remove all listeners.

```rust
dispatcher.clear();
```

### Middleware

#### `add_middleware<F>(&self, middleware: F)`

Add middleware that can filter or transform events.

**Parameters:**
- `F: Fn(&dyn Event) -> bool + Send + Sync + 'static` - Middleware function returning `true` to allow the event

```rust
dispatcher.add_middleware(|event: &dyn Event| {
    println!("Processing: {}", event.event_name());
    true // Allow all events
});
```

### Metrics

#### `metrics(&self) -> HashMap<TypeId, EventMetadata>`

Get event dispatch metrics.

**Returns:** `HashMap<TypeId, EventMetadata>` - Metrics for each event type

```rust
let metrics = dispatcher.metrics();
for (_, meta) in metrics {
    println!("Event: {} dispatched {} times", 
        meta.event_name, meta.dispatch_count);
}
```

## Priority System

### Priority

Enum defining listener execution priority.

```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum Priority {
    Lowest = 0,
    Low = 25,
    #[default]
    Normal = 50,
    High = 75,
    Highest = 100,
    Critical = 125,
}
```

`Default` is implemented and points to `Normal`, so `Priority::default()`
or any `..Default::default()` struct-update expression yields normal
priority.

#### Values

- **`Lowest`** - Lowest priority (0)
- **`Low`** - Low priority (25)
- **`Normal`** - Normal priority (50) - Default
- **`High`** - High priority (75)
- **`Highest`** - Highest priority (100)
- **`Critical`** - Critical priority (125) - Use sparingly

#### Methods

##### `all() -> &'static [Priority]`

Get all priority levels in order.

```rust
let priorities = Priority::all();
for priority in priorities {
    println!("Priority: {:?}", priority);
}
```

#### Example

```rust
use mod_events::Priority;

// Critical operations first
dispatcher.subscribe_with_priority(|event: &PaymentEvent| {
    process_payment(event)?;
    Ok(())
}, Priority::Critical);

// Normal operations
dispatcher.on(|event: &PaymentEvent| {
    send_receipt(event);
});
```

## Event Listeners

### EventListener

Trait for reusable event listeners.

```rust
pub trait EventListener<T: Event>: Send + Sync {
    fn handle(&self, event: &T) -> Result<(), ListenerError>;
    fn priority(&self) -> Priority { Priority::Normal }
}
```

#### Required Methods

- **`handle(&self, event: &T) -> Result<(), ListenerError>`** - Handle the event

#### Provided Methods

- **`priority(&self) -> Priority`** - Get the priority (default: `Priority::Normal`)

#### Example

```rust
use mod_events::{Event, EventListener, ListenerError, Priority};

struct EmailNotifier {
    smtp_server: String,
}

impl EventListener<UserRegistered> for EmailNotifier {
    fn handle(&self, event: &UserRegistered) -> Result<(), ListenerError> {
        send_email(&self.smtp_server, &event.email)
            .map_err(ListenerError::new)?;
        Ok(())
    }

    fn priority(&self) -> Priority {
        Priority::High
    }
}
```

### AsyncEventListener

*Available with the `async` feature*

Trait for async event listeners.

```rust
pub type AsyncEventResult<'a> =
    Pin<Box<dyn Future<Output = Result<(), ListenerError>> + Send + 'a>>;

pub trait AsyncEventListener<T: Event>: Send + Sync {
    fn handle<'a>(&'a self, event: &'a T) -> AsyncEventResult<'a>;
    fn priority(&self) -> Priority { Priority::Normal }
}
```

#### Required Methods

- **`handle<'a>(&'a self, event: &'a T) -> Pin<Box<dyn Future<...> + Send + 'a>>`** - Handle the event asynchronously

#### Provided Methods

- **`priority(&self) -> Priority`** - Get the priority (default: `Priority::Normal`)

#### Example

```rust
use mod_events::{AsyncEventListener, ListenerError, Priority};

struct AsyncEmailNotifier {
    smtp_client: AsyncSmtpClient,
}

use mod_events::AsyncEventResult;

impl AsyncEventListener<UserRegistered> for AsyncEmailNotifier {
    fn handle<'a>(&'a self, event: &'a UserRegistered) -> AsyncEventResult<'a> {
        Box::pin(async move {
            self.smtp_client
                .send_email(&event.email)
                .await
                .map_err(ListenerError::new)?;
            Ok(())
        })
    }

    fn priority(&self) -> Priority {
        Priority::High
    }
}
```

## Results and Metrics

### DispatchResult

Information about event dispatch results.

```rust
pub struct DispatchResult { /* private fields */ }
```

#### Methods

##### `is_blocked(&self) -> bool`

Check if the event was blocked by middleware.

```rust
let result = dispatcher.dispatch(event);
if result.is_blocked() {
    println!("Event was blocked by middleware");
}
```

##### `listener_count(&self) -> usize`

Get the total number of listeners that were called.

```rust
let count = result.listener_count();
println!("Called {} listeners", count);
```

##### `success_count(&self) -> usize`

Get the number of successful handlers.

```rust
let successes = result.success_count();
println!("{} handlers succeeded", successes);
```

##### `error_count(&self) -> usize`

Get the number of failed handlers.

```rust
let errors = result.error_count();
println!("{} handlers failed", errors);
```

##### `all_succeeded(&self) -> bool`

Check if all handlers succeeded.

```rust
if result.all_succeeded() {
    println!("All handlers completed successfully");
}
```

##### `has_errors(&self) -> bool`

Check if any handlers failed.

```rust
if result.has_errors() {
    println!("Some handlers failed");
}
```

##### `errors(&self) -> Vec<&ListenerError>`

Borrow every error produced by failing listeners, in dispatch order.

```rust
for error in result.errors() {
    eprintln!("Handler error: {}", error);
}
```

### EventMetadata

Metadata about event dispatch history.

```rust
pub struct EventMetadata {
    pub event_name: &'static str,
    pub type_id: TypeId,
    pub last_dispatch: Instant,
    pub dispatch_count: u64,
    pub listener_count: usize,
}
```

#### Fields

- **`event_name`** - The name of the event type
- **`type_id`** - Type ID of the event
- **`last_dispatch`** - Timestamp of the last dispatch
- **`dispatch_count`** - `u64`. Total number of times this event has been dispatched. Backed by an `AtomicU64` on the dispatch hot path.
- **`listener_count`** - Number of listeners (sync + async, when the `async` feature is enabled) currently subscribed. Derived from the live registry at snapshot time, so it cannot drift.

#### Methods

##### `time_since_last_dispatch(&self) -> Duration`

Get the time since the last dispatch.

```rust
let metrics = dispatcher.metrics();
for (_, meta) in metrics {
    let elapsed = meta.time_since_last_dispatch();
    println!("Last {} dispatch: {:?} ago", meta.event_name, elapsed);
}
```

### ListenerId

Unique identifier for event listeners.

```rust
pub struct ListenerId { /* private fields */ }
```

Used for unsubscribing listeners:

```rust
let id = dispatcher.on(|event: &MyEvent| {
    println!("Handler");
});

dispatcher.unsubscribe(id);
```

## Middleware

### MiddlewareFunction

Type alias for middleware functions.

```rust
pub type MiddlewareFunction = Box<dyn Fn(&dyn Event) -> bool + Send + Sync>;
```

Middleware functions receive an event and return `true` to allow processing or `false` to block it.

### MiddlewareManager

Manages middleware execution.

```rust
pub struct MiddlewareManager { /* private fields */ }
```

#### Methods

##### `new() -> Self`

Create a new middleware manager.

##### `add<F>(&mut self, middleware: F)`

Add middleware to the chain.

**Parameters:**
- `F: Fn(&dyn Event) -> bool + Send + Sync + 'static` - Middleware function

##### `process(&self, event: &dyn Event) -> bool`

Process an event through all middleware.

**Returns:** `bool` - `true` if the event should continue

##### `count(&self) -> usize`

Get the number of middleware functions.

##### `clear(&mut self)`

Remove all middleware.

## Type Aliases

### AsyncEventResult

*Available with the `async` feature*

```rust
pub type AsyncEventResult<'a> =
    Pin<Box<dyn Future<Output = Result<(), ListenerError>> + Send + 'a>>;
```

The pinned, boxed future type returned by [`AsyncEventListener::handle`].
Use it as the return type when implementing `AsyncEventListener` by
hand instead of spelling out the full `Pin<Box<…>>`.

### MiddlewareFunction

```rust
pub type MiddlewareFunction = Box<dyn Fn(&dyn Event) -> bool + Send + Sync>;
```

Boxed middleware function. See the [Middleware](#middleware) section.

## Feature Flags

### `async`

Enables async event handling support. On by default.

```toml
[dependencies]
mod-events = { version = "0.2.1", features = ["async"] }

# Disable to build sync-only:
mod-events = { version = "0.2.1", default-features = false }
```

When enabled, provides:
- `subscribe_async` methods
- `dispatch_async` method
- `AsyncEventListener` trait
- Async-related type aliases

## Thread Safety

All types in mod-events are thread-safe:

- `EventDispatcher` implements `Send + Sync`
- Events must implement `Send + Sync`
- Listeners must implement `Send + Sync`
- All operations are safe for concurrent use

## Performance Characteristics

- **Event dispatch**: sub-microsecond per listener.
- **Subscribe**: O(n) per call (binary insertion via `Vec::partition_point`).
- **Metrics path**: lock-free on the hot path. The dispatch path takes a read lock on the metrics map, clones a per-type `Arc`, releases the lock, then increments atomics. The write lock is only ever taken on the first dispatch of a brand-new event type.
- **Memory overhead**: ~200 bytes per dispatcher plus ~64 bytes per registered event type.
- **Scaling**: Linear with number of listeners per event type.
- **Thread contention**: Minimal — `parking_lot::RwLock` for the registry, `AtomicU64` for counters. Concurrency invariants verified by `loom` model checks for the only double-checked-locking pattern in the crate.

## Error Handling

The library uses typed error handling at every public boundary:

- `Result<T, E>` for every fallible operation.
- [`ListenerError`]#listenererror — typed wrapper around any
  `Error + Send + Sync + 'static`. This is the *only* error type
  exported from the crate; `Box<dyn Error>` does not appear in any
  public signature.
- Individual listener failures do not affect other listeners.
- Middleware can block events by returning `false`; the resulting
  `DispatchResult::is_blocked()` returns `true`.

### ListenerError

```rust
pub struct ListenerError(/* Box<dyn Error + Send + Sync + 'static> */);

impl ListenerError {
    pub fn new<E: Error + Send + Sync + 'static>(error: E) -> Self;
    pub fn message<S: Into<String>>(msg: S) -> Self;
    pub fn inner(&self) -> &(dyn Error + Send + Sync + 'static);
    pub fn into_inner(self) -> Box<dyn Error + Send + Sync + 'static>;
}

impl From<Box<dyn Error + Send + Sync + 'static>> for ListenerError { /* … */ }
impl From<&str> for ListenerError { /* … */ }
impl From<String> for ListenerError { /* … */ }
```

Common construction patterns:

```rust
use mod_events::ListenerError;
use std::io;

// From any concrete error type:
let e = ListenerError::new(io::Error::new(io::ErrorKind::Other, "io failed"));

// From a string literal or owned String, via Into:
let e: ListenerError = "validation failed".into();
let e: ListenerError = format!("retry budget exhausted at {}", 5).into();

// From an existing boxed error:
fn pre_existing() -> Box<dyn std::error::Error + Send + Sync> { /* … */ unreachable!() }
let e: ListenerError = pre_existing().into();
```

## Best Practices

1. **Keep events simple** - Only essential data
2. **Use appropriate priorities** - Critical operations first
3. **Handle errors gracefully** - Don't panic in listeners
4. **Prefer `emit()` for fire-and-forget** - Better performance
5. **Use middleware for cross-cutting concerns** - Logging, metrics
6. **Monitor with metrics** - Track dispatch counts and timing

## Examples

See the [Examples](examples.md) document for end-to-end usage patterns.

## Migration Guide

See the [Migration Guide](migration.md) for upgrading from other event systems.

<br>

## Next Steps

- Get Started [Quick Start Guide]quick-start.md
- Check out more [Examples]examples.md
- Learn [Best Practices]best-practices.md
- Review [Performance Guide]performance.md
- See the [Migration Guide]migration.md