aboutsummaryrefslogtreecommitdiff
path: root/src/di_container/asynchronous/binding/builder.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-10-23 18:12:23 +0200
committerHampusM <hampus@hampusmat.com>2022-10-23 18:12:23 +0200
commit9e01cdf341a7866180b3a63d745f3b2d7578d28a (patch)
tree0c036b7b4a68e44b6eb2221bf7beb3c34fe9c1c8 /src/di_container/asynchronous/binding/builder.rs
parent740ef47d49e02ae2f2184f4c347d8eba8aee38fd (diff)
refactor!: reduce DI container coupling
BREAKING CHANGE: You now have to import the DI containers's interfaces to use the DI containers's methods
Diffstat (limited to 'src/di_container/asynchronous/binding/builder.rs')
-rw-r--r--src/di_container/asynchronous/binding/builder.rs355
1 files changed, 130 insertions, 225 deletions
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<Args, Return> = Box<(dyn Fn<Args, Output = Return> + Send + Sync)>;
-/// Binding builder for type `Interface` inside a [`AsyncDIContainer`].
-pub struct AsyncBindingBuilder<Interface>
+/// Binding builder for type `Interface` inside a [`IAsyncDIContainer`].
+///
+/// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer
+pub struct AsyncBindingBuilder<Interface, DIContainerType>
where
Interface: 'static + ?Sized + Send + Sync,
+ DIContainerType: IAsyncDIContainer,
{
- di_container: Arc<AsyncDIContainer>,
+ di_container: Arc<DIContainerType>,
interface_phantom: PhantomData<Interface>,
}
-impl<Interface> AsyncBindingBuilder<Interface>
+impl<Interface, DIContainerType> AsyncBindingBuilder<Interface, DIContainerType>
where
Interface: 'static + ?Sized + Send + Sync,
+ DIContainerType: IAsyncDIContainer,
{
- pub(crate) fn new(di_container: Arc<AsyncDIContainer>) -> Self
+ pub(crate) fn new(di_container: Arc<DIContainerType>) -> 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<Implementation>(
&self,
) -> Result<
- AsyncBindingScopeConfigurator<Interface, Implementation>,
+ AsyncBindingScopeConfigurator<Interface, Implementation, DIContainerType>,
AsyncBindingBuilderError,
>
where
- Implementation: AsyncInjectable,
+ Implementation: AsyncInjectable<DIContainerType>,
{
- {
- let bindings_lock = self.di_container.bindings.lock().await;
-
- if bindings_lock.has::<Interface>(None) {
- return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::<
- Interface,
- >(
- )));
- }
+ if self.di_container.has_binding::<Interface>(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<Args, Return, FactoryFunc>(
&self,
factory_func: &'static FactoryFunc,
- ) -> Result<AsyncBindingWhenConfigurator<Interface>, AsyncBindingBuilderError>
+ ) -> Result<
+ AsyncBindingWhenConfigurator<Interface, DIContainerType>,
+ AsyncBindingBuilderError,
+ >
where
Args: 'static,
Return: 'static + ?Sized,
Interface: Fn<Args, Output = Return> + Send + Sync,
FactoryFunc:
- Fn<(Arc<AsyncDIContainer>,), Output = BoxFn<Args, Return>> + Send + Sync,
+ Fn<(Arc<DIContainerType>,), Output = BoxFn<Args, Return>> + 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::<Interface>(None) {
+ if self.di_container.has_binding::<Interface>(None).await {
return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::<
Interface,
>(
@@ -177,22 +186,24 @@ where
let factory_impl = ThreadsafeCastableFactory::new(factory_func);
- bindings_lock.set::<Interface>(
- None,
- Box::new(crate::provider::r#async::AsyncFactoryProvider::new(
- crate::ptr::ThreadsafeFactoryPtr::new(factory_impl),
- AsyncFactoryVariant::Normal,
- )),
- );
+ self.di_container
+ .set_binding::<Interface>(
+ 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<Args, Return, FactoryFunc>(
&self,
factory_func: &'static FactoryFunc,
- ) -> Result<AsyncBindingWhenConfigurator<Interface>, AsyncBindingBuilderError>
+ ) -> Result<
+ AsyncBindingWhenConfigurator<Interface, DIContainerType>,
+ AsyncBindingBuilderError,
+ >
where
Args: 'static,
Return: 'static + ?Sized,
Interface:
Fn<Args, Output = crate::future::BoxFuture<'static, Return>> + Send + Sync,
FactoryFunc: Fn<
- (Arc<AsyncDIContainer>,),
+ (Arc<DIContainerType>,),
Output = BoxFn<Args, crate::future::BoxFuture<'static, Return>>,
> + 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::<Interface>(None) {
+ if self.di_container.has_binding::<Interface>(None).await {
return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::<
Interface,
>(
@@ -268,29 +283,31 @@ where
let factory_impl = ThreadsafeCastableFactory::new(factory_func);
- bindings_lock.set::<Interface>(
- None,
- Box::new(crate::provider::r#async::AsyncFactoryProvider::new(
- crate::ptr::ThreadsafeFactoryPtr::new(factory_impl),
- AsyncFactoryVariant::Normal,
- )),
- );
+ self.di_container
+ .set_binding::<Interface>(
+ 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<Return, FactoryFunc>(
&self,
factory_func: &'static FactoryFunc,
- ) -> Result<AsyncBindingWhenConfigurator<Interface>, AsyncBindingBuilderError>
+ ) -> Result<
+ AsyncBindingWhenConfigurator<Interface, DIContainerType>,
+ AsyncBindingBuilderError,
+ >
where
Return: 'static + ?Sized,
FactoryFunc: Fn<
- (Arc<AsyncDIContainer>,),
+ (Arc<DIContainerType>,),
Output = BoxFn<(), crate::ptr::TransientPtr<Return>>,
> + 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::<Interface>(None) {
+ if self.di_container.has_binding::<Interface>(None).await {
return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::<
Interface,
>(
@@ -353,22 +373,24 @@ where
let factory_impl = ThreadsafeCastableFactory::new(factory_func);
- bindings_lock.set::<Interface>(
- None,
- Box::new(crate::provider::r#async::AsyncFactoryProvider::new(
- crate::ptr::ThreadsafeFactoryPtr::new(factory_impl),
- AsyncFactoryVariant::Default,
- )),
- );
+ self.di_container
+ .set_binding::<Interface>(
+ 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<Return, FactoryFunc>(
&self,
factory_func: &'static FactoryFunc,
- ) -> Result<AsyncBindingWhenConfigurator<Interface>, AsyncBindingBuilderError>
+ ) -> Result<
+ AsyncBindingWhenConfigurator<Interface, DIContainerType>,
+ AsyncBindingBuilderError,
+ >
where
Return: 'static + ?Sized,
FactoryFunc: Fn<
- (Arc<AsyncDIContainer>,),
+ (Arc<DIContainerType>,),
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::<Interface>(None) {
+ if self.di_container.has_binding::<Interface>(None).await {
return Err(AsyncBindingBuilderError::BindingAlreadyExists(type_name::<
Interface,
>(
@@ -441,13 +467,15 @@ where
let factory_impl = ThreadsafeCastableFactory::new(factory_func);
- bindings_lock.set::<Interface>(
- None,
- Box::new(crate::provider::r#async::AsyncFactoryProvider::new(
- crate::ptr::ThreadsafeFactoryPtr::new(factory_impl),
- AsyncFactoryVariant::AsyncDefault,
- )),
- );
+ self.di_container
+ .set_binding::<Interface>(
+ 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<dyn Error>>
{
- 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::<dyn subjects_async::IUserManager>()
+ .with(eq(None))
+ .return_once(|_name| false)
+ .once();
- di_container
- .bind::<dyn subjects_async::IUserManager>()
- .to::<subjects_async::UserManager>()
- .await?;
+ di_container_mock
+ .expect_set_binding::<dyn subjects_async::IUserManager>()
+ .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<dyn Error>>
- {
- 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::<dyn subjects_async::IUserManager>()
- .to::<subjects_async::UserManager>()
- .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<dyn Error>>
- {
- let mut di_container = AsyncDIContainer::new();
-
- {
- assert_eq!(di_container.bindings.lock().await.count(), 0);
- }
-
- di_container
- .bind::<dyn subjects_async::IUserManager>()
- .to::<subjects_async::UserManager>()
- .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<dyn Error>>
- {
- let mut di_container = AsyncDIContainer::new();
-
- {
- assert_eq!(di_container.bindings.lock().await.count(), 0);
- }
-
- di_container
- .bind::<dyn subjects_async::IUserManager>()
- .to::<subjects_async::UserManager>()
- .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<dyn Error>>
- {
- let mut di_container = AsyncDIContainer::new();
-
- {
- assert_eq!(di_container.bindings.lock().await.count(), 0);
- }
-
- di_container
- .bind::<dyn subjects_async::IUserManager>()
- .to::<subjects_async::UserManager>()
- .await?
- .in_singleton_scope()
- .await?
- .when_named("cool")
- .await?;
-
- {
- assert_eq!(di_container.bindings.lock().await.count(), 1);
- }
+ binding_builder.to::<subjects_async::UserManager>().await?;
Ok(())
}
+ /*
#[tokio::test]
#[cfg(feature = "factory")]
async fn can_bind_to_factory() -> Result<(), Box<dyn Error>>
@@ -613,41 +554,5 @@ mod tests
Ok(())
}
-
- #[tokio::test]
- #[cfg(feature = "factory")]
- async fn can_bind_to_factory_when_named() -> Result<(), Box<dyn Error>>
- {
- 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::<IUserManagerFactory>()
- .to_factory(&|_| {
- Box::new(|| {
- let user_manager: TransientPtr<dyn subjects_async::IUserManager> =
- TransientPtr::new(subjects_async::UserManager::new());
-
- user_manager
- })
- })
- .await?
- .when_named("awesome")
- .await?;
-
- {
- assert_eq!(di_container.bindings.lock().await.count(), 1);
- }
-
- Ok(())
- }
+ */
}