rok-container 0.3.4

IoC service container and dependency injection for the rok ecosystem
Documentation
use std::any::Any;
use std::sync::Arc;

use axum::extract::FromRequestParts;
use axum::http::request::Parts;

use crate::container::Container;
use crate::error::ContainerError;

/// Axum extractor that resolves `Arc<T>` from an [`Arc<Container>`] extension.
///
/// Requires [`Arc<Container>`] to be installed as an Axum [`Extension`](axum::Extension)
/// layer.
///
/// # Example
///
/// ```rust,ignore
/// use std::sync::Arc;
/// use axum::{routing::post, Extension, Router};
/// use rok_container::{Container, Inject};
///
/// async fn store(Inject(svc): Inject<UserService>) -> impl IntoResponse {
///     svc.create_user().await
/// }
///
/// let container = Arc::new(Container::new());
/// container.singleton(UserService::new());
///
/// let app = Router::new()
///     .route("/users", post(store))
///     .layer(Extension(container));
/// ```
pub struct Inject<T>(pub Arc<T>);

impl<T> Inject<T> {
    /// Unwrap the inner `Arc<T>`.
    pub fn into_inner(self) -> Arc<T> {
        self.0
    }
}

impl<T, S> FromRequestParts<S> for Inject<T>
where
    T: Any + Send + Sync + 'static,
    S: Send + Sync,
{
    type Rejection = ContainerError;

    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
        let container = parts
            .extensions
            .get::<Arc<Container>>()
            .cloned()
            .ok_or(ContainerError::NotRegistered(std::any::type_name::<T>()))?;
        Ok(Inject(container.make::<T>()?))
    }
}