From 5b0c6a52022e67a2d9cee251b3d08b9cb2b5f6cb Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 9 Oct 2022 12:05:24 +0200 Subject: refactor!: reorganize DI containers BREAKING CHANGE: DIContainer, AsyncDIContainer & the binding structs have been relocated --- src/async_di_container.rs | 1641 --------------------------------------------- 1 file changed, 1641 deletions(-) delete mode 100644 src/async_di_container.rs (limited to 'src/async_di_container.rs') diff --git a/src/async_di_container.rs b/src/async_di_container.rs deleted file mode 100644 index 3943dae..0000000 --- a/src/async_di_container.rs +++ /dev/null @@ -1,1641 +0,0 @@ -//! 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::marker::PhantomData; -use std::sync::Arc; - -use tokio::sync::Mutex; - -#[cfg(feature = "factory")] -use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; -use crate::di_container_binding_map::DIContainerBindingMap; -use crate::errors::async_di_container::{ - AsyncBindingBuilderError, - AsyncBindingScopeConfiguratorError, - AsyncBindingWhenConfiguratorError, - AsyncDIContainerError, -}; -use crate::future::BoxFuture; -use crate::interfaces::async_injectable::AsyncInjectable; -use crate::libs::intertrait::cast::error::CastError; -use crate::libs::intertrait::cast::{CastArc, CastBox}; -use crate::provider::r#async::{ - AsyncProvidable, - AsyncSingletonProvider, - AsyncTransientTypeProvider, - IAsyncProvider, -}; -use crate::ptr::{SomeThreadsafePtr, ThreadsafeSingletonPtr, TransientPtr}; - -/// Alias for a threadsafe boxed function. -#[cfg(feature = "factory")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] -pub type BoxFn = Box<(dyn Fn + Send + Sync)>; - -/// When configurator for a binding for type 'Interface' inside a [`AsyncDIContainer`]. -pub struct AsyncBindingWhenConfigurator -where - Interface: 'static + ?Sized + Send + Sync, -{ - di_container: Arc, - interface_phantom: PhantomData, -} - -impl AsyncBindingWhenConfigurator -where - Interface: 'static + ?Sized + Send + Sync, -{ - fn new(di_container: Arc) -> Self - { - Self { - di_container, - interface_phantom: PhantomData, - } - } - - /// Configures the binding to have a name. - /// - /// # Errors - /// Will return Err if no binding for the interface already exists. - pub async fn when_named( - &self, - name: &'static str, - ) -> Result<(), AsyncBindingWhenConfiguratorError> - { - let mut bindings_lock = self.di_container.bindings.lock().await; - - let binding = bindings_lock.remove::(None).map_or_else( - || { - Err(AsyncBindingWhenConfiguratorError::BindingNotFound( - type_name::(), - )) - }, - Ok, - )?; - - bindings_lock.set::(Some(name), binding); - - Ok(()) - } -} - -/// Scope configurator for a binding for type 'Interface' inside a [`AsyncDIContainer`]. -pub struct AsyncBindingScopeConfigurator -where - Interface: 'static + ?Sized + Send + Sync, - Implementation: AsyncInjectable, -{ - di_container: Arc, - interface_phantom: PhantomData, - implementation_phantom: PhantomData, -} - -impl AsyncBindingScopeConfigurator -where - Interface: 'static + ?Sized + Send + Sync, - Implementation: AsyncInjectable, -{ - fn new(di_container: Arc) -> Self - { - Self { - di_container, - interface_phantom: PhantomData, - implementation_phantom: PhantomData, - } - } - - /// Configures the binding to be in a transient scope. - /// - /// This is the default. - pub async fn in_transient_scope(&self) -> AsyncBindingWhenConfigurator - { - let mut bindings_lock = self.di_container.bindings.lock().await; - - bindings_lock.set::( - None, - Box::new(AsyncTransientTypeProvider::::new()), - ); - - AsyncBindingWhenConfigurator::new(self.di_container.clone()) - } - - /// Configures the binding to be in a singleton scope. - /// - /// # Errors - /// Will return Err if resolving the implementation fails. - pub async fn in_singleton_scope( - &self, - ) -> Result, AsyncBindingScopeConfiguratorError> - { - let singleton: ThreadsafeSingletonPtr = - ThreadsafeSingletonPtr::from( - Implementation::resolve(&self.di_container, Vec::new()) - .await - .map_err( - AsyncBindingScopeConfiguratorError::SingletonResolveFailed, - )?, - ); - - let mut bindings_lock = self.di_container.bindings.lock().await; - - bindings_lock - .set::(None, Box::new(AsyncSingletonProvider::new(singleton))); - - Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) - } -} - -/// Binding builder for type `Interface` inside a [`AsyncDIContainer`]. -pub struct AsyncBindingBuilder -where - Interface: 'static + ?Sized + Send + Sync, -{ - di_container: Arc, - interface_phantom: PhantomData, -} - -impl AsyncBindingBuilder -where - Interface: 'static + ?Sized + Send + Sync, -{ - fn new(di_container: Arc) -> Self - { - Self { - di_container, - interface_phantom: PhantomData, - } - } - - /// Creates a binding of type `Interface` to type `Implementation` inside of the - /// associated [`AsyncDIContainer`]. - /// - /// The scope of the binding is transient. But that can be changed by using the - /// returned [`AsyncBindingScopeConfigurator`] - /// - /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding for - /// the interface. - /// - /// # Examples - /// ``` - /// # use std::error::Error; - /// # - /// # use syrette::{AsyncDIContainer, injectable}; - /// # - /// # trait Foo: Send + Sync {} - /// # - /// # struct Bar {} - /// # - /// # #[injectable(Foo, async = true)] - /// # impl Bar { - /// # fn new() -> Self - /// # { - /// # Self {} - /// # } - /// # } - /// # - /// # impl Foo for Bar {} - /// # - /// # #[tokio::main] - /// # async fn main() -> Result<(), Box> - /// # { - /// # let mut di_container = AsyncDIContainer::new(); - /// # - /// di_container.bind::().to::().await?; - /// # - /// # Ok(()) - /// # } - /// ``` - pub async fn to( - &self, - ) -> Result< - AsyncBindingScopeConfigurator, - AsyncBindingBuilderError, - > - where - Implementation: AsyncInjectable, - { - { - let bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { - return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >( - ))); - } - } - - let binding_scope_configurator = - AsyncBindingScopeConfigurator::new(self.di_container.clone()); - - binding_scope_configurator.in_transient_scope().await; - - Ok(binding_scope_configurator) - } - - /// Creates a binding of factory type `Interface` to a factory inside of the - /// associated [`AsyncDIContainer`]. - /// - /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding - /// for the interface. - /// - /// # Examples - /// ``` - /// # use std::error::Error; - /// # - /// # use syrette::{AsyncDIContainer, factory}; - /// # use syrette::ptr::TransientPtr; - /// # - /// # trait Foo: Send + Sync {} - /// # - /// # struct Bar - /// # { - /// # num: i32, - /// # some_str: String - /// # } - /// # - /// # impl Foo for Bar {} - /// # - /// # #[factory(threadsafe = true)] - /// # type FooFactory = dyn Fn(i32, String) -> dyn Foo; - /// # - /// # #[tokio::main] - /// # async fn main() -> Result<(), Box> - /// # { - /// # let mut di_container = AsyncDIContainer::new(); - /// # - /// di_container - /// .bind::() - /// .to_factory(&|_| { - /// Box::new(|num, some_str| { - /// let bar = TransientPtr::new(Bar { num, some_str }); - /// - /// bar as TransientPtr - /// }) - /// }) - /// .await?; - /// # - /// # Ok(()) - /// # } - /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub async fn to_factory( - &self, - factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> - where - Args: 'static, - Return: 'static + ?Sized, - Interface: Fn + Send + Sync, - FactoryFunc: - Fn<(Arc,), Output = BoxFn> + Send + Sync, - { - use crate::provider::r#async::AsyncFactoryVariant; - - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { - return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >( - ))); - } - - let factory_impl = ThreadsafeCastableFactory::new(factory_func); - - bindings_lock.set::( - None, - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::Normal, - )), - ); - - Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) - } - - /// Creates a binding of factory type `Interface` to a async factory inside of the - /// associated [`AsyncDIContainer`]. - /// - /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding - /// for the interface. - /// - /// # Examples - /// ``` - /// # use std::error::Error; - /// # use std::time::Duration; - /// # - /// # use syrette::{AsyncDIContainer, factory, async_closure}; - /// # use syrette::ptr::TransientPtr; - /// # - /// # trait Foo: Send + Sync {} - /// # - /// # struct Bar - /// # { - /// # num: i32, - /// # some_str: String - /// # } - /// # - /// # impl Foo for Bar {} - /// # - /// # #[factory(async = true)] - /// # type FooFactory = dyn Fn(i32, String) -> dyn Foo; - /// # - /// # #[tokio::main] - /// # async fn main() -> Result<(), Box> - /// # { - /// # let mut di_container = AsyncDIContainer::new(); - /// # - /// di_container - /// .bind::() - /// .to_async_factory(&|_| { - /// async_closure!(|num, some_str| { - /// let bar = TransientPtr::new(Bar { num, some_str }); - /// - /// tokio::time::sleep(Duration::from_secs(2)).await; - /// - /// bar as TransientPtr - /// }) - /// }) - /// .await?; - /// # - /// # Ok(()) - /// # } - /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub async fn to_async_factory( - &self, - factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> - where - Args: 'static, - Return: 'static + ?Sized, - Interface: - Fn> + Send + Sync, - FactoryFunc: Fn< - (Arc,), - Output = BoxFn>, - > + Send - + Sync, - { - use crate::provider::r#async::AsyncFactoryVariant; - - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { - return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >( - ))); - } - - let factory_impl = ThreadsafeCastableFactory::new(factory_func); - - bindings_lock.set::( - None, - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::Normal, - )), - ); - - Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) - } - - /// Creates a binding of type `Interface` to a factory that takes no arguments - /// inside of the associated [`AsyncDIContainer`]. - /// - /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding - /// for the interface. - /// - /// # Examples - /// ``` - /// # use std::error::Error; - /// # - /// # use syrette::AsyncDIContainer; - /// # use syrette::ptr::TransientPtr; - /// # - /// # trait Foo: Send + Sync {} - /// # - /// # struct Bar - /// # { - /// # num: i32, - /// # some_str: String - /// # } - /// # - /// # impl Foo for Bar {} - /// # - /// # #[tokio::main] - /// # async fn main() -> Result<(), Box> - /// # { - /// # let mut di_container = AsyncDIContainer::new(); - /// # - /// di_container - /// .bind::() - /// .to_default_factory(&|_| { - /// Box::new(|| { - /// let bar = TransientPtr::new(Bar { - /// num: 42, - /// some_str: "hello".to_string(), - /// }); - /// - /// bar as TransientPtr - /// }) - /// }) - /// .await?; - /// # - /// # Ok(()) - /// # } - /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub async fn to_default_factory( - &self, - factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> - where - Return: 'static + ?Sized, - FactoryFunc: Fn< - (Arc,), - Output = BoxFn<(), crate::ptr::TransientPtr>, - > + Send - + Sync, - { - use crate::provider::r#async::AsyncFactoryVariant; - - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { - return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >( - ))); - } - - let factory_impl = ThreadsafeCastableFactory::new(factory_func); - - bindings_lock.set::( - None, - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::Default, - )), - ); - - Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) - } - - /// Creates a binding of factory type `Interface` to a async factory inside of the - /// associated [`AsyncDIContainer`]. - /// - /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding - /// for the interface. - /// - /// # Examples - /// ``` - /// # use std::error::Error; - /// # use std::time::Duration; - /// # - /// # use syrette::{AsyncDIContainer, async_closure}; - /// # use syrette::ptr::TransientPtr; - /// # - /// # trait Foo: Send + Sync {} - /// # - /// # struct Bar - /// # { - /// # num: i32, - /// # some_str: String - /// # } - /// # - /// # impl Foo for Bar {} - /// # - /// # #[tokio::main] - /// # async fn main() -> Result<(), Box> - /// # { - /// # let mut di_container = AsyncDIContainer::new(); - /// # - /// di_container - /// .bind::() - /// .to_async_default_factory(&|_| { - /// async_closure!(|| { - /// let bar = TransientPtr::new(Bar { - /// num: 42, - /// some_str: "hello".to_string(), - /// }); - /// - /// tokio::time::sleep(Duration::from_secs(1)).await; - /// - /// bar as TransientPtr - /// }) - /// }) - /// .await?; - /// # - /// # Ok(()) - /// # } - /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub async fn to_async_default_factory( - &self, - factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> - where - Return: 'static + ?Sized, - FactoryFunc: Fn< - (Arc,), - Output = BoxFn<(), crate::future::BoxFuture<'static, Return>>, - > + Send - + Sync, - { - use crate::provider::r#async::AsyncFactoryVariant; - - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { - return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >( - ))); - } - - let factory_impl = ThreadsafeCastableFactory::new(factory_func); - - bindings_lock.set::( - None, - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::AsyncDefault, - )), - ); - - Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) - } -} - -/// Dependency injection container. -pub struct AsyncDIContainer -{ - bindings: Mutex>, -} - -impl AsyncDIContainer -{ - /// Returns a new `AsyncDIContainer`. - #[must_use] - pub fn new() -> Arc - { - Arc::new(Self { - bindings: Mutex::new(DIContainerBindingMap::new()), - }) - } - - /// Returns a new [`AsyncBindingBuilder`] for the given interface. - #[must_use] - pub fn bind(self: &mut Arc) -> AsyncBindingBuilder - where - Interface: 'static + ?Sized + Send + Sync, - { - AsyncBindingBuilder::::new(self.clone()) - } - - /// 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::(Vec::new(), None).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::(Vec::new(), Some(name)).await - } - - #[doc(hidden)] - pub async fn get_bound( - self: &Arc, - dependency_history: Vec<&'static str>, - name: Option<&'static str>, - ) -> Result, AsyncDIContainerError> - where - Interface: 'static + ?Sized + Send + Sync, - { - let binding_providable = self - .get_binding_providable::(name, dependency_history) - .await?; - - self.handle_binding_providable(binding_providable).await - } - - async fn handle_binding_providable( - self: &Arc, - binding_providable: AsyncProvidable, - ) -> Result, AsyncDIContainerError> - where - Interface: 'static + ?Sized + Send + Sync, - { - match binding_providable { - AsyncProvidable::Transient(transient_binding) => { - Ok(SomeThreadsafePtr::Transient( - transient_binding.cast::().map_err(|_| { - AsyncDIContainerError::CastFailed { - interface: type_name::(), - binding_kind: "transient", - } - })?, - )) - } - AsyncProvidable::Singleton(singleton_binding) => { - Ok(SomeThreadsafePtr::ThreadsafeSingleton( - singleton_binding - .cast::() - .map_err(|err| match err { - CastError::NotArcCastable(_) => { - AsyncDIContainerError::InterfaceNotAsync(type_name::< - Interface, - >( - )) - } - CastError::CastFailed { from: _, to: _ } => { - AsyncDIContainerError::CastFailed { - interface: type_name::(), - binding_kind: "singleton", - } - } - })?, - )) - } - #[cfg(feature = "factory")] - AsyncProvidable::Factory(factory_binding) => { - use crate::interfaces::factory::IThreadsafeFactory; - - let factory = factory_binding - .cast::,), Interface>>() - .map_err(|err| match err { - CastError::NotArcCastable(_) => { - AsyncDIContainerError::InterfaceNotAsync( - type_name::(), - ) - } - CastError::CastFailed { from: _, to: _ } => { - AsyncDIContainerError::CastFailed { - interface: type_name::(), - binding_kind: "factory", - } - } - })?; - - Ok(SomeThreadsafePtr::ThreadsafeFactory( - factory(self.clone()).into(), - )) - } - #[cfg(feature = "factory")] - AsyncProvidable::DefaultFactory(binding) => { - use crate::interfaces::factory::IThreadsafeFactory; - - let default_factory = Self::cast_factory_binding::< - dyn IThreadsafeFactory< - (Arc,), - dyn Fn<(), Output = TransientPtr> + Send + Sync, - >, - >(binding, "default factory")?; - - Ok(SomeThreadsafePtr::Transient(default_factory(self.clone())())) - } - #[cfg(feature = "factory")] - AsyncProvidable::AsyncDefaultFactory(binding) => { - use crate::interfaces::factory::IThreadsafeFactory; - - let async_default_factory = Self::cast_factory_binding::< - dyn IThreadsafeFactory< - (Arc,), - dyn Fn<(), Output = BoxFuture<'static, TransientPtr>> - + Send - + Sync, - >, - >( - binding, "async default factory" - )?; - - Ok(SomeThreadsafePtr::Transient( - async_default_factory(self.clone())().await, - )) - } - } - } - - #[cfg(feature = "factory")] - fn cast_factory_binding( - factory_binding: Arc, - binding_kind: &'static str, - ) -> Result, AsyncDIContainerError> - { - factory_binding.cast::().map_err(|err| match err { - CastError::NotArcCastable(_) => { - AsyncDIContainerError::InterfaceNotAsync(type_name::()) - } - CastError::CastFailed { from: _, to: _ } => { - AsyncDIContainerError::CastFailed { - interface: type_name::(), - binding_kind, - } - } - }) - } - - async fn get_binding_providable( - self: &Arc, - name: Option<&'static str>, - dependency_history: Vec<&'static str>, - ) -> Result - where - Interface: 'static + ?Sized + Send + Sync, - { - let provider; - - { - let bindings_lock = self.bindings.lock().await; - - provider = bindings_lock - .get::(name) - .map_or_else( - || { - Err(AsyncDIContainerError::BindingNotFound { - interface: type_name::(), - name, - }) - }, - Ok, - )? - .clone(); - } - - provider - .provide(self, dependency_history) - .await - .map_err(|err| AsyncDIContainerError::BindingResolveFailed { - reason: err, - interface: type_name::(), - }) - } -} - -#[cfg(test)] -mod tests -{ - use std::error::Error; - - use async_trait::async_trait; - use mockall::mock; - - use super::*; - use crate::errors::injectable::InjectableError; - use crate::ptr::TransientPtr; - - mod subjects - { - //! Test subjects. - - use std::fmt::Debug; - use std::sync::Arc; - - use async_trait::async_trait; - use syrette_macros::declare_interface; - - use super::AsyncDIContainer; - use crate::interfaces::async_injectable::AsyncInjectable; - use crate::ptr::TransientPtr; - - pub trait IUserManager: Send + Sync - { - fn add_user(&self, user_id: i128); - - fn remove_user(&self, user_id: i128); - } - - pub struct UserManager {} - - impl UserManager - { - pub fn new() -> Self - { - Self {} - } - } - - impl IUserManager for UserManager - { - fn add_user(&self, _user_id: i128) - { - // ... - } - - fn remove_user(&self, _user_id: i128) - { - // ... - } - } - - use crate as syrette; - - declare_interface!(UserManager -> IUserManager); - - #[async_trait] - impl AsyncInjectable for UserManager - { - async fn resolve( - _: &Arc, - _dependency_history: Vec<&'static str>, - ) -> Result, crate::errors::injectable::InjectableError> - where - Self: Sized, - { - Ok(TransientPtr::new(Self::new())) - } - } - - pub trait INumber: Send + Sync - { - fn get(&self) -> i32; - - fn set(&mut self, number: i32); - } - - impl PartialEq for dyn INumber - { - fn eq(&self, other: &Self) -> bool - { - self.get() == other.get() - } - } - - impl Debug for dyn INumber - { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - f.write_str(format!("{}", self.get()).as_str()) - } - } - - pub struct Number - { - pub num: i32, - } - - impl Number - { - pub fn new() -> Self - { - Self { num: 0 } - } - } - - impl INumber for Number - { - fn get(&self) -> i32 - { - self.num - } - - fn set(&mut self, number: i32) - { - self.num = number; - } - } - - declare_interface!(Number -> INumber, async = true); - - #[async_trait] - impl AsyncInjectable for Number - { - async fn resolve( - _: &Arc, - _dependency_history: Vec<&'static str>, - ) -> Result, crate::errors::injectable::InjectableError> - where - Self: Sized, - { - Ok(TransientPtr::new(Self::new())) - } - } - } - - #[tokio::test] - async fn can_bind_to() -> Result<(), Box> - { - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to::() - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - async fn can_bind_to_transient() -> Result<(), Box> - { - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to::() - .await? - .in_transient_scope() - .await; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - async fn can_bind_to_transient_when_named() -> Result<(), Box> - { - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to::() - .await? - .in_transient_scope() - .await - .when_named("regular") - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - async fn can_bind_to_singleton() -> Result<(), Box> - { - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to::() - .await? - .in_singleton_scope() - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - async fn can_bind_to_singleton_when_named() -> Result<(), Box> - { - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to::() - .await? - .in_singleton_scope() - .await? - .when_named("cool") - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - #[cfg(feature = "factory")] - async fn can_bind_to_factory() -> Result<(), Box> - { - use crate as syrette; - use crate::factory; - - #[factory(threadsafe = true)] - type IUserManagerFactory = dyn Fn() -> dyn subjects::IUserManager; - - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to_factory(&|_| { - Box::new(|| { - let user_manager: TransientPtr = - TransientPtr::new(subjects::UserManager::new()); - - user_manager - }) - }) - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - #[cfg(feature = "factory")] - async fn can_bind_to_factory_when_named() -> Result<(), Box> - { - use crate as syrette; - use crate::factory; - - #[factory(threadsafe = true)] - type IUserManagerFactory = dyn Fn() -> dyn subjects::IUserManager; - - let mut di_container = AsyncDIContainer::new(); - - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } - - di_container - .bind::() - .to_factory(&|_| { - Box::new(|| { - let user_manager: TransientPtr = - TransientPtr::new(subjects::UserManager::new()); - - user_manager - }) - }) - .await? - .when_named("awesome") - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } - - #[tokio::test] - async fn can_get() -> Result<(), Box> - { - mock! { - Provider {} - - #[async_trait] - impl IAsyncProvider for Provider - { - async fn provide( - &self, - di_container: &Arc, - dependency_history: Vec<&'static str>, - ) -> Result; - - fn do_clone(&self) -> Box; - } - } - - let di_container = AsyncDIContainer::new(); - - let mut mock_provider = MockProvider::new(); - - mock_provider.expect_do_clone().returning(|| { - let mut inner_mock_provider = MockProvider::new(); - - inner_mock_provider.expect_provide().returning(|_, _| { - Ok(AsyncProvidable::Transient(TransientPtr::new( - subjects::UserManager::new(), - ))) - }); - - Box::new(inner_mock_provider) - }); - - { - di_container - .bindings - .lock() - .await - .set::(None, Box::new(mock_provider)); - } - - di_container - .get::() - .await? - .transient()?; - - Ok(()) - } - - #[tokio::test] - async fn can_get_named() -> Result<(), Box> - { - mock! { - Provider {} - - #[async_trait] - impl IAsyncProvider for Provider - { - async fn provide( - &self, - di_container: &Arc, - dependency_history: Vec<&'static str>, - ) -> Result; - - fn do_clone(&self) -> Box; - } - } - - let di_container = AsyncDIContainer::new(); - - let mut mock_provider = MockProvider::new(); - - mock_provider.expect_do_clone().returning(|| { - let mut inner_mock_provider = MockProvider::new(); - - inner_mock_provider.expect_provide().returning(|_, _| { - Ok(AsyncProvidable::Transient(TransientPtr::new( - subjects::UserManager::new(), - ))) - }); - - Box::new(inner_mock_provider) - }); - - { - di_container - .bindings - .lock() - .await - .set::( - Some("special"), - Box::new(mock_provider), - ); - } - - di_container - .get_named::("special") - .await? - .transient()?; - - Ok(()) - } - - #[tokio::test] - async fn can_get_singleton() -> Result<(), Box> - { - mock! { - Provider {} - - #[async_trait] - impl IAsyncProvider for Provider - { - async fn provide( - &self, - di_container: &Arc, - dependency_history: Vec<&'static str>, - ) -> Result; - - fn do_clone(&self) -> Box; - } - } - - let di_container = AsyncDIContainer::new(); - - let mut mock_provider = MockProvider::new(); - - let mut singleton = ThreadsafeSingletonPtr::new(subjects::Number::new()); - - ThreadsafeSingletonPtr::get_mut(&mut singleton).unwrap().num = 2820; - - mock_provider.expect_do_clone().returning(move || { - let mut inner_mock_provider = MockProvider::new(); - - let singleton_clone = singleton.clone(); - - inner_mock_provider.expect_provide().returning(move |_, _| { - Ok(AsyncProvidable::Singleton(singleton_clone.clone())) - }); - - Box::new(inner_mock_provider) - }); - - { - di_container - .bindings - .lock() - .await - .set::(None, Box::new(mock_provider)); - } - - let first_number_rc = di_container - .get::() - .await? - .threadsafe_singleton()?; - - assert_eq!(first_number_rc.get(), 2820); - - let second_number_rc = di_container - .get::() - .await? - .threadsafe_singleton()?; - - assert_eq!(first_number_rc.as_ref(), second_number_rc.as_ref()); - - Ok(()) - } - - #[tokio::test] - async fn can_get_singleton_named() -> Result<(), Box> - { - mock! { - Provider {} - - #[async_trait] - impl IAsyncProvider for Provider - { - async fn provide( - &self, - di_container: &Arc, - dependency_history: Vec<&'static str>, - ) -> Result; - - fn do_clone(&self) -> Box; - } - } - - let di_container = AsyncDIContainer::new(); - - let mut mock_provider = MockProvider::new(); - - let mut singleton = ThreadsafeSingletonPtr::new(subjects::Number::new()); - - ThreadsafeSingletonPtr::get_mut(&mut singleton).unwrap().num = 2820; - - mock_provider.expect_do_clone().returning(move || { - let mut inner_mock_provider = MockProvider::new(); - - let singleton_clone = singleton.clone(); - - inner_mock_provider.expect_provide().returning(move |_, _| { - Ok(AsyncProvidable::Singleton(singleton_clone.clone())) - }); - - Box::new(inner_mock_provider) - }); - - { - di_container - .bindings - .lock() - .await - .set::(Some("cool"), Box::new(mock_provider)); - } - - let first_number_rc = di_container - .get_named::("cool") - .await? - .threadsafe_singleton()?; - - assert_eq!(first_number_rc.get(), 2820); - - let second_number_rc = di_container - .get_named::("cool") - .await? - .threadsafe_singleton()?; - - assert_eq!(first_number_rc.as_ref(), second_number_rc.as_ref()); - - Ok(()) - } - - #[tokio::test] - #[cfg(feature = "factory")] - async fn can_get_factory() -> Result<(), Box> - { - trait IUserManager: Send + Sync - { - fn add_user(&mut self, user_id: i128); - - fn remove_user(&mut self, user_id: i128); - } - - struct UserManager - { - users: Vec, - } - - impl UserManager - { - fn new(users: Vec) -> Self - { - Self { users } - } - } - - impl IUserManager for UserManager - { - fn add_user(&mut self, user_id: i128) - { - self.users.push(user_id); - } - - fn remove_user(&mut self, user_id: i128) - { - let user_index = - self.users.iter().position(|user| *user == user_id).unwrap(); - - self.users.remove(user_index); - } - } - - use crate as syrette; - - #[crate::factory(threadsafe = true)] - type IUserManagerFactory = dyn Fn(Vec) -> dyn IUserManager; - - mock! { - Provider {} - - #[async_trait] - impl IAsyncProvider for Provider - { - async fn provide( - &self, - di_container: &Arc, - dependency_history: Vec<&'static str>, - ) -> Result; - - fn do_clone(&self) -> Box; - } - } - - let di_container = AsyncDIContainer::new(); - - let mut mock_provider = MockProvider::new(); - - mock_provider.expect_do_clone().returning(|| { - type FactoryFunc = Box< - (dyn Fn<(Vec,), Output = TransientPtr> + Send + Sync) - >; - - let mut inner_mock_provider = MockProvider::new(); - - let factory_func: &'static (dyn Fn< - (Arc,), - Output = FactoryFunc> + Send + Sync) = &|_| { - Box::new(|users| { - let user_manager: TransientPtr = - TransientPtr::new(UserManager::new(users)); - - user_manager - }) - }; - - inner_mock_provider.expect_provide().returning(|_, _| { - Ok(AsyncProvidable::Factory( - crate::ptr::ThreadsafeFactoryPtr::new( - ThreadsafeCastableFactory::new(factory_func), - ), - )) - }); - - Box::new(inner_mock_provider) - }); - - { - di_container - .bindings - .lock() - .await - .set::(None, Box::new(mock_provider)); - } - - di_container - .get::() - .await? - .threadsafe_factory()?; - - Ok(()) - } - - #[tokio::test] - #[cfg(feature = "factory")] - async fn can_get_factory_named() -> Result<(), Box> - { - trait IUserManager: Send + Sync - { - fn add_user(&mut self, user_id: i128); - - fn remove_user(&mut self, user_id: i128); - } - - struct UserManager - { - users: Vec, - } - - impl UserManager - { - fn new(users: Vec) -> Self - { - Self { users } - } - } - - impl IUserManager for UserManager - { - fn add_user(&mut self, user_id: i128) - { - self.users.push(user_id); - } - - fn remove_user(&mut self, user_id: i128) - { - let user_index = - self.users.iter().position(|user| *user == user_id).unwrap(); - - self.users.remove(user_index); - } - } - - use crate as syrette; - - #[crate::factory(threadsafe = true)] - type IUserManagerFactory = dyn Fn(Vec) -> dyn IUserManager; - - mock! { - Provider {} - - #[async_trait] - impl IAsyncProvider for Provider - { - async fn provide( - &self, - di_container: &Arc, - dependency_history: Vec<&'static str>, - ) -> Result; - - fn do_clone(&self) -> Box; - } - } - - let di_container = AsyncDIContainer::new(); - - let mut mock_provider = MockProvider::new(); - - mock_provider.expect_do_clone().returning(|| { - type FactoryFunc = Box< - (dyn Fn<(Vec,), Output = TransientPtr> + Send + Sync) - >; - - let mut inner_mock_provider = MockProvider::new(); - - let factory_func: &'static (dyn Fn< - (Arc,), - Output = FactoryFunc> + Send + Sync) = &|_| { - Box::new(|users| { - let user_manager: TransientPtr = - TransientPtr::new(UserManager::new(users)); - - user_manager - }) - }; - - inner_mock_provider.expect_provide().returning(|_, _| { - Ok(AsyncProvidable::Factory( - crate::ptr::ThreadsafeFactoryPtr::new( - ThreadsafeCastableFactory::new(factory_func), - ), - )) - }); - - Box::new(inner_mock_provider) - }); - - { - di_container - .bindings - .lock() - .await - .set::(Some("special"), Box::new(mock_provider)); - } - - di_container - .get_named::("special") - .await? - .threadsafe_factory()?; - - Ok(()) - } -} -- cgit v1.2.3-18-g5258