noema 0.4.0

Noema IOC and DI framework for Rust
Documentation
//! Typed event publish/subscribe: user-owned transports, JSON wire, compile-time registry.
//!
//! Noema links `EventPublisher<E>` → your `publish_raw` and your consumer → `dispatch(name, bytes)` → handlers.

#[macro_use]
mod macros;

pub mod dispatch;
pub mod json;

pub use dispatch::{
    DispatchContext, EventDispatch, EventDispatcherContext, InvokeMode, ReceiveFn, SubscriberEntry,
    SubscriberRegistry,
};
pub use json::{from_bytes, to_bytes};
pub use noema_macros::event;

use std::future::Future;
use std::sync::Arc;

/// Boxed error type for events operations.
pub type BoxDynError = Box<dyn std::error::Error + Send + Sync>;

/// Result type for events operations.
pub type NoemaResult<T> = Result<T, BoxDynError>;

/// Event metadata (wire name + description). Use `#[event(name = "...")]`.
pub trait Event: Send + Sync + 'static {
    /// Stable wire identifier used in registry and `publish_raw`.
    const WIRE_NAME: &'static str;

    fn name(&self) -> String {
        Self::WIRE_NAME.to_string()
    }

    fn describe(&self) -> String {
        format!("Event {}", Self::WIRE_NAME)
    }
}

/// User transport: send `(name, json_bytes)` to Kafka or similar.
#[async_trait::async_trait]
pub trait EventPublishRaw: Send + Sync {
    async fn publish_raw(&self, name: &str, payload: &[u8]) -> NoemaResult<()>;
}

/// Typed publish (generated by `publisher!` on your transport struct).
#[async_trait::async_trait]
pub trait EventPublisher<E: Event + Send + Sync>: Send + Sync {
    async fn publish(&self, event: E) -> NoemaResult<()>;
}

/// Business handler for event type `E`.
#[async_trait::async_trait]
pub trait EventListener<E: Event + Send + Sync + 'static>: Send + Sync {
    fn name(&self) -> String {
        std::any::type_name::<Self>().to_string()
    }

    async fn handle(&self, event: Arc<E>) -> NoemaResult<()>;

    async fn on_error(
        &self,
        error_handler: Arc<dyn BackgroundErrorHandler + Send + Sync>,
        error: BoxDynError,
        _event: Arc<E>,
    ) {
        error_handler.handle(error, E::WIRE_NAME, self.name()).await;
    }
}

/// Spawns handler futures (per transport instance).
pub trait BackgroundSpawner: Send + Sync {
    fn spawn(&self, fut: std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'static>>);
}

/// Handles errors from dispatch and listeners (per transport instance).
#[async_trait::async_trait]
pub trait BackgroundErrorHandler: Send + Sync {
    async fn handle(&self, error: BoxDynError, event_name: &str, handler_name: String);
}

#[cfg(test)]
mod tests;