From ca86952c1486b7f2313fef62e6cacf36e248efd2 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 13 Jul 2024 16:26:28 +0200 Subject: refactor: move & rename all mod.rs files --- src/di_container/asynchronous.rs | 839 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 839 insertions(+) create mode 100644 src/di_container/asynchronous.rs (limited to 'src/di_container/asynchronous.rs') diff --git a/src/di_container/asynchronous.rs b/src/di_container/asynchronous.rs new file mode 100644 index 0000000..c993b8b --- /dev/null +++ b/src/di_container/asynchronous.rs @@ -0,0 +1,839 @@ +//! 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::()?; +//! +//! let database_service = di_container +//! .get::() +//! .await? +//! .transient()?; +//! +//! Ok(()) +//! } +//! ``` +use std::any::type_name; + +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. +#[derive(Default)] +pub struct AsyncDIContainer +{ + binding_storage: DIContainerBindingStorage>, +} + +impl AsyncDIContainer +{ + /// Returns a new `AsyncDIContainer`. + #[must_use] + pub fn new() -> Self + { + Self { + binding_storage: DIContainerBindingStorage::new(), + } + } +} + +#[cfg_attr(test, mockall::automock)] +impl AsyncDIContainer +{ + /// Returns a new [`AsyncBindingBuilder`] for the given interface. + /// + /// # Examples + /// ``` + /// # use syrette::{AsyncDIContainer, injectable}; + /// # + /// # struct DiskWriter {} + /// # + /// # #[injectable(async = true)] + /// # impl DiskWriter + /// # { + /// # fn new() -> Self + /// # { + /// # Self {} + /// # } + /// # } + /// # + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// let mut di_container = AsyncDIContainer::new(); + /// + /// di_container.bind::().to::()?; + /// # + /// # Ok(()) + /// # } + /// ``` + #[allow(clippy::missing_panics_doc)] + pub fn bind(&mut self) -> AsyncBindingBuilder<'_, Interface> + where + Interface: 'static + ?Sized + Send + Sync, + { + #[cfg(test)] + panic!("Bind function is unusable when testing"); + + #[cfg(not(test))] + AsyncBindingBuilder::new(self, 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 + /// + /// # Examples + /// ``` + /// # use syrette::{AsyncDIContainer, injectable}; + /// # + /// # struct DeviceManager {} + /// # + /// # #[injectable(async = true)] + /// # impl DeviceManager + /// # { + /// # fn new() -> Self + /// # { + /// # Self {} + /// # } + /// # } + /// # + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// let mut di_container = AsyncDIContainer::new(); + /// + /// di_container.bind::().to::()?; + /// + /// let device_manager = di_container.get::().await?.transient(); + /// # + /// # Ok(()) + /// # } + /// ``` + pub async fn get( + &self, + ) -> 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 + /// + /// # Examples + /// ``` + /// # use syrette::{AsyncDIContainer, injectable}; + /// # + /// # struct DeviceManager {} + /// # + /// # #[injectable(async = true)] + /// # impl DeviceManager + /// # { + /// # fn new() -> Self + /// # { + /// # Self {} + /// # } + /// # } + /// # + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// let mut di_container = AsyncDIContainer::new(); + /// + /// di_container + /// .bind::() + /// .to::()? + /// .in_transient_scope() + /// .when_named("usb"); + /// + /// let device_manager = di_container + /// .get_named::("usb") + /// .await? + /// .transient(); + /// # + /// # Ok(()) + /// # } + /// ``` + pub async fn get_named( + &self, + 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::