//! Asynchronous dependency injection container. //! //! # Examples //! ``` //! use std::collections::HashMap; //! use std::error::Error; //! //! use syrette::{injectable, AsyncDIContainer}; //! //! trait IDatabaseService: Send + Sync //! { //! fn get_all_records(&self, table_name: String) -> HashMap; //! } //! //! struct DatabaseService {} //! //! #[injectable(IDatabaseService, async = true)] //! impl DatabaseService //! { //! fn new() -> Self //! { //! Self {} //! } //! } //! //! impl IDatabaseService for DatabaseService //! { //! fn get_all_records(&self, table_name: String) -> HashMap //! { //! // Do stuff here //! HashMap::::new() //! } //! } //! //! #[tokio::main] //! async fn main() -> Result<(), Box> //! { //! let mut di_container = AsyncDIContainer::new(); //! //! di_container //! .bind::() //! .to::() //! .await?; //! //! let database_service = di_container //! .get::() //! .await? //! .transient()?; //! //! Ok(()) //! } //! ``` use std::any::type_name; use std::sync::Arc; use async_lock::Mutex; use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder; use crate::di_container::binding_storage::DIContainerBindingStorage; use crate::di_container::BindingOptions; use crate::errors::async_di_container::AsyncDIContainerError; use crate::private::cast::arc::CastArc; use crate::private::cast::boxed::CastBox; use crate::private::cast::error::CastError; use crate::provider::r#async::{AsyncProvidable, IAsyncProvider}; use crate::ptr::SomePtr; use crate::util::use_double; use_double!(crate::dependency_history::DependencyHistory); pub mod binding; /// Async dependency injection container. pub struct AsyncDIContainer { binding_storage: Mutex>>, } impl AsyncDIContainer { /// Returns a new `AsyncDIContainer`. #[must_use] pub fn new() -> Arc { Arc::new(Self { binding_storage: Mutex::new(DIContainerBindingStorage::new()), }) } } #[cfg_attr(test, mockall::automock)] impl AsyncDIContainer { /// Returns a new [`AsyncBindingBuilder`] for the given interface. #[allow(clippy::missing_panics_doc)] pub fn bind(self: &mut Arc) -> AsyncBindingBuilder where Interface: 'static + ?Sized + Send + Sync, { #[cfg(test)] panic!("Bind function is unusable when testing"); #[cfg(not(test))] AsyncBindingBuilder::new(self.clone(), DependencyHistory::new) } /// Returns the type bound with `Interface`. /// /// # Errors /// Will return `Err` if: /// - No binding for `Interface` exists /// - Resolving the binding for `Interface` fails /// - Casting the binding for `Interface` fails pub async fn get( self: &Arc, ) -> Result, AsyncDIContainerError> where Interface: 'static + ?Sized + Send + Sync, { self.get_bound::(DependencyHistory::new(), BindingOptions::new()) .await } /// Returns the type bound with `Interface` and the specified name. /// /// # Errors /// Will return `Err` if: /// - No binding for `Interface` with name `name` exists /// - Resolving the binding for `Interface` fails /// - Casting the binding for `Interface` fails pub async fn get_named( self: &Arc, name: &'static str, ) -> Result, AsyncDIContainerError> where Interface: 'static + ?Sized + Send + Sync, { self.get_bound::( DependencyHistory::new(), BindingOptions::new().name(name), ) .await } /// Returns the type bound with `Interface` where the binding has the specified /// options. /// /// `dependency_history` is passed to the bound type when it is being resolved. /// /// # Errors /// Will return `Err` if: /// - No binding for `Interface` exists /// - Resolving the binding for `Interface` fails /// - Casting the binding for `Interface` fails /// /// # Examples /// ``` /// # use syrette::di_container::asynchronous::AsyncDIContainer; /// # use syrette::dependency_history::DependencyHistory; /// # use syrette::di_container::BindingOptions; /// # /// # struct EventHandler {} /// # struct Button {} /// # /// # Box::pin(async { /// # let di_container = AsyncDIContainer::new(); /// # /// let mut dependency_history = DependencyHistory::new(); /// /// dependency_history.push::(); /// /// di_container /// .get_bound::