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
//! The [`Event`] and [`Listener`] contracts.
use ;
use Future;
use Arc;
use ;
/// Something that happened, which listeners may react to.
///
/// Any plain object can be an event — a blanket impl covers
/// every eligible type, so there is no `impl Event for OrderShipped` to write:
///
/// ```
/// # use rainier_events::Event;
/// struct OrderShipped { pub order_id: u64 }
///
/// assert!(OrderShipped::event_name().ends_with("OrderShipped"));
/// ```
///
/// The bounds are what dispatch requires: `Send + Sync` because listeners may
/// run on any task, and `'static` because the event is type-erased into an
/// `Arc<dyn Any>` to reach listeners registered for its type.
///
/// The cost of the blanket impl is that [`event_name`](Event::event_name)
/// cannot be overridden per type — an impl for your type would conflict with
/// it. When the derived Rust path is not the name you want a wildcard listener
/// to see, dispatch it explicitly with
/// [`Dispatcher::dispatch_as`](crate::Dispatcher::dispatch_as).
/// A reaction to an event of type `E`.
///
/// Listeners take `Arc<E>` rather than `&E` so their returned futures own
/// what they need and can be `'static`. A borrowing signature would force
/// every listener's future to be tied to the `dispatch` call's stack frame,
/// which rules out boxing them into one heterogeneous list — and sharing one
/// `Arc` across listeners avoids cloning the event per listener besides.
/// Any `async` closure taking `Arc<E>` is a listener.
///
/// ```
/// # use rainier_events::Dispatcher;
/// # use std::sync::Arc;
/// # struct UserRegistered { email: String }
/// # #[tokio::main] async fn main() -> rainier_support::Result<()> {
/// let events = Dispatcher::new();
/// events.listen(|event: Arc<UserRegistered>| async move {
/// println!("welcome {}", event.email);
/// Ok(())
/// });
/// # events.dispatch(UserRegistered { email: "a@b.c".into() }).await?;
/// # Ok(()) }
/// ```
/// A listener registered for *every* event, receiving the event's name and its
/// type-erased payload.
///
/// The payload can be recovered with
/// [`downcast`](std::sync::Arc::downcast) when the listener knows the type;
/// most wildcard listeners (logging, metrics, an audit trail) only need the
/// name.
/// A type that registers several related listeners at once — an event
/// subscriber.
///
/// Keeps a feature's event wiring in one place instead of scattering
/// `listen` calls across a service provider.
///
/// ```
/// # use rainier_events::{Dispatcher, EventSubscriber};
/// # use std::sync::Arc;
/// # struct OrderPlaced; struct OrderShipped;
/// struct OrderNotifications;
///
/// impl EventSubscriber for OrderNotifications {
/// fn subscribe(&self, events: &Dispatcher) {
/// events.listen(|_: Arc<OrderPlaced>| async { Ok(()) });
/// events.listen(|_: Arc<OrderShipped>| async { Ok(()) });
/// }
/// }
/// ```