auto-di 0.4.0

Ergonomic async-aware automatic dependency injection for Rust
Documentation
use std::{any::Any, marker::PhantomData, sync::Arc};

use crate::{Container, DiError, ResolutionContext};

/// Resolves a dependency each time [`Provider::get`] is called.
pub struct Provider<T> {
    container: Container,
    context: ResolutionContext,
    _marker: PhantomData<fn() -> T>,
}

impl<T> Clone for Provider<T> {
    fn clone(&self) -> Self {
        Self {
            container: self.container.clone(),
            context: self.context.clone(),
            _marker: PhantomData,
        }
    }
}

impl<T> Provider<T>
where
    T: Any + Send + Sync,
{
    #[doc(hidden)]
    pub fn from_context(container: Container, context: ResolutionContext) -> Self {
        Self {
            container,
            context,
            _marker: PhantomData,
        }
    }

    pub async fn get(&self) -> Result<Arc<T>, DiError> {
        self.container.resolve_dependency::<T>(&self.context).await
    }
}

/// Resolves a dependency on first access and caches it locally.
pub struct Lazy<T> {
    container: Container,
    context: ResolutionContext,
    cell: tokio::sync::OnceCell<Arc<T>>,
}

impl<T> Lazy<T>
where
    T: Any + Send + Sync,
{
    #[doc(hidden)]
    pub fn from_context(container: Container, context: ResolutionContext) -> Self {
        Self {
            container,
            context,
            cell: tokio::sync::OnceCell::new(),
        }
    }

    pub async fn get(&self) -> Result<&Arc<T>, DiError> {
        self.cell
            .get_or_try_init(|| async {
                self.container.resolve_dependency::<T>(&self.context).await
            })
            .await
    }
}