//! # Event Bus //! //! An asynchronous event bus for routing typed messages between modules //! without direct coupling. //! //! ## Features //! //! - **Key → event mapping**: each topic (`&str`) is independent //! - **Type-unrestricted**: any `T: Any + Send + Sync + Clone` //! - **Targeted wake-up**: only subscribers of the matching topic are woken up //! - **Callback API**: JavaScript-style — `bus.on("topic", |payload| { ... })` //! - **Glob pattern**: `on_pattern("user-*", |topic, payload| { ... })` //! - **Async handlers**: `on_async` and `on_pattern_async` //! //! ## Example — sync callback //! //! ```rust,no_run //! use std::sync::Arc; //! use oxspeak_server_lib::event_bus::EventBus; //! //! #[derive(Clone, Debug)] //! struct User { name: String } //! //! # tokio_test::block_on(async { //! let bus = Arc::new(EventBus::new()); //! //! bus.on::("user-connected", |user| { //! println!("Connected: {:?}", user); //! }); //! //! bus.emit("user-connected", User { name: "Alice".into() }); //! # tokio::time::sleep(std::time::Duration::from_millis(10)).await; //! # }); //! ``` //! //! ## Example — async callback //! //! ```rust,no_run //! use std::sync::Arc; //! use oxspeak_server_lib::event_bus::EventBus; //! //! #[derive(Clone, Debug)] //! struct User { name: String } //! //! # tokio_test::block_on(async { //! let bus = Arc::new(EventBus::new()); //! //! bus.on_async::("user-connected", |user| async move { //! println!("(async) Connected: {:?}", user); //! }); //! //! bus.emit("user-connected", User { name: "Bob".into() }); //! # tokio::time::sleep(std::time::Duration::from_millis(10)).await; //! # }); //! ``` //! //! ## Example — glob pattern (topic included in the callback) //! //! ```rust,no_run //! use std::sync::Arc; //! use oxspeak_server_lib::event_bus::EventBus; //! //! #[derive(Clone, Debug)] //! struct User { name: String } //! //! # tokio_test::block_on(async { //! let bus = Arc::new(EventBus::new()); //! //! bus.on_pattern::("user-*", |topic, user| { //! match topic.as_str() { //! "user-created" => println!("Created : {:?}", user), //! "user-deleted" => println!("Deleted : {:?}", user), //! other => println!("{}: {:?}", other, user), //! } //! }); //! //! bus.emit("user-created", User { name: "Alice".into() }); //! bus.emit("user-deleted", User { name: "Bob".into() }); //! # tokio::time::sleep(std::time::Duration::from_millis(10)).await; //! # }); //! ``` //! //! ## Example — multi-type with `match_event!` (advanced) //! //! ```rust,no_run //! use std::sync::Arc; //! use oxspeak_server_lib::event_bus::EventBus; //! use oxspeak_server_lib::match_event; //! //! #[derive(Clone, Debug)] struct User { name: String } //! #[derive(Clone, Debug)] struct UdpMetric { value: f32 } //! //! # tokio_test::block_on(async { //! let bus = Arc::new(EventBus::new()); //! let mut rx = bus.on_raw("mixed-topic"); //! //! bus.emit("mixed-topic", User { name: "Alice".into() }); //! //! if let Ok(evt) = rx.recv().await { //! match_event!(evt, //! User => |u| println!("User: {:?}", u), //! UdpMetric => |m| println!("Metric: {:?}", m), //! ); //! } //! # }); //! ``` mod bus; // Public re-exports pub use bus::{AnyEvent, EventBus}; /// Downcasts an [`AnyEvent`] to one or more concrete types and executes /// the matching closure if the type matches. /// /// Non-matching branches are silently ignored. /// /// # Syntax /// ```text /// match_event!(evt, Type1 => |val| { ... }, Type2 => |val| { ... }) /// ``` /// /// # Example /// ```rust,no_run /// # use std::sync::Arc; /// # use oxspeak_server_lib::event_bus::EventBus; /// # use oxspeak_server_lib::match_event; /// # #[derive(Clone, Debug)] struct User { name: String } /// # #[derive(Clone, Debug)] struct UdpMetric { value: f32 } /// # let bus = Arc::new(EventBus::new()); /// # tokio_test::block_on(async { /// let mut rx = bus.on_raw("user-connected"); /// bus.emit("user-connected", User { name: "Alice".into() }); /// /// if let Ok(evt) = rx.recv().await { /// match_event!(evt, /// User => |u| println!("User: {:?}", u), /// UdpMetric => |m| println!("Metric: {:?}", m), /// ); /// } /// # }); /// ``` #[macro_export] macro_rules! match_event { ($evt:expr, $($type:ty => $handler:expr),+ $(,)?) => { $( if let Some(val) = ($evt).downcast_ref::<$type>() { ($handler)(val.clone()); } else )+ { // No matching type → silently ignored } }; } // ───────────────────────────────────────────────────────────────────────────── // Tests // ───────────────────────────────────────────────────────────────────────────── #[cfg(test)] mod tests;