From 9e01cdf341a7866180b3a63d745f3b2d7578d28a Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 23 Oct 2022 18:12:23 +0200 Subject: refactor!: reduce DI container coupling BREAKING CHANGE: You now have to import the DI containers's interfaces to use the DI containers's methods --- src/di_container/asynchronous/binding/builder.rs | 355 +++++++++-------------- 1 file changed, 130 insertions(+), 225 deletions(-) (limited to 'src/di_container/asynchronous/binding/builder.rs') diff --git a/src/di_container/asynchronous/binding/builder.rs b/src/di_container/asynchronous/binding/builder.rs index 6daba30..d9ad0e6 100644 --- a/src/di_container/asynchronous/binding/builder.rs +++ b/src/di_container/asynchronous/binding/builder.rs @@ -1,4 +1,6 @@ -//! Binding builder for types inside of a [`AsyncDIContainer`]. +//! Binding builder for types inside of a [`IAsyncDIContainer`]. +//! +//! [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer use std::any::type_name; use std::marker::PhantomData; use std::sync::Arc; @@ -6,29 +8,33 @@ use std::sync::Arc; use crate::di_container::asynchronous::binding::scope_configurator::AsyncBindingScopeConfigurator; #[cfg(feature = "factory")] use crate::di_container::asynchronous::binding::when_configurator::AsyncBindingWhenConfigurator; +use crate::di_container::asynchronous::IAsyncDIContainer; use crate::errors::async_di_container::AsyncBindingBuilderError; use crate::interfaces::async_injectable::AsyncInjectable; -use crate::AsyncDIContainer; /// 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)>; -/// Binding builder for type `Interface` inside a [`AsyncDIContainer`]. -pub struct AsyncBindingBuilder +/// Binding builder for type `Interface` inside a [`IAsyncDIContainer`]. +/// +/// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer +pub struct AsyncBindingBuilder where Interface: 'static + ?Sized + Send + Sync, + DIContainerType: IAsyncDIContainer, { - di_container: Arc, + di_container: Arc, interface_phantom: PhantomData, } -impl AsyncBindingBuilder +impl AsyncBindingBuilder where Interface: 'static + ?Sized + Send + Sync, + DIContainerType: IAsyncDIContainer, { - pub(crate) fn new(di_container: Arc) -> Self + pub(crate) fn new(di_container: Arc) -> Self { Self { di_container, @@ -37,20 +43,21 @@ where } /// Creates a binding of type `Interface` to type `Implementation` inside of the - /// associated [`AsyncDIContainer`]. + /// associated [`IAsyncDIContainer`]. /// /// 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 + /// Will return Err if the associated [`IAsyncDIContainer`] already have a binding for /// the interface. /// /// # Examples /// ``` /// # use std::error::Error; /// # - /// # use syrette::{AsyncDIContainer, injectable}; + /// # use syrette::injectable; + /// # use syrette::di_container::asynchronous::prelude::*; /// # /// # trait Foo: Send + Sync {} /// # @@ -76,24 +83,22 @@ where /// # Ok(()) /// # } /// ``` + /// + /// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer pub async fn to( &self, ) -> Result< - AsyncBindingScopeConfigurator, + AsyncBindingScopeConfigurator, AsyncBindingBuilderError, > where - Implementation: AsyncInjectable, + Implementation: AsyncInjectable, { - { - let bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { - return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >( - ))); - } + if self.di_container.has_binding::(None).await { + return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< + Interface, + >( + ))); } let binding_scope_configurator = @@ -105,17 +110,18 @@ where } /// Creates a binding of factory type `Interface` to a factory inside of the - /// associated [`AsyncDIContainer`]. + /// associated [`IAsyncDIContainer`]. /// /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding + /// Will return Err if the associated [`IAsyncDIContainer`] already have a binding /// for the interface. /// /// # Examples /// ``` /// # use std::error::Error; /// # - /// # use syrette::{AsyncDIContainer, factory}; + /// # use syrette::{factory}; + /// # use syrette::di_container::asynchronous::prelude::*; /// # use syrette::ptr::TransientPtr; /// # /// # trait Foo: Send + Sync {} @@ -150,25 +156,28 @@ where /// # Ok(()) /// # } /// ``` + /// + /// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer #[cfg(feature = "factory")] #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] pub async fn to_factory( &self, factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> + ) -> Result< + AsyncBindingWhenConfigurator, + AsyncBindingBuilderError, + > where Args: 'static, Return: 'static + ?Sized, Interface: Fn + Send + Sync, FactoryFunc: - Fn<(Arc,), Output = BoxFn> + Send + Sync, + Fn<(Arc,), Output = BoxFn> + Send + Sync, { use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; use crate::provider::r#async::AsyncFactoryVariant; - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { + if self.di_container.has_binding::(None).await { return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< Interface, >( @@ -177,22 +186,24 @@ where 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, - )), - ); + self.di_container + .set_binding::( + None, + Box::new(crate::provider::r#async::AsyncFactoryProvider::new( + crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), + AsyncFactoryVariant::Normal, + )), + ) + .await; Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) } /// Creates a binding of factory type `Interface` to a async factory inside of the - /// associated [`AsyncDIContainer`]. + /// associated [`IAsyncDIContainer`]. /// /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding + /// Will return Err if the associated [`IAsyncDIContainer`] already have a binding /// for the interface. /// /// # Examples @@ -200,7 +211,8 @@ where /// # use std::error::Error; /// # use std::time::Duration; /// # - /// # use syrette::{AsyncDIContainer, factory, async_closure}; + /// # use syrette::{factory, async_closure}; + /// # use syrette::di_container::asynchronous::prelude::*; /// # use syrette::ptr::TransientPtr; /// # /// # trait Foo: Send + Sync {} @@ -237,19 +249,24 @@ where /// # Ok(()) /// # } /// ``` + /// + /// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer #[cfg(feature = "factory")] #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] pub async fn to_async_factory( &self, factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> + ) -> Result< + AsyncBindingWhenConfigurator, + AsyncBindingBuilderError, + > where Args: 'static, Return: 'static + ?Sized, Interface: Fn> + Send + Sync, FactoryFunc: Fn< - (Arc,), + (Arc,), Output = BoxFn>, > + Send + Sync, @@ -257,9 +274,7 @@ where use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; use crate::provider::r#async::AsyncFactoryVariant; - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { + if self.di_container.has_binding::(None).await { return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< Interface, >( @@ -268,29 +283,31 @@ where 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, - )), - ); + self.di_container + .set_binding::( + None, + Box::new(crate::provider::r#async::AsyncFactoryProvider::new( + crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), + AsyncFactoryVariant::Normal, + )), + ) + .await; 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`]. + /// inside of the associated [`IAsyncDIContainer`]. /// /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding + /// Will return Err if the associated [`IAsyncDIContainer`] already have a binding /// for the interface. /// /// # Examples /// ``` /// # use std::error::Error; /// # - /// # use syrette::AsyncDIContainer; + /// # use syrette::di_container::asynchronous::prelude::*; /// # use syrette::ptr::TransientPtr; /// # /// # trait Foo: Send + Sync {} @@ -325,16 +342,21 @@ where /// # Ok(()) /// # } /// ``` + /// + /// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer #[cfg(feature = "factory")] #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] pub async fn to_default_factory( &self, factory_func: &'static FactoryFunc, - ) -> Result, AsyncBindingBuilderError> + ) -> Result< + AsyncBindingWhenConfigurator, + AsyncBindingBuilderError, + > where Return: 'static + ?Sized, FactoryFunc: Fn< - (Arc,), + (Arc,), Output = BoxFn<(), crate::ptr::TransientPtr>, > + Send + Sync, @@ -342,9 +364,7 @@ where use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; use crate::provider::r#async::AsyncFactoryVariant; - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { + if self.di_container.has_binding::(None).await { return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< Interface, >( @@ -353,22 +373,24 @@ where 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, - )), - ); + self.di_container + .set_binding::( + None, + Box::new(crate::provider::r#async::AsyncFactoryProvider::new( + crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), + AsyncFactoryVariant::Default, + )), + ) + .await; Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) } /// Creates a binding of factory type `Interface` to a async factory inside of the - /// associated [`AsyncDIContainer`]. + /// associated [`IAsyncDIContainer`]. /// /// # Errors - /// Will return Err if the associated [`AsyncDIContainer`] already have a binding + /// Will return Err if the associated [`IAsyncDIContainer`] already have a binding /// for the interface. /// /// # Examples @@ -376,7 +398,8 @@ where /// # use std::error::Error; /// # use std::time::Duration; /// # - /// # use syrette::{AsyncDIContainer, async_closure}; + /// # use syrette::async_closure; + /// # use syrette::di_container::asynchronous::prelude::*; /// # use syrette::ptr::TransientPtr; /// # /// # trait Foo: Send + Sync {} @@ -413,16 +436,21 @@ where /// # Ok(()) /// # } /// ``` + /// + /// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer #[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> + ) -> Result< + AsyncBindingWhenConfigurator, + AsyncBindingBuilderError, + > where Return: 'static + ?Sized, FactoryFunc: Fn< - (Arc,), + (Arc,), Output = BoxFn<(), crate::future::BoxFuture<'static, Return>>, > + Send + Sync, @@ -430,9 +458,7 @@ where use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; use crate::provider::r#async::AsyncFactoryVariant; - let mut bindings_lock = self.di_container.bindings.lock().await; - - if bindings_lock.has::(None) { + if self.di_container.has_binding::(None).await { return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::< Interface, >( @@ -441,13 +467,15 @@ where 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, - )), - ); + self.di_container + .set_binding::( + None, + Box::new(crate::provider::r#async::AsyncFactoryProvider::new( + crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), + AsyncFactoryVariant::AsyncDefault, + )), + ) + .await; Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone())) } @@ -458,127 +486,40 @@ mod tests { use std::error::Error; + use mockall::predicate::eq; + use super::*; - use crate::ptr::TransientPtr; + use crate::test_utils::mocks::async_di_container::MockAsyncDIContainer; use crate::test_utils::subjects_async; #[tokio::test] async fn can_bind_to() -> Result<(), Box> { - let mut di_container = AsyncDIContainer::new(); + let mut di_container_mock = MockAsyncDIContainer::new(); - { - assert_eq!(di_container.bindings.lock().await.count(), 0); - } + di_container_mock + .expect_has_binding::() + .with(eq(None)) + .return_once(|_name| false) + .once(); - di_container - .bind::() - .to::() - .await?; + di_container_mock + .expect_set_binding::() + .withf(|name, _provider| name.is_none()) + .return_once(|_name, _provider| ()) + .once(); - { - 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); - } + let binding_builder = AsyncBindingBuilder::< + dyn subjects_async::IUserManager, + MockAsyncDIContainer, + >::new(Arc::new(di_container_mock)); - 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); - } + binding_builder.to::().await?; Ok(()) } + /* #[tokio::test] #[cfg(feature = "factory")] async fn can_bind_to_factory() -> Result<(), Box> @@ -613,41 +554,5 @@ mod tests 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_async::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_async::UserManager::new()); - - user_manager - }) - }) - .await? - .when_named("awesome") - .await?; - - { - assert_eq!(di_container.bindings.lock().await.count(), 1); - } - - Ok(()) - } + */ } -- cgit v1.2.3-18-g5258