arcly-http 0.1.1

Enterprise-grade NestJS-inspired web framework on axum: zero-lock DI, declarative controllers, multi-tenant data routing, transactional outbox, ABAC, and a self-documenting OpenAPI surface
Documentation
//! Lock-free async event bus. Listeners register once; emissions iterate a
//! frozen snapshot under a single `RwLock` read.

use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use futures::future::{join_all, BoxFuture};

pub trait Listener: Send + Sync + 'static {
    fn on_event(&self, payload: &serde_json::Value) -> BoxFuture<'static, ()>;
}

type Listeners = HashMap<&'static str, Vec<Arc<dyn Listener>>>;

#[derive(Default, Clone)]
pub struct EventBus {
    inner: Arc<RwLock<Listeners>>,
}

impl EventBus {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn subscribe(&self, event: &'static str, listener: Arc<dyn Listener>) {
        self.inner
            .write()
            .unwrap()
            .entry(event)
            .or_default()
            .push(listener);
    }

    pub async fn emit(&self, event: &'static str, payload: serde_json::Value) {
        let snapshot: Vec<Arc<dyn Listener>> = self
            .inner
            .read()
            .unwrap()
            .get(event)
            .cloned()
            .unwrap_or_default();
        let futs = snapshot.iter().map(|l| l.on_event(&payload));
        join_all(futs).await;
    }
}