noema 0.4.0

Noema IOC and DI framework for Rust
Documentation
/// Register request handlers and optional per-input pipeline behaviors (compile-time).
///
/// Optionally call [`global_pipeline!`](crate::global_pipeline) and
/// [`enable_global_pipeline`](crate::mediator::global::enable_global_pipeline) to prepend global behaviors.
///
/// # Syntax
///
/// ```ignore
/// request!(MyInput: MyInputHandler);
/// request!(CreateOrder: CreateOrderHandler => [ValidateOrder, LogRequest]);
/// ```
///
/// Handler and each behavior MUST implement [`Injectable`](crate::core::Injectable).
#[macro_export]
macro_rules! request {
    ($($input:path: $handler:ty $(=> [$($behavior:ty),* $(,)?])?),* $(,)?) => {
        $(
            $crate::__request_one!($input, $handler, [$($($behavior),*)*]);
        )*
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __request_one {
    ($input:path, $handler:ty, []) => {
        const _: () = {
            use std::sync::Arc;

            use $crate::core::{Container, Injectable};
            use $crate::mediator::global::GLOBAL;
            use ::std::sync::atomic::Ordering;
            use $crate::mediator::pipeline::run_pipeline;
            use $crate::mediator::{InputHandler, Mediator};

            #[async_trait::async_trait]
            impl Mediator<$input> for Container {
                async fn send(
                    input: $input,
                ) -> $crate::mediator::NoemaResult<<$input as $crate::mediator::Input>::Output> {
                    let input = Arc::new(input);
                    let handler: $crate::arc_dyn!(InputHandler<$input>) =
                        Arc::new(<$handler as Injectable<Container>>::inject(&Container));

                    let mut behaviors = Vec::new();
                    if GLOBAL.load(Ordering::Acquire) {
                        __noema_emit_globals!($input, behaviors);
                    }
                    let behaviors = Arc::<[_]>::from(behaviors);

                    run_pipeline(input, handler, behaviors).await
                }
            }
        };
    };

    ($input:path, $handler:ty, [$($behavior:ty),* $(,)?]) => {
        const _: () = {
            use std::sync::Arc;

            use $crate::core::{Container, Injectable};
            use $crate::mediator::global::GLOBAL;
            use ::std::sync::atomic::Ordering;
            use $crate::mediator::pipeline::run_pipeline;
            use $crate::mediator::{InputHandler, Mediator};

            #[async_trait::async_trait]
            impl Mediator<$input> for Container {
                async fn send(
                    input: $input,
                ) -> $crate::mediator::NoemaResult<<$input as $crate::mediator::Input>::Output> {
                    let input = Arc::new(input);
                    let handler: $crate::arc_dyn!(InputHandler<$input>) =
                        Arc::new(<$handler as Injectable<Container>>::inject(&Container));

                    let mut behaviors = Vec::new();
                    if GLOBAL.load(Ordering::Acquire) {
                        __noema_emit_globals!($input, behaviors);
                    }
                    $(
                        behaviors.push(
                            Arc::new(
                                <$behavior as Injectable<Container>>::inject(&Container),
                            ) as ::std::sync::Arc<
                                dyn $crate::mediator::PipelineBehavior<$input> + Send + Sync,
                            >,
                        );
                    )*
                    let behaviors = Arc::<[_]>::from(behaviors);

                    run_pipeline(input, handler, behaviors).await
                }
            }
        };
    };
}