//! Asynchronous dependency injection container. //! //! # Examples //! ``` //! use std::collections::HashMap; //! use std::error::Error; //! //! use syrette::di_container::asynchronous::prelude::*; //! use syrette::injectable; //! //! 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 async_trait::async_trait; 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::future::BoxFuture; 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; pub mod prelude; /// Async dependency injection container interface. /// /// **This trait is sealed and cannot be implemented for types outside this crate.** #[async_trait] pub trait IAsyncDIContainer: Sized + 'static + Send + Sync + details::DIContainerInternals { /// Returns a new [`AsyncBindingBuilder`] for the given interface. fn bind(self: &mut Arc) -> AsyncBindingBuilder where Interface: 'static + ?Sized + Send + Sync; /// 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 fn get<'a, 'b, Interface>( self: &'a Arc, ) -> BoxFuture<'b, Result, AsyncDIContainerError>> where Interface: 'static + 'b + ?Sized + Send + Sync, 'a: 'b, Self: 'b; /// 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 fn get_named<'a, 'b, Interface>( self: &'a Arc, name: &'static str, ) -> BoxFuture<'b, Result, AsyncDIContainerError>> where Interface: 'static + 'b + ?Sized + Send + Sync, 'a: 'b, Self: 'b; /// 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::di_container::asynchronous::IAsyncDIContainer; /// # 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::