Skip to main content

rainier_events/
event.rs

1//! The [`Event`] and [`Listener`] contracts.
2
3use std::any::{type_name, Any};
4use std::future::Future;
5use std::sync::Arc;
6
7use rainier_support::{BoxedFuture, Result};
8
9/// Something that happened, which listeners may react to.
10///
11/// Any plain object can be an event — a blanket impl covers
12/// every eligible type, so there is no `impl Event for OrderShipped` to write:
13///
14/// ```
15/// # use rainier_events::Event;
16/// struct OrderShipped { pub order_id: u64 }
17///
18/// assert!(OrderShipped::event_name().ends_with("OrderShipped"));
19/// ```
20///
21/// The bounds are what dispatch requires: `Send + Sync` because listeners may
22/// run on any task, and `'static` because the event is type-erased into an
23/// `Arc<dyn Any>` to reach listeners registered for its type.
24///
25/// The cost of the blanket impl is that [`event_name`](Event::event_name)
26/// cannot be overridden per type — an impl for your type would conflict with
27/// it. When the derived Rust path is not the name you want a wildcard listener
28/// to see, dispatch it explicitly with
29/// [`Dispatcher::dispatch_as`](crate::Dispatcher::dispatch_as).
30pub trait Event: Send + Sync + 'static {
31    /// A human-readable name, used by wildcard listeners and log output.
32    /// Always the Rust type path; see the trait docs.
33    fn event_name() -> &'static str
34    where
35        Self: Sized,
36    {
37        type_name::<Self>()
38    }
39}
40
41impl<T: Send + Sync + 'static> Event for T {}
42
43/// A reaction to an event of type `E`.
44///
45/// Listeners take `Arc<E>` rather than `&E` so their returned futures own
46/// what they need and can be `'static`. A borrowing signature would force
47/// every listener's future to be tied to the `dispatch` call's stack frame,
48/// which rules out boxing them into one heterogeneous list — and sharing one
49/// `Arc` across listeners avoids cloning the event per listener besides.
50pub trait Listener<E: Event>: Send + Sync + 'static {
51    /// Handle the event.
52    ///
53    /// Returning `Err` stops the remaining listeners for this event; see
54    /// [`Dispatcher::dispatch`](crate::Dispatcher::dispatch).
55    fn handle(&self, event: Arc<E>) -> BoxedFuture<Result<()>>;
56}
57
58/// Any `async` closure taking `Arc<E>` is a listener.
59///
60/// ```
61/// # use rainier_events::Dispatcher;
62/// # use std::sync::Arc;
63/// # struct UserRegistered { email: String }
64/// # #[tokio::main] async fn main() -> rainier_support::Result<()> {
65/// let events = Dispatcher::new();
66/// events.listen(|event: Arc<UserRegistered>| async move {
67///     println!("welcome {}", event.email);
68///     Ok(())
69/// });
70/// # events.dispatch(UserRegistered { email: "a@b.c".into() }).await?;
71/// # Ok(()) }
72/// ```
73impl<E, F, Fut> Listener<E> for F
74where
75    E: Event,
76    F: Fn(Arc<E>) -> Fut + Send + Sync + 'static,
77    Fut: Future<Output = Result<()>> + Send + 'static,
78{
79    fn handle(&self, event: Arc<E>) -> BoxedFuture<Result<()>> {
80        Box::pin(self(event))
81    }
82}
83
84/// A listener registered for *every* event, receiving the event's name and its
85/// type-erased payload.
86///
87/// The payload can be recovered with
88/// [`downcast`](std::sync::Arc::downcast) when the listener knows the type;
89/// most wildcard listeners (logging, metrics, an audit trail) only need the
90/// name.
91pub trait WildcardListener: Send + Sync + 'static {
92    /// Handle any dispatched event.
93    fn handle(
94        &self,
95        name: &'static str,
96        event: Arc<dyn Any + Send + Sync>,
97    ) -> BoxedFuture<Result<()>>;
98}
99
100impl<F, Fut> WildcardListener for F
101where
102    F: Fn(&'static str, Arc<dyn Any + Send + Sync>) -> Fut + Send + Sync + 'static,
103    Fut: Future<Output = Result<()>> + Send + 'static,
104{
105    fn handle(
106        &self,
107        name: &'static str,
108        event: Arc<dyn Any + Send + Sync>,
109    ) -> BoxedFuture<Result<()>> {
110        Box::pin(self(name, event))
111    }
112}
113
114/// A type that registers several related listeners at once — an event
115/// subscriber.
116///
117/// Keeps a feature's event wiring in one place instead of scattering
118/// `listen` calls across a service provider.
119///
120/// ```
121/// # use rainier_events::{Dispatcher, EventSubscriber};
122/// # use std::sync::Arc;
123/// # struct OrderPlaced; struct OrderShipped;
124/// struct OrderNotifications;
125///
126/// impl EventSubscriber for OrderNotifications {
127///     fn subscribe(&self, events: &Dispatcher) {
128///         events.listen(|_: Arc<OrderPlaced>| async { Ok(()) });
129///         events.listen(|_: Arc<OrderShipped>| async { Ok(()) });
130///     }
131/// }
132/// ```
133pub trait EventSubscriber {
134    /// Register this subscriber's listeners.
135    fn subscribe(&self, dispatcher: &crate::Dispatcher);
136}