arcature 2026.2.1

Arcature application framework: a high-level Application facade over the certified Arcature subsystems, with the low-level Axum/Tower escape hatch preserved.
Documentation
//! `Service` trait and `Inject<T>` extractor (A8, ADR-0004).
//!
//! A **service** is cheap composition from application resources. It is
//! constructed per request from application state `S` via [`Resolve<S>`],
//! NOT stored as a singleton, NOT resolved through a runtime container.
//!
//! The `#[service]` proc-macro generates:
//! - `impl DxComponent` — the static name for `arc services` inspection.
//! - `impl Service` — the service marker + `DEPS` metadata for `arc check`.
//! - `impl Resolve<S>` — per-state construction from field types.
//!
//! Handlers receive a service via the [`Inject<T>`] extractor, which is a
//! genuine Axum `FromRequestParts` implementation — Axum remains the handler
//! runtime (ADR-0004 §1; no Arcature dispatcher).
//!
//! # Service dependency cycles
//!
//! Services compose by **value**, not by reference. A service `A` that
//! depends on service `B` stores `B` as a field. A cycle (`A` contains `B`
//! contains `A`) would require infinite size — `rustc` rejects it at
//! compile time. No runtime cycle detection is needed; the type system
//! makes service cycles impossible.
//!
//! # Module service privacy
//!
//! A module's internal services are private by default. Privacy is
//! enforced by `rustc` visibility (a `pub(crate)` service cannot be named
//! outside its crate) and by `arc check` validation (which cross-references
//! `ModuleDescriptor.services` / `exports` / `imports`). The `DEPS`
//! metadata generated by `#[service]` feeds `arc check`'s graph
//! validation (A13).

use axum::extract::FromRequestParts;

use super::DxComponent;
use super::resolve::Resolve;

/// A service: cheap per-request composition from application resources.
///
/// The `#[service]` macro generates this impl. The trait extends
/// [`DxComponent`] (for the static `NAME` used in `arc services`) and adds
/// `DEPS` — the dependency type names for `arc check` graph validation.
///
/// `DEPS` lists the simple type names of the service's fields. For
/// `LinkService { db: Db, cache: Cache }`, `DEPS = ["Db", "Cache"]`.
/// Resources (Db, Cache) are leaf nodes in the graph; service-to-service
/// edges are what `arc check` validates for cycles and privacy.
pub trait Service: DxComponent + Send + Sync + 'static {
    /// The dependency type names, for `arc check` graph validation.
    /// Empty for services with no typed dependencies.
    const DEPS: &'static [&'static str] = &[];
}

/// Axum extractor: construct a `T: Resolve<S>` from application state.
///
/// A genuine `FromRequestParts` implementation — Axum remains the handler
/// runtime. The extractor calls `T::resolve(state)` to construct the
/// value cheaply from the application's `Arc`/`Clone`-backed resources.
///
/// # Example
///
/// ```ignore
/// async fn show(link: Bound<Link>, svc: Inject<LinkService>) -> Result<Json<Link>> {
///     let link = link.into_inner();
///     let report = svc.recent_for(link.id);
///     // ...
/// }
/// ```
///
/// `Inject<T>` works for any `T: Resolve<S>`, including built-in resources
/// (`Inject<Db>`) and services (`Inject<LinkService>`). The `Service`
/// trait is metadata, not a bound on the extractor.
pub struct Inject<T>(pub T);

impl<T> Inject<T> {
    /// Extract the resolved value.
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T, S> FromRequestParts<S> for Inject<T>
where
    T: Resolve<S>,
    S: Send + Sync,
{
    type Rejection = std::convert::Infallible;

    async fn from_request_parts(
        _parts: &mut axum::http::request::Parts,
        state: &S,
    ) -> Result<Self, Self::Rejection> {
        Ok(Inject(T::resolve(state)))
    }
}