aro-web 1.0.0

HTTP/ADR layer for the Aro web framework
Documentation
//! HTTP/ADR layer for the Aro web framework.
//!
//! This crate provides the web adapter built on Axum. Axum is re-exported at
//! the crate root as an intentional escape hatch: advanced features (auth,
//! `WebSockets`, `OpenAPI`, static files, etc.) are delegated to the Axum/tower
//! ecosystem rather than wrapped by Aro.

mod app;
pub mod cache;
pub mod config;
pub mod dep;
pub mod error;
pub mod fallback;
pub mod health;
pub mod json_body;
pub mod middleware;
pub mod state;

#[cfg(any(test, feature = "test-utils"))]
pub mod test;

pub use app::App;
pub use axum;
pub use axum::extract::DefaultBodyLimit;

#[doc(hidden)]
pub use ::pastey as __private_pastey;

// SSE support
pub use axum::response::sse::{Event, KeepAlive, Sse};

/// Collect route handlers into an `axum::Router<AroState>`.
///
/// Takes a list of handler function names and chains their generated
/// `__aro_register_<fn>` functions into a single Router. Non-empty invocations
/// produce a `Router<AroState>`, making handlers compatible with both stateless
/// handlers and handlers using `Dep<T>` extractors.
///
/// # Examples
///
/// ```ignore
/// use aro_web::routes;
///
/// // Stateless handlers
/// let router = routes![hello, get_user, create_user];
/// App::new().routes_with_state(router).build();
///
/// // Stateful handlers using Dep<T>
/// let router = routes![handler_with_dep, stateless_handler];
/// App::new()
///     .register::<dyn MyService>(service)
///     .routes_with_state(router)
///     .build();
/// ```
///
/// Module-qualified paths are supported:
///
/// ```ignore
/// let router = routes![users::get_user, users::create_user];
/// ```
///
/// An empty invocation returns an empty `Router<()>` for composition with
/// stateless routes; use [`App::routes_with_state`](App::routes_with_state) only
/// when the router contains handlers:
///
/// ```ignore
/// let router = routes![];
/// ```
#[macro_export]
macro_rules! routes {
    () => {
        $crate::axum::Router::new()
    };
    ($($($segment:ident)::+),+ $(,)?) => {
        $crate::__private_pastey::paste! {{
            let router = $crate::axum::Router::new();
            $(
                let router = $crate::__aro_route_register!(router [] $($segment)::+);
            )+
            router
        }}
    };
}

/// Internal helper: resolve a handler path to its registration function and call it.
///
/// Uses brackets `[prefix segments]` as an accumulator for the module path.
#[doc(hidden)]
#[macro_export]
macro_rules! __aro_route_register {
    // Peel off a leading module segment, push it into the accumulator.
    ($router:ident [$($prefix:tt)*] $first:ident :: $($rest:ident)::+) => {
        $crate::__aro_route_register!($router [$($prefix)* $first ::] $($rest)::+)
    };
    // Base case: single ident remaining is the handler name.
    ($router:ident [$($prefix:tt)*] $handler:ident) => {
        $crate::__private_pastey::paste! { $($prefix)* [<__aro_register_ $handler>]($router) }
    };
}