aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml2
-rw-r--r--examples/async-factory/main.rs3
-rw-r--r--examples/async/bootstrap.rs3
-rw-r--r--examples/async/main.rs12
-rw-r--r--examples/basic/bootstrap.rs2
-rw-r--r--examples/basic/main.rs1
-rw-r--r--examples/factory/bootstrap.rs2
-rw-r--r--examples/factory/main.rs3
-rw-r--r--examples/generics/bootstrap.rs3
-rw-r--r--examples/generics/main.rs6
-rw-r--r--examples/named/bootstrap.rs2
-rw-r--r--examples/named/main.rs1
-rw-r--r--examples/unbound/bootstrap.rs2
-rw-r--r--examples/unbound/main.rs11
-rw-r--r--examples/with-3rd-party/bootstrap.rs3
-rw-r--r--examples/with-3rd-party/main.rs6
-rw-r--r--macros/src/injectable/implementation.rs16
-rw-r--r--src/di_container/asynchronous/binding/builder.rs355
-rw-r--r--src/di_container/asynchronous/binding/scope_configurator.rs58
-rw-r--r--src/di_container/asynchronous/binding/when_configurator.rs46
-rw-r--r--src/di_container/asynchronous/mod.rs217
-rw-r--r--src/di_container/asynchronous/prelude.rs3
-rw-r--r--src/di_container/binding_map.rs7
-rw-r--r--src/di_container/blocking/binding/builder.rs273
-rw-r--r--src/di_container/blocking/binding/scope_configurator.rs45
-rw-r--r--src/di_container/blocking/binding/when_configurator.rs46
-rw-r--r--src/di_container/blocking/mod.rs166
-rw-r--r--src/di_container/blocking/prelude.rs2
-rw-r--r--src/interfaces/async_injectable.rs12
-rw-r--r--src/interfaces/injectable.rs12
-rw-r--r--src/lib.rs1
-rw-r--r--src/provider/async.rs103
-rw-r--r--src/provider/blocking.rs75
-rw-r--r--src/test_utils.rs172
34 files changed, 1013 insertions, 658 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 7c5f905..cd21b22 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -47,7 +47,7 @@ async-trait = { version = "0.1.57", optional = true }
tokio = { version = "1.20.1", features = ["sync"], optional = true }
[dev_dependencies]
-mockall = "0.11.1"
+mockall = { git = "https://github.com/HampusMat/mockall" }
anyhow = "1.0.62"
third-party-lib = { path = "./examples/with-3rd-party/third-party-lib" }
tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread", "time"] }
diff --git a/examples/async-factory/main.rs b/examples/async-factory/main.rs
index 715abf5..b9beded 100644
--- a/examples/async-factory/main.rs
+++ b/examples/async-factory/main.rs
@@ -5,8 +5,9 @@
use std::time::Duration;
use anyhow::Result;
+use syrette::di_container::asynchronous::prelude::*;
use syrette::ptr::TransientPtr;
-use syrette::{async_closure, declare_default_factory, factory, AsyncDIContainer};
+use syrette::{async_closure, declare_default_factory, factory};
use tokio::time::sleep;
trait IFoo: Send + Sync
diff --git a/examples/async/bootstrap.rs b/examples/async/bootstrap.rs
index 9b495c2..5f90d88 100644
--- a/examples/async/bootstrap.rs
+++ b/examples/async/bootstrap.rs
@@ -1,8 +1,9 @@
use std::sync::Arc;
use anyhow::Result;
+use syrette::declare_default_factory;
+use syrette::di_container::asynchronous::prelude::*;
use syrette::ptr::TransientPtr;
-use syrette::{declare_default_factory, AsyncDIContainer};
use crate::animals::cat::Cat;
use crate::animals::dog::Dog;
diff --git a/examples/async/main.rs b/examples/async/main.rs
index 03e36e1..d051b94 100644
--- a/examples/async/main.rs
+++ b/examples/async/main.rs
@@ -2,19 +2,19 @@
#![deny(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
-use anyhow::Result;
-use tokio::spawn;
-
mod animals;
mod bootstrap;
mod food;
mod interfaces;
-use bootstrap::bootstrap;
-use interfaces::dog::IDog;
-use interfaces::human::IHuman;
+use anyhow::Result;
+use syrette::di_container::asynchronous::prelude::*;
+use tokio::spawn;
+use crate::bootstrap::bootstrap;
+use crate::interfaces::dog::IDog;
use crate::interfaces::food::IFoodFactory;
+use crate::interfaces::human::IHuman;
#[tokio::main]
async fn main() -> Result<()>
diff --git a/examples/basic/bootstrap.rs b/examples/basic/bootstrap.rs
index 2c45676..1cad500 100644
--- a/examples/basic/bootstrap.rs
+++ b/examples/basic/bootstrap.rs
@@ -1,7 +1,7 @@
use std::error::Error;
use std::rc::Rc;
-use syrette::DIContainer;
+use syrette::di_container::blocking::prelude::*;
use crate::animals::cat::Cat;
use crate::animals::dog::Dog;
diff --git a/examples/basic/main.rs b/examples/basic/main.rs
index dbc9215..7b129e9 100644
--- a/examples/basic/main.rs
+++ b/examples/basic/main.rs
@@ -11,6 +11,7 @@ mod interfaces;
use bootstrap::bootstrap;
use interfaces::dog::IDog;
use interfaces::human::IHuman;
+use syrette::di_container::blocking::prelude::*;
fn main() -> Result<(), Box<dyn Error>>
{
diff --git a/examples/factory/bootstrap.rs b/examples/factory/bootstrap.rs
index f8bef6e..e535dd2 100644
--- a/examples/factory/bootstrap.rs
+++ b/examples/factory/bootstrap.rs
@@ -1,8 +1,8 @@
use std::error::Error;
use std::rc::Rc;
+use syrette::di_container::blocking::prelude::*;
use syrette::ptr::TransientPtr;
-use syrette::DIContainer;
use crate::interfaces::user::{IUser, IUserFactory};
use crate::interfaces::user_manager::IUserManager;
diff --git a/examples/factory/main.rs b/examples/factory/main.rs
index 0f1a97b..d428717 100644
--- a/examples/factory/main.rs
+++ b/examples/factory/main.rs
@@ -9,8 +9,9 @@ mod user_manager;
use std::error::Error;
-use bootstrap::bootstrap;
+use syrette::di_container::blocking::prelude::*;
+use crate::bootstrap::bootstrap;
use crate::interfaces::user_manager::IUserManager;
fn main() -> Result<(), Box<dyn Error>>
diff --git a/examples/generics/bootstrap.rs b/examples/generics/bootstrap.rs
index 98d03db..4034aa8 100644
--- a/examples/generics/bootstrap.rs
+++ b/examples/generics/bootstrap.rs
@@ -1,6 +1,7 @@
use std::rc::Rc;
-use syrette::{di_container_bind, DIContainer};
+use syrette::di_container::blocking::prelude::*;
+use syrette::di_container_bind;
use crate::interfaces::printer::IPrinter;
use crate::printer::Printer;
diff --git a/examples/generics/main.rs b/examples/generics/main.rs
index f491aa0..7910cad 100644
--- a/examples/generics/main.rs
+++ b/examples/generics/main.rs
@@ -4,8 +4,10 @@ mod printer;
use std::error::Error;
-use bootstrap::bootstrap;
-use interfaces::printer::IPrinter;
+use syrette::di_container::blocking::prelude::*;
+
+use crate::bootstrap::bootstrap;
+use crate::interfaces::printer::IPrinter;
fn main() -> Result<(), Box<dyn Error>>
{
diff --git a/examples/named/bootstrap.rs b/examples/named/bootstrap.rs
index 5f63b47..f7edc5d 100644
--- a/examples/named/bootstrap.rs
+++ b/examples/named/bootstrap.rs
@@ -1,7 +1,7 @@
use std::rc::Rc;
use anyhow::Result;
-use syrette::DIContainer;
+use syrette::di_container::blocking::prelude::*;
use crate::interfaces::ninja::INinja;
use crate::interfaces::weapon::IWeapon;
diff --git a/examples/named/main.rs b/examples/named/main.rs
index 5411a12..e7cccd0 100644
--- a/examples/named/main.rs
+++ b/examples/named/main.rs
@@ -9,6 +9,7 @@ mod ninja;
mod shuriken;
use anyhow::Result;
+use syrette::di_container::blocking::prelude::*;
use crate::bootstrap::bootstrap;
use crate::interfaces::ninja::INinja;
diff --git a/examples/unbound/bootstrap.rs b/examples/unbound/bootstrap.rs
index 04643dc..61e5326 100644
--- a/examples/unbound/bootstrap.rs
+++ b/examples/unbound/bootstrap.rs
@@ -1,7 +1,7 @@
use std::rc::Rc;
use anyhow::Result;
-use syrette::DIContainer;
+use syrette::di_container::blocking::prelude::*;
use crate::animal_store::AnimalStore;
use crate::animals::dog::Dog;
diff --git a/examples/unbound/main.rs b/examples/unbound/main.rs
index f8dddbb..29fa0d4 100644
--- a/examples/unbound/main.rs
+++ b/examples/unbound/main.rs
@@ -2,16 +2,17 @@
#![deny(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
-use anyhow::Result;
-
mod animal_store;
mod animals;
mod bootstrap;
mod interfaces;
-use bootstrap::bootstrap;
-use interfaces::dog::IDog;
-use interfaces::human::IHuman;
+use anyhow::Result;
+use syrette::di_container::blocking::prelude::*;
+
+use crate::bootstrap::bootstrap;
+use crate::interfaces::dog::IDog;
+use crate::interfaces::human::IHuman;
fn main() -> Result<()>
{
diff --git a/examples/with-3rd-party/bootstrap.rs b/examples/with-3rd-party/bootstrap.rs
index 4fea754..9a55eb1 100644
--- a/examples/with-3rd-party/bootstrap.rs
+++ b/examples/with-3rd-party/bootstrap.rs
@@ -1,8 +1,9 @@
use std::error::Error;
use std::rc::Rc;
+use syrette::declare_default_factory;
+use syrette::di_container::blocking::prelude::*;
use syrette::ptr::TransientPtr;
-use syrette::{declare_default_factory, DIContainer};
use third_party_lib::Shuriken;
use crate::interfaces::ninja::INinja;
diff --git a/examples/with-3rd-party/main.rs b/examples/with-3rd-party/main.rs
index e48c78f..520038e 100644
--- a/examples/with-3rd-party/main.rs
+++ b/examples/with-3rd-party/main.rs
@@ -2,12 +2,14 @@
#![deny(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
-use std::error::Error;
-
mod bootstrap;
mod interfaces;
mod ninja;
+use std::error::Error;
+
+use syrette::di_container::blocking::prelude::*;
+
use crate::bootstrap::bootstrap;
use crate::interfaces::ninja::INinja;
diff --git a/macros/src/injectable/implementation.rs b/macros/src/injectable/implementation.rs
index 9542a98..6cde446 100644
--- a/macros/src/injectable/implementation.rs
+++ b/macros/src/injectable/implementation.rs
@@ -132,11 +132,13 @@ impl<Dep: IDependency> InjectableImpl<Dep>
quote! {
#maybe_doc_hidden
- impl #generics syrette::interfaces::async_injectable::AsyncInjectable for #self_type
+ impl #generics syrette::interfaces::async_injectable::AsyncInjectable<
+ syrette::di_container::asynchronous::AsyncDIContainer
+ > for #self_type
{
fn resolve<'di_container, 'fut>(
#di_container_var: &'di_container std::sync::Arc<
- syrette::AsyncDIContainer
+ syrette::di_container::asynchronous::AsyncDIContainer
>,
mut #dependency_history_var: Vec<&'static str>,
) -> syrette::future::BoxFuture<
@@ -153,6 +155,7 @@ impl<Dep: IDependency> InjectableImpl<Dep>
Box::pin(async move {
use std::any::type_name;
+ use syrette::di_container::asynchronous::IAsyncDIContainer;
use syrette::errors::injectable::InjectableError;
let self_type_name = type_name::<#self_type>();
@@ -183,10 +186,14 @@ impl<Dep: IDependency> InjectableImpl<Dep>
quote! {
#maybe_doc_hidden
- impl #generics syrette::interfaces::injectable::Injectable for #self_type
+ impl #generics syrette::interfaces::injectable::Injectable<
+ syrette::di_container::blocking::DIContainer
+ > for #self_type
{
fn resolve(
- #di_container_var: &std::rc::Rc<syrette::DIContainer>,
+ #di_container_var: &std::rc::Rc<
+ syrette::di_container::blocking::DIContainer
+ >,
mut #dependency_history_var: Vec<&'static str>,
) -> Result<
syrette::ptr::TransientPtr<Self>,
@@ -194,6 +201,7 @@ impl<Dep: IDependency> InjectableImpl<Dep>
{
use std::any::type_name;
+ use syrette::di_container::blocking::IDIContainer;
use syrette::errors::injectable::InjectableError;
let self_type_name = type_name::<#self_type>();
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(())
- }
+ */
}
diff --git a/src/di_container/asynchronous/binding/scope_configurator.rs b/src/di_container/asynchronous/binding/scope_configurator.rs
index 2b0f0b3..fd42fea 100644
--- a/src/di_container/asynchronous/binding/scope_configurator.rs
+++ b/src/di_container/asynchronous/binding/scope_configurator.rs
@@ -1,31 +1,38 @@
-//! Scope configurator for a binding for types inside of a [`AsyncDIContainer`].
+//! Scope configurator for a binding for types inside of a [`IAsyncDIContainer`].
+//!
+//! [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer
use std::marker::PhantomData;
use std::sync::Arc;
use crate::di_container::asynchronous::binding::when_configurator::AsyncBindingWhenConfigurator;
+use crate::di_container::asynchronous::IAsyncDIContainer;
use crate::errors::async_di_container::AsyncBindingScopeConfiguratorError;
use crate::interfaces::async_injectable::AsyncInjectable;
use crate::provider::r#async::{AsyncSingletonProvider, AsyncTransientTypeProvider};
use crate::ptr::ThreadsafeSingletonPtr;
-use crate::AsyncDIContainer;
-/// Scope configurator for a binding for type 'Interface' inside a [`AsyncDIContainer`].
-pub struct AsyncBindingScopeConfigurator<Interface, Implementation>
+/// Scope configurator for a binding for type 'Interface' inside a [`IAsyncDIContainer`].
+///
+/// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer
+pub struct AsyncBindingScopeConfigurator<Interface, Implementation, DIContainerType>
where
Interface: 'static + ?Sized + Send + Sync,
- Implementation: AsyncInjectable,
+ Implementation: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
- di_container: Arc<AsyncDIContainer>,
+ di_container: Arc<DIContainerType>,
interface_phantom: PhantomData<Interface>,
implementation_phantom: PhantomData<Implementation>,
}
-impl<Interface, Implementation> AsyncBindingScopeConfigurator<Interface, Implementation>
+impl<Interface, Implementation, DIContainerType>
+ AsyncBindingScopeConfigurator<Interface, Implementation, DIContainerType>
where
Interface: 'static + ?Sized + Send + Sync,
- Implementation: AsyncInjectable,
+ Implementation: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
- pub(crate) fn new(di_container: Arc<AsyncDIContainer>) -> Self
+ pub(crate) fn new(di_container: Arc<DIContainerType>) -> Self
{
Self {
di_container,
@@ -37,14 +44,18 @@ where
/// Configures the binding to be in a transient scope.
///
/// This is the default.
- pub async fn in_transient_scope(&self) -> AsyncBindingWhenConfigurator<Interface>
+ pub async fn in_transient_scope(
+ &self,
+ ) -> AsyncBindingWhenConfigurator<Interface, DIContainerType>
{
- let mut bindings_lock = self.di_container.bindings.lock().await;
-
- bindings_lock.set::<Interface>(
- None,
- Box::new(AsyncTransientTypeProvider::<Implementation>::new()),
- );
+ self.di_container
+ .set_binding::<Interface>(
+ None,
+ Box::new(
+ AsyncTransientTypeProvider::<Implementation, DIContainerType>::new(),
+ ),
+ )
+ .await;
AsyncBindingWhenConfigurator::new(self.di_container.clone())
}
@@ -55,7 +66,10 @@ where
/// Will return Err if resolving the implementation fails.
pub async fn in_singleton_scope(
&self,
- ) -> Result<AsyncBindingWhenConfigurator<Interface>, AsyncBindingScopeConfiguratorError>
+ ) -> Result<
+ AsyncBindingWhenConfigurator<Interface, DIContainerType>,
+ AsyncBindingScopeConfiguratorError,
+ >
{
let singleton: ThreadsafeSingletonPtr<Implementation> =
ThreadsafeSingletonPtr::from(
@@ -66,10 +80,12 @@ where
)?,
);
- let mut bindings_lock = self.di_container.bindings.lock().await;
-
- bindings_lock
- .set::<Interface>(None, Box::new(AsyncSingletonProvider::new(singleton)));
+ self.di_container
+ .set_binding::<Interface>(
+ None,
+ Box::new(AsyncSingletonProvider::new(singleton)),
+ )
+ .await;
Ok(AsyncBindingWhenConfigurator::new(self.di_container.clone()))
}
diff --git a/src/di_container/asynchronous/binding/when_configurator.rs b/src/di_container/asynchronous/binding/when_configurator.rs
index b245ad8..3175420 100644
--- a/src/di_container/asynchronous/binding/when_configurator.rs
+++ b/src/di_container/asynchronous/binding/when_configurator.rs
@@ -1,25 +1,31 @@
-//! When configurator for a binding for types inside of a [`AsyncDIContainer`].
+//! When configurator for a binding 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;
+use crate::di_container::asynchronous::IAsyncDIContainer;
use crate::errors::async_di_container::AsyncBindingWhenConfiguratorError;
-use crate::AsyncDIContainer;
-/// When configurator for a binding for type 'Interface' inside a [`AsyncDIContainer`].
-pub struct AsyncBindingWhenConfigurator<Interface>
+/// When configurator for a binding for type 'Interface' inside a [`IAsyncDIContainer`].
+///
+/// [`IAsyncDIContainer`]: crate::di_container::asynchronous::IAsyncDIContainer
+pub struct AsyncBindingWhenConfigurator<Interface, DIContainerType>
where
Interface: 'static + ?Sized + Send + Sync,
+ DIContainerType: IAsyncDIContainer,
{
- di_container: Arc<AsyncDIContainer>,
+ di_container: Arc<DIContainerType>,
interface_phantom: PhantomData<Interface>,
}
-impl<Interface> AsyncBindingWhenConfigurator<Interface>
+impl<Interface, DIContainerType> AsyncBindingWhenConfigurator<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,
@@ -36,18 +42,22 @@ where
name: &'static str,
) -> Result<(), AsyncBindingWhenConfiguratorError>
{
- let mut bindings_lock = self.di_container.bindings.lock().await;
+ let binding = self
+ .di_container
+ .remove_binding::<Interface>(None)
+ .await
+ .map_or_else(
+ || {
+ Err(AsyncBindingWhenConfiguratorError::BindingNotFound(
+ type_name::<Interface>(),
+ ))
+ },
+ Ok,
+ )?;
- let binding = bindings_lock.remove::<Interface>(None).map_or_else(
- || {
- Err(AsyncBindingWhenConfiguratorError::BindingNotFound(
- type_name::<Interface>(),
- ))
- },
- Ok,
- )?;
-
- bindings_lock.set::<Interface>(Some(name), binding);
+ self.di_container
+ .set_binding::<Interface>(Some(name), binding)
+ .await;
Ok(())
}
diff --git a/src/di_container/asynchronous/mod.rs b/src/di_container/asynchronous/mod.rs
index b6653a5..14e6abe 100644
--- a/src/di_container/asynchronous/mod.rs
+++ b/src/di_container/asynchronous/mod.rs
@@ -5,7 +5,8 @@
//! use std::collections::HashMap;
//! use std::error::Error;
//!
-//! use syrette::{injectable, AsyncDIContainer};
+//! use syrette::di_container::asynchronous::prelude::*;
+//! use syrette::injectable;
//!
//! trait IDatabaseService: Send + Sync
//! {
@@ -53,6 +54,7 @@
use std::any::type_name;
use std::sync::Arc;
+use async_trait::async_trait;
use tokio::sync::Mutex;
use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder;
@@ -65,11 +67,64 @@ use crate::provider::r#async::{AsyncProvidable, IAsyncProvider};
use crate::ptr::{SomeThreadsafePtr, TransientPtr};
pub mod binding;
+pub mod prelude;
+
+/// Dependency injection container interface.
+#[async_trait]
+pub trait IAsyncDIContainer:
+ Sized + 'static + Send + Sync + details::DIContainerInternals
+{
+ /// Returns a new [`AsyncBindingBuilder`] for the given interface.
+ #[must_use]
+ fn bind<Interface>(self: &mut Arc<Self>) -> AsyncBindingBuilder<Interface, Self>
+ 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<Self>,
+ ) -> BoxFuture<'b, Result<SomeThreadsafePtr<Interface>, 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<Self>,
+ name: &'static str,
+ ) -> BoxFuture<'b, Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>>
+ where
+ Interface: 'static + 'b + ?Sized + Send + Sync,
+ 'a: 'b,
+ Self: 'b;
+
+ #[doc(hidden)]
+ async fn get_bound<Interface>(
+ self: &Arc<Self>,
+ dependency_history: Vec<&'static str>,
+ name: Option<&'static str>,
+ ) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
+ where
+ Interface: 'static + ?Sized + Send + Sync;
+}
/// Dependency injection container.
pub struct AsyncDIContainer
{
- bindings: Mutex<DIContainerBindingMap<dyn IAsyncProvider>>,
+ bindings: Mutex<DIContainerBindingMap<dyn IAsyncProvider<Self>>>,
}
impl AsyncDIContainer
@@ -82,51 +137,43 @@ impl AsyncDIContainer
bindings: Mutex::new(DIContainerBindingMap::new()),
})
}
+}
- /// Returns a new [`AsyncBindingBuilder`] for the given interface.
+#[async_trait]
+impl IAsyncDIContainer for AsyncDIContainer
+{
#[must_use]
- pub fn bind<Interface>(self: &mut Arc<Self>) -> AsyncBindingBuilder<Interface>
+ fn bind<Interface>(self: &mut Arc<Self>) -> AsyncBindingBuilder<Interface, Self>
where
Interface: 'static + ?Sized + Send + Sync,
{
- AsyncBindingBuilder::<Interface>::new(self.clone())
+ 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<Interface>(
- self: &Arc<Self>,
- ) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
+ fn get<'a, 'b, Interface>(
+ self: &'a Arc<Self>,
+ ) -> BoxFuture<'b, Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>>
where
- Interface: 'static + ?Sized + Send + Sync,
+ Interface: 'static + 'b + ?Sized + Send + Sync,
+ 'a: 'b,
+ Self: 'b,
{
- self.get_bound::<Interface>(Vec::new(), None).await
+ Box::pin(async { self.get_bound::<Interface>(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<Interface>(
- self: &Arc<Self>,
+ fn get_named<'a, 'b, Interface>(
+ self: &'a Arc<Self>,
name: &'static str,
- ) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
+ ) -> BoxFuture<'b, Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>>
where
- Interface: 'static + ?Sized + Send + Sync,
+ Interface: 'static + 'b + ?Sized + Send + Sync,
+ 'a: 'b,
+ Self: 'b,
{
- self.get_bound::<Interface>(Vec::new(), Some(name)).await
+ Box::pin(async { self.get_bound::<Interface>(Vec::new(), Some(name)).await })
}
- #[doc(hidden)]
- pub async fn get_bound<Interface>(
+ async fn get_bound<Interface>(
self: &Arc<Self>,
dependency_history: Vec<&'static str>,
name: Option<&'static str>,
@@ -140,10 +187,44 @@ impl AsyncDIContainer
self.handle_binding_providable(binding_providable).await
}
+}
+
+#[async_trait]
+impl details::DIContainerInternals for AsyncDIContainer
+{
+ async fn has_binding<Interface>(self: &Arc<Self>, name: Option<&'static str>) -> bool
+ where
+ Interface: ?Sized + 'static,
+ {
+ self.bindings.lock().await.has::<Interface>(name)
+ }
+
+ async fn set_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ provider: Box<dyn IAsyncProvider<Self>>,
+ ) where
+ Interface: 'static + ?Sized,
+ {
+ self.bindings.lock().await.set::<Interface>(name, provider);
+ }
+ async fn remove_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ ) -> Option<Box<dyn IAsyncProvider<Self>>>
+ where
+ Interface: 'static + ?Sized,
+ {
+ self.bindings.lock().await.remove::<Interface>(name)
+ }
+}
+
+impl AsyncDIContainer
+{
async fn handle_binding_providable<Interface>(
self: &Arc<Self>,
- binding_providable: AsyncProvidable,
+ binding_providable: AsyncProvidable<Self>,
) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
where
Interface: 'static + ?Sized + Send + Sync,
@@ -261,7 +342,7 @@ impl AsyncDIContainer
self: &Arc<Self>,
name: Option<&'static str>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, AsyncDIContainerError>
+ ) -> Result<AsyncProvidable<Self>, AsyncDIContainerError>
where
Interface: 'static + ?Sized + Send + Sync,
{
@@ -294,6 +375,40 @@ impl AsyncDIContainer
}
}
+pub(crate) mod details
+{
+ use std::sync::Arc;
+
+ use async_trait::async_trait;
+
+ use crate::provider::r#async::IAsyncProvider;
+
+ #[async_trait]
+ pub trait DIContainerInternals
+ {
+ async fn has_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ ) -> bool
+ where
+ Interface: ?Sized + 'static;
+
+ async fn set_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ provider: Box<dyn IAsyncProvider<Self>>,
+ ) where
+ Interface: 'static + ?Sized;
+
+ async fn remove_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ ) -> Option<Box<dyn IAsyncProvider<Self>>>
+ where
+ Interface: 'static + ?Sized;
+ }
+}
+
#[cfg(test)]
mod tests
{
@@ -314,15 +429,15 @@ mod tests
Provider {}
#[async_trait]
- impl IAsyncProvider for Provider
+ impl IAsyncProvider<AsyncDIContainer> for Provider
{
async fn provide(
&self,
di_container: &Arc<AsyncDIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<AsyncDIContainer>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<AsyncDIContainer>>;
}
}
@@ -365,15 +480,15 @@ mod tests
Provider {}
#[async_trait]
- impl IAsyncProvider for Provider
+ impl IAsyncProvider<AsyncDIContainer> for Provider
{
async fn provide(
&self,
di_container: &Arc<AsyncDIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<AsyncDIContainer>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<AsyncDIContainer>>;
}
}
@@ -419,15 +534,15 @@ mod tests
Provider {}
#[async_trait]
- impl IAsyncProvider for Provider
+ impl IAsyncProvider<AsyncDIContainer> for Provider
{
async fn provide(
&self,
di_container: &Arc<AsyncDIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<AsyncDIContainer>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<AsyncDIContainer>>;
}
}
@@ -483,15 +598,15 @@ mod tests
Provider {}
#[async_trait]
- impl IAsyncProvider for Provider
+ impl IAsyncProvider<AsyncDIContainer> for Provider
{
async fn provide(
&self,
di_container: &Arc<AsyncDIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<AsyncDIContainer>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<AsyncDIContainer>>;
}
}
@@ -593,15 +708,15 @@ mod tests
Provider {}
#[async_trait]
- impl IAsyncProvider for Provider
+ impl IAsyncProvider<AsyncDIContainer> for Provider
{
async fn provide(
&self,
di_container: &Arc<AsyncDIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<AsyncDIContainer>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<AsyncDIContainer>>;
}
}
@@ -704,15 +819,15 @@ mod tests
Provider {}
#[async_trait]
- impl IAsyncProvider for Provider
+ impl IAsyncProvider<AsyncDIContainer> for Provider
{
async fn provide(
&self,
di_container: &Arc<AsyncDIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<AsyncDIContainer>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<AsyncDIContainer>>;
}
}
diff --git a/src/di_container/asynchronous/prelude.rs b/src/di_container/asynchronous/prelude.rs
new file mode 100644
index 0000000..50fc42b
--- /dev/null
+++ b/src/di_container/asynchronous/prelude.rs
@@ -0,0 +1,3 @@
+//! Commonly used types.
+
+pub use crate::di_container::asynchronous::{AsyncDIContainer, IAsyncDIContainer};
diff --git a/src/di_container/binding_map.rs b/src/di_container/binding_map.rs
index 6ecd34c..3a73f7a 100644
--- a/src/di_container/binding_map.rs
+++ b/src/di_container/binding_map.rs
@@ -81,13 +81,6 @@ where
name,
})
}
-
- /// Only used by tests in the `di_container` module.
- #[cfg(test)]
- pub fn count(&self) -> usize
- {
- self.bindings.len()
- }
}
#[cfg(test)]
diff --git a/src/di_container/blocking/binding/builder.rs b/src/di_container/blocking/binding/builder.rs
index 8e15f0c..e1c1561 100644
--- a/src/di_container/blocking/binding/builder.rs
+++ b/src/di_container/blocking/binding/builder.rs
@@ -1,4 +1,6 @@
-//! Binding builder for types inside of a [`DIContainer`].
+//! Binding builder for types inside of a [`IDIContainer`].
+//!
+//! [`IDIContainer`]: crate::di_container::blocking::IDIContainer
use std::any::type_name;
use std::marker::PhantomData;
use std::rc::Rc;
@@ -6,24 +8,28 @@ use std::rc::Rc;
use crate::di_container::blocking::binding::scope_configurator::BindingScopeConfigurator;
#[cfg(feature = "factory")]
use crate::di_container::blocking::binding::when_configurator::BindingWhenConfigurator;
-use crate::di_container::blocking::DIContainer;
+use crate::di_container::blocking::IDIContainer;
use crate::errors::di_container::BindingBuilderError;
use crate::interfaces::injectable::Injectable;
-/// Binding builder for type `Interface` inside a [`DIContainer`].
-pub struct BindingBuilder<Interface>
+/// Binding builder for type `Interface` inside a [`IDIContainer`].
+///
+/// [`IDIContainer`]: crate::di_container::blocking::IDIContainer
+pub struct BindingBuilder<Interface, DIContainerType>
where
Interface: 'static + ?Sized,
+ DIContainerType: IDIContainer,
{
- di_container: Rc<DIContainer>,
+ di_container: Rc<DIContainerType>,
interface_phantom: PhantomData<Interface>,
}
-impl<Interface> BindingBuilder<Interface>
+impl<Interface, DIContainerType> BindingBuilder<Interface, DIContainerType>
where
Interface: 'static + ?Sized,
+ DIContainerType: IDIContainer,
{
- pub(crate) fn new(di_container: Rc<DIContainer>) -> Self
+ pub(crate) fn new(di_container: Rc<DIContainerType>) -> Self
{
Self {
di_container,
@@ -32,13 +38,13 @@ where
}
/// Creates a binding of type `Interface` to type `Implementation` inside of the
- /// associated [`DIContainer`].
+ /// associated [`IDIContainer`].
///
/// The scope of the binding is transient. But that can be changed by using the
/// returned [`BindingScopeConfigurator`]
///
/// # Errors
- /// Will return Err if the associated [`DIContainer`] already have a binding for
+ /// Will return Err if the associated [`IDIContainer`] already have a binding for
/// the interface.
///
/// # Examples
@@ -46,6 +52,7 @@ where
/// # use std::error::Error;
/// #
/// # use syrette::{DIContainer, injectable};
+ /// # use syrette::di_container::blocking::IDIContainer;
/// #
/// # trait Foo {}
/// #
@@ -70,16 +77,19 @@ where
/// # Ok(())
/// # }
/// ```
+ ///
+ /// [`IDIContainer`]: crate::di_container::blocking::IDIContainer
pub fn to<Implementation>(
&self,
- ) -> Result<BindingScopeConfigurator<Interface, Implementation>, BindingBuilderError>
+ ) -> Result<
+ BindingScopeConfigurator<Interface, Implementation, DIContainerType>,
+ BindingBuilderError,
+ >
where
- Implementation: Injectable,
+ Implementation: Injectable<DIContainerType>,
{
{
- let bindings = self.di_container.bindings.borrow();
-
- if bindings.has::<Interface>(None) {
+ if self.di_container.has_binding::<Interface>(None) {
return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
Interface,
>(
@@ -96,10 +106,10 @@ where
}
/// Creates a binding of factory type `Interface` to a factory inside of the
- /// associated [`DIContainer`].
+ /// associated [`IDIContainer`].
///
/// # Errors
- /// Will return Err if the associated [`DIContainer`] already have a binding for
+ /// Will return Err if the associated [`IDIContainer`] already have a binding for
/// the interface.
///
/// # Examples
@@ -108,6 +118,7 @@ where
/// #
/// # use syrette::{DIContainer, factory};
/// # use syrette::ptr::TransientPtr;
+ /// # use syrette::di_container::blocking::IDIContainer;
/// #
/// # trait ICustomerID {}
/// # trait ICustomer {}
@@ -158,36 +169,31 @@ where
/// # Ok(())
/// # }
/// ```
+ ///
+ /// [`IDIContainer`]: crate::di_container::blocking::IDIContainer
#[cfg(feature = "factory")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))]
pub fn to_factory<Args, Return, Func>(
&self,
factory_func: &'static Func,
- ) -> Result<BindingWhenConfigurator<Interface>, BindingBuilderError>
+ ) -> Result<BindingWhenConfigurator<Interface, DIContainerType>, BindingBuilderError>
where
Args: 'static,
Return: 'static + ?Sized,
Interface: Fn<Args, Output = crate::ptr::TransientPtr<Return>>,
- Func: Fn<(std::rc::Rc<DIContainer>,), Output = Box<Interface>>,
+ Func: Fn<(std::rc::Rc<DIContainerType>,), Output = Box<Interface>>,
{
use crate::castable_factory::blocking::CastableFactory;
- {
- let bindings = self.di_container.bindings.borrow();
-
- if bindings.has::<Interface>(None) {
- return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
- Interface,
- >(
- )));
- }
+ if self.di_container.has_binding::<Interface>(None) {
+ return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
+ Interface,
+ >()));
}
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
-
let factory_impl = CastableFactory::new(factory_func);
- bindings_mut.set::<Interface>(
+ self.di_container.set_binding::<Interface>(
None,
Box::new(crate::provider::blocking::FactoryProvider::new(
crate::ptr::FactoryPtr::new(factory_impl),
@@ -199,10 +205,10 @@ where
}
/// Creates a binding of type `Interface` to a factory that takes no arguments
- /// inside of the associated [`DIContainer`].
+ /// inside of the associated [`IDIContainer`].
///
/// # Errors
- /// Will return Err if the associated [`DIContainer`] already have a binding for
+ /// Will return Err if the associated [`IDIContainer`] already have a binding for
/// the interface.
///
/// # Examples
@@ -211,6 +217,7 @@ where
/// #
/// # use syrette::{DIContainer, factory};
/// # use syrette::ptr::TransientPtr;
+ /// # use syrette::di_container::blocking::IDIContainer;
/// #
/// # trait IBuffer {}
/// #
@@ -248,16 +255,18 @@ where
/// # Ok(())
/// # }
/// ```
+ ///
+ /// [`IDIContainer`]: crate::di_container::blocking::IDIContainer
#[cfg(feature = "factory")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))]
pub fn to_default_factory<Return, FactoryFunc>(
&self,
factory_func: &'static FactoryFunc,
- ) -> Result<BindingWhenConfigurator<Interface>, BindingBuilderError>
+ ) -> Result<BindingWhenConfigurator<Interface, DIContainerType>, BindingBuilderError>
where
Return: 'static + ?Sized,
FactoryFunc: Fn<
- (Rc<DIContainer>,),
+ (Rc<DIContainerType>,),
Output = crate::ptr::TransientPtr<
dyn Fn<(), Output = crate::ptr::TransientPtr<Return>>,
>,
@@ -265,22 +274,15 @@ where
{
use crate::castable_factory::blocking::CastableFactory;
- {
- let bindings = self.di_container.bindings.borrow();
-
- if bindings.has::<Interface>(None) {
- return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
- Interface,
- >(
- )));
- }
+ if self.di_container.has_binding::<Interface>(None) {
+ return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
+ Interface,
+ >()));
}
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
-
let factory_impl = CastableFactory::new(factory_func);
- bindings_mut.set::<Interface>(
+ self.di_container.set_binding::<Interface>(
None,
Box::new(crate::provider::blocking::FactoryProvider::new(
crate::ptr::FactoryPtr::new(factory_impl),
@@ -297,92 +299,34 @@ mod tests
{
use std::error::Error;
+ use mockall::predicate::eq;
+
use super::*;
- use crate::ptr::TransientPtr;
- use crate::test_utils::subjects;
+ use crate::test_utils::{mocks, subjects};
#[test]
fn can_bind_to() -> Result<(), Box<dyn Error>>
{
- let mut di_container = DIContainer::new();
+ let mut mock_di_container = mocks::blocking_di_container::MockDIContainer::new();
- assert_eq!(di_container.bindings.borrow().count(), 0);
+ mock_di_container
+ .expect_has_binding::<dyn subjects::INumber>()
+ .with(eq(None))
+ .return_once(|_name| false)
+ .once();
- di_container
- .bind::<dyn subjects::IUserManager>()
- .to::<subjects::UserManager>()?;
+ mock_di_container
+ .expect_set_binding::<dyn subjects::INumber>()
+ .withf(|name, _provider| name.is_none())
+ .return_once(|_name, _provider| ())
+ .once();
- assert_eq!(di_container.bindings.borrow().count(), 1);
+ let binding_builder = BindingBuilder::<
+ dyn subjects::INumber,
+ mocks::blocking_di_container::MockDIContainer,
+ >::new(Rc::new(mock_di_container));
- Ok(())
- }
-
- #[test]
- fn can_bind_to_transient() -> Result<(), Box<dyn Error>>
- {
- let mut di_container = DIContainer::new();
-
- assert_eq!(di_container.bindings.borrow().count(), 0);
-
- di_container
- .bind::<dyn subjects::IUserManager>()
- .to::<subjects::UserManager>()?
- .in_transient_scope();
-
- assert_eq!(di_container.bindings.borrow().count(), 1);
-
- Ok(())
- }
-
- #[test]
- fn can_bind_to_transient_when_named() -> Result<(), Box<dyn Error>>
- {
- let mut di_container = DIContainer::new();
-
- assert_eq!(di_container.bindings.borrow().count(), 0);
-
- di_container
- .bind::<dyn subjects::IUserManager>()
- .to::<subjects::UserManager>()?
- .in_transient_scope()
- .when_named("regular")?;
-
- assert_eq!(di_container.bindings.borrow().count(), 1);
-
- Ok(())
- }
-
- #[test]
- fn can_bind_to_singleton() -> Result<(), Box<dyn Error>>
- {
- let mut di_container = DIContainer::new();
-
- assert_eq!(di_container.bindings.borrow().count(), 0);
-
- di_container
- .bind::<dyn subjects::IUserManager>()
- .to::<subjects::UserManager>()?
- .in_singleton_scope()?;
-
- assert_eq!(di_container.bindings.borrow().count(), 1);
-
- Ok(())
- }
-
- #[test]
- fn can_bind_to_singleton_when_named() -> Result<(), Box<dyn Error>>
- {
- let mut di_container = DIContainer::new();
-
- assert_eq!(di_container.bindings.borrow().count(), 0);
-
- di_container
- .bind::<dyn subjects::IUserManager>()
- .to::<subjects::UserManager>()?
- .in_singleton_scope()?
- .when_named("cool")?;
-
- assert_eq!(di_container.bindings.borrow().count(), 1);
+ binding_builder.to::<subjects::Number>()?;
Ok(())
}
@@ -393,57 +337,80 @@ mod tests
{
use crate as syrette;
use crate::factory;
+ use crate::ptr::TransientPtr;
#[factory]
- type IUserManagerFactory = dyn Fn() -> dyn subjects::IUserManager;
+ type IUserManagerFactory = dyn Fn(i32, String) -> dyn subjects::IUserManager;
- let mut di_container = DIContainer::new();
+ let mut mock_di_container = mocks::blocking_di_container::MockDIContainer::new();
- assert_eq!(di_container.bindings.borrow().count(), 0);
+ mock_di_container
+ .expect_has_binding::<IUserManagerFactory>()
+ .with(eq(None))
+ .return_once(|_name| false)
+ .once();
- di_container
- .bind::<IUserManagerFactory>()
- .to_factory(&|_| {
- Box::new(move || {
- let user_manager: TransientPtr<dyn subjects::IUserManager> =
- TransientPtr::new(subjects::UserManager::new());
+ mock_di_container
+ .expect_set_binding::<IUserManagerFactory>()
+ .withf(|name, _provider| name.is_none())
+ .return_once(|_name, _provider| ())
+ .once();
- user_manager
- })
- })?;
+ let binding_builder = BindingBuilder::<
+ IUserManagerFactory,
+ mocks::blocking_di_container::MockDIContainer,
+ >::new(Rc::new(mock_di_container));
- assert_eq!(di_container.bindings.borrow().count(), 1);
+ binding_builder.to_factory(&|_| {
+ Box::new(move |_num, _text| {
+ let user_manager: TransientPtr<dyn subjects::IUserManager> =
+ TransientPtr::new(subjects::UserManager::new());
+
+ user_manager
+ })
+ })?;
Ok(())
}
#[test]
#[cfg(feature = "factory")]
- fn can_bind_to_factory_when_named() -> Result<(), Box<dyn Error>>
+ fn can_bind_to_default_factory() -> Result<(), Box<dyn Error>>
{
+ use syrette_macros::declare_default_factory;
+
use crate as syrette;
- use crate::factory;
+ use crate::ptr::TransientPtr;
- #[factory]
- type IUserManagerFactory = dyn Fn() -> dyn subjects::IUserManager;
+ declare_default_factory!(dyn subjects::IUserManager);
+
+ let mut mock_di_container = mocks::blocking_di_container::MockDIContainer::new();
- let mut di_container = DIContainer::new();
+ mock_di_container
+ .expect_has_binding::<dyn subjects::IUserManager>()
+ .with(eq(None))
+ .return_once(|_name| false)
+ .once();
- assert_eq!(di_container.bindings.borrow().count(), 0);
+ mock_di_container
+ .expect_set_binding::<dyn subjects::IUserManager>()
+ .withf(|name, _provider| name.is_none())
+ .return_once(|_name, _provider| ())
+ .once();
- di_container
- .bind::<IUserManagerFactory>()
- .to_factory(&|_| {
- Box::new(move || {
- let user_manager: TransientPtr<dyn subjects::IUserManager> =
- TransientPtr::new(subjects::UserManager::new());
+ let binding_builder = BindingBuilder::<
+ dyn subjects::IUserManager,
+ mocks::blocking_di_container::MockDIContainer,
+ >::new(Rc::new(mock_di_container));
- user_manager
- })
- })?
- .when_named("awesome")?;
+ binding_builder.to_default_factory(&|_| {
+ Box::new(move || {
+ let user_manager: TransientPtr<dyn subjects::IUserManager> =
+ TransientPtr::new(subjects::UserManager::new());
- assert_eq!(di_container.bindings.borrow().count(), 1);
+ user_manager
+ })
+ })?;
Ok(())
}
diff --git a/src/di_container/blocking/binding/scope_configurator.rs b/src/di_container/blocking/binding/scope_configurator.rs
index 09897b6..5553415 100644
--- a/src/di_container/blocking/binding/scope_configurator.rs
+++ b/src/di_container/blocking/binding/scope_configurator.rs
@@ -1,31 +1,38 @@
-//! Scope configurator for a binding for types inside of a [`DIContainer`].
+//! Scope configurator for a binding for types inside of a [`IDIContainer`].
+//!
+//! [`IDIContainer`]: crate::di_container::blocking::IDIContainer
use std::marker::PhantomData;
use std::rc::Rc;
use crate::di_container::blocking::binding::when_configurator::BindingWhenConfigurator;
-use crate::di_container::blocking::DIContainer;
+use crate::di_container::blocking::IDIContainer;
use crate::errors::di_container::BindingScopeConfiguratorError;
use crate::interfaces::injectable::Injectable;
use crate::provider::blocking::{SingletonProvider, TransientTypeProvider};
use crate::ptr::SingletonPtr;
-/// Scope configurator for a binding for type 'Interface' inside a [`DIContainer`].
-pub struct BindingScopeConfigurator<Interface, Implementation>
+/// Scope configurator for a binding for type 'Interface' inside a [`IDIContainer`].
+///
+/// [`IDIContainer`]: crate::di_container::blocking::IDIContainer
+pub struct BindingScopeConfigurator<Interface, Implementation, DIContainerType>
where
Interface: 'static + ?Sized,
- Implementation: Injectable,
+ Implementation: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
- di_container: Rc<DIContainer>,
+ di_container: Rc<DIContainerType>,
interface_phantom: PhantomData<Interface>,
implementation_phantom: PhantomData<Implementation>,
}
-impl<Interface, Implementation> BindingScopeConfigurator<Interface, Implementation>
+impl<Interface, Implementation, DIContainerType>
+ BindingScopeConfigurator<Interface, Implementation, DIContainerType>
where
Interface: 'static + ?Sized,
- Implementation: Injectable,
+ Implementation: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
- pub(crate) fn new(di_container: Rc<DIContainer>) -> Self
+ pub(crate) fn new(di_container: Rc<DIContainerType>) -> Self
{
Self {
di_container,
@@ -38,13 +45,13 @@ where
///
/// This is the default.
#[allow(clippy::must_use_candidate)]
- pub fn in_transient_scope(&self) -> BindingWhenConfigurator<Interface>
+ pub fn in_transient_scope(
+ &self,
+ ) -> BindingWhenConfigurator<Interface, DIContainerType>
{
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
-
- bindings_mut.set::<Interface>(
+ self.di_container.set_binding::<Interface>(
None,
- Box::new(TransientTypeProvider::<Implementation>::new()),
+ Box::new(TransientTypeProvider::<Implementation, DIContainerType>::new()),
);
BindingWhenConfigurator::new(self.di_container.clone())
@@ -56,16 +63,18 @@ where
/// Will return Err if resolving the implementation fails.
pub fn in_singleton_scope(
&self,
- ) -> Result<BindingWhenConfigurator<Interface>, BindingScopeConfiguratorError>
+ ) -> Result<
+ BindingWhenConfigurator<Interface, DIContainerType>,
+ BindingScopeConfiguratorError,
+ >
{
let singleton: SingletonPtr<Implementation> = SingletonPtr::from(
Implementation::resolve(&self.di_container, Vec::new())
.map_err(BindingScopeConfiguratorError::SingletonResolveFailed)?,
);
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
-
- bindings_mut.set::<Interface>(None, Box::new(SingletonProvider::new(singleton)));
+ self.di_container
+ .set_binding::<Interface>(None, Box::new(SingletonProvider::new(singleton)));
Ok(BindingWhenConfigurator::new(self.di_container.clone()))
}
diff --git a/src/di_container/blocking/binding/when_configurator.rs b/src/di_container/blocking/binding/when_configurator.rs
index 9cd9bb6..5b9a8c0 100644
--- a/src/di_container/blocking/binding/when_configurator.rs
+++ b/src/di_container/blocking/binding/when_configurator.rs
@@ -1,25 +1,31 @@
-//! When configurator for a binding for types inside of a [`DIContainer`].
+//! When configurator for a binding for types inside of a [`IDIContainer`].
+//!
+//! [`IDIContainer`]: crate::di_container::blocking::IDIContainer
use std::any::type_name;
use std::marker::PhantomData;
use std::rc::Rc;
-use crate::di_container::blocking::DIContainer;
+use crate::di_container::blocking::IDIContainer;
use crate::errors::di_container::BindingWhenConfiguratorError;
-/// When configurator for a binding for type 'Interface' inside a [`DIContainer`].
-pub struct BindingWhenConfigurator<Interface>
+/// When configurator for a binding for type 'Interface' inside a [`IDIContainer`].
+///
+/// [`IDIContainer`]: crate::di_container::blocking::IDIContainer
+pub struct BindingWhenConfigurator<Interface, DIContainerType>
where
Interface: 'static + ?Sized,
+ DIContainerType: IDIContainer,
{
- di_container: Rc<DIContainer>,
+ di_container: Rc<DIContainerType>,
interface_phantom: PhantomData<Interface>,
}
-impl<Interface> BindingWhenConfigurator<Interface>
+impl<Interface, DIContainerType> BindingWhenConfigurator<Interface, DIContainerType>
where
Interface: 'static + ?Sized,
+ DIContainerType: IDIContainer,
{
- pub(crate) fn new(di_container: Rc<DIContainer>) -> Self
+ pub(crate) fn new(di_container: Rc<DIContainerType>) -> Self
{
Self {
di_container,
@@ -36,19 +42,21 @@ where
name: &'static str,
) -> Result<(), BindingWhenConfiguratorError>
{
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
+ let binding = self
+ .di_container
+ .remove_binding::<Interface>(None)
+ .map_or_else(
+ || {
+ Err(BindingWhenConfiguratorError::BindingNotFound(type_name::<
+ Interface,
+ >(
+ )))
+ },
+ Ok,
+ )?;
- let binding = bindings_mut.remove::<Interface>(None).map_or_else(
- || {
- Err(BindingWhenConfiguratorError::BindingNotFound(type_name::<
- Interface,
- >(
- )))
- },
- Ok,
- )?;
-
- bindings_mut.set::<Interface>(Some(name), binding);
+ self.di_container
+ .set_binding::<Interface>(Some(name), binding);
Ok(())
}
diff --git a/src/di_container/blocking/mod.rs b/src/di_container/blocking/mod.rs
index f6b64fa..3b9c16e 100644
--- a/src/di_container/blocking/mod.rs
+++ b/src/di_container/blocking/mod.rs
@@ -5,6 +5,7 @@
//! use std::collections::HashMap;
//! use std::error::Error;
//!
+//! use syrette::di_container::blocking::IDIContainer;
//! use syrette::{injectable, DIContainer};
//!
//! trait IDatabaseService
@@ -61,11 +62,55 @@ use crate::provider::blocking::{IProvider, Providable};
use crate::ptr::SomePtr;
pub mod binding;
+pub mod prelude;
-/// Dependency injection container.
+/// Blocking dependency injection container interface.
+pub trait IDIContainer: Sized + 'static + details::DIContainerInternals
+{
+ /// Returns a new [`BindingBuilder`] for the given interface.
+ fn bind<Interface>(self: &mut Rc<Self>) -> BindingBuilder<Interface, Self>
+ where
+ Interface: 'static + ?Sized;
+
+ /// 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<Interface>(self: &Rc<Self>) -> Result<SomePtr<Interface>, DIContainerError>
+ where
+ Interface: 'static + ?Sized;
+
+ /// 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<Interface>(
+ self: &Rc<Self>,
+ name: &'static str,
+ ) -> Result<SomePtr<Interface>, DIContainerError>
+ where
+ Interface: 'static + ?Sized;
+
+ #[doc(hidden)]
+ fn get_bound<Interface>(
+ self: &Rc<Self>,
+ dependency_history: Vec<&'static str>,
+ name: Option<&'static str>,
+ ) -> Result<SomePtr<Interface>, DIContainerError>
+ where
+ Interface: 'static + ?Sized;
+}
+
+/// Blocking dependency injection container.
pub struct DIContainer
{
- bindings: RefCell<DIContainerBindingMap<dyn IProvider>>,
+ bindings: RefCell<DIContainerBindingMap<dyn IProvider<Self>>>,
}
impl DIContainer
@@ -78,38 +123,26 @@ impl DIContainer
bindings: RefCell::new(DIContainerBindingMap::new()),
})
}
+}
- /// Returns a new [`BindingBuilder`] for the given interface.
+impl IDIContainer for DIContainer
+{
#[must_use]
- pub fn bind<Interface>(self: &mut Rc<Self>) -> BindingBuilder<Interface>
+ fn bind<Interface>(self: &mut Rc<Self>) -> BindingBuilder<Interface, Self>
where
Interface: 'static + ?Sized,
{
- BindingBuilder::<Interface>::new(self.clone())
+ BindingBuilder::<Interface, Self>::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 fn get<Interface>(self: &Rc<Self>) -> Result<SomePtr<Interface>, DIContainerError>
+ fn get<Interface>(self: &Rc<Self>) -> Result<SomePtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
self.get_bound::<Interface>(Vec::new(), None)
}
- /// 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 fn get_named<Interface>(
+ fn get_named<Interface>(
self: &Rc<Self>,
name: &'static str,
) -> Result<SomePtr<Interface>, DIContainerError>
@@ -120,7 +153,7 @@ impl DIContainer
}
#[doc(hidden)]
- pub fn get_bound<Interface>(
+ fn get_bound<Interface>(
self: &Rc<Self>,
dependency_history: Vec<&'static str>,
name: Option<&'static str>,
@@ -133,10 +166,43 @@ impl DIContainer
self.handle_binding_providable(binding_providable)
}
+}
+
+impl details::DIContainerInternals for DIContainer
+{
+ fn has_binding<Interface>(self: &Rc<Self>, name: Option<&'static str>) -> bool
+ where
+ Interface: ?Sized + 'static,
+ {
+ self.bindings.borrow().has::<Interface>(name)
+ }
+
+ fn set_binding<Interface>(
+ self: &Rc<Self>,
+ name: Option<&'static str>,
+ provider: Box<dyn IProvider<Self>>,
+ ) where
+ Interface: 'static + ?Sized,
+ {
+ self.bindings.borrow_mut().set::<Interface>(name, provider);
+ }
+
+ fn remove_binding<Interface>(
+ self: &Rc<Self>,
+ name: Option<&'static str>,
+ ) -> Option<Box<dyn IProvider<Self>>>
+ where
+ Interface: 'static + ?Sized,
+ {
+ self.bindings.borrow_mut().remove::<Interface>(name)
+ }
+}
+impl DIContainer
+{
fn handle_binding_providable<Interface>(
self: &Rc<Self>,
- binding_providable: Providable,
+ binding_providable: Providable<Self>,
) -> Result<SomePtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
@@ -195,7 +261,7 @@ impl DIContainer
self: &Rc<Self>,
name: Option<&'static str>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, DIContainerError>
+ ) -> Result<Providable<Self>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -219,6 +285,34 @@ impl DIContainer
}
}
+pub(crate) mod details
+{
+ use std::rc::Rc;
+
+ use crate::provider::blocking::IProvider;
+
+ pub trait DIContainerInternals
+ {
+ fn has_binding<Interface>(self: &Rc<Self>, name: Option<&'static str>) -> bool
+ where
+ Interface: ?Sized + 'static;
+
+ fn set_binding<Interface>(
+ self: &Rc<Self>,
+ name: Option<&'static str>,
+ provider: Box<dyn IProvider<Self>>,
+ ) where
+ Interface: 'static + ?Sized;
+
+ fn remove_binding<Interface>(
+ self: &Rc<Self>,
+ name: Option<&'static str>,
+ ) -> Option<Box<dyn IProvider<Self>>>
+ where
+ Interface: 'static + ?Sized;
+ }
+}
+
#[cfg(test)]
mod tests
{
@@ -238,13 +332,13 @@ mod tests
mock! {
Provider {}
- impl IProvider for Provider
+ impl IProvider<DIContainer> for Provider
{
fn provide(
&self,
di_container: &Rc<DIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainer>, InjectableError>;
}
}
@@ -276,13 +370,13 @@ mod tests
mock! {
Provider {}
- impl IProvider for Provider
+ impl IProvider<DIContainer> for Provider
{
fn provide(
&self,
di_container: &Rc<DIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainer>, InjectableError>;
}
}
@@ -314,13 +408,13 @@ mod tests
mock! {
Provider {}
- impl IProvider for Provider
+ impl IProvider<DIContainer> for Provider
{
fn provide(
&self,
di_container: &Rc<DIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainer>, InjectableError>;
}
}
@@ -359,13 +453,13 @@ mod tests
mock! {
Provider {}
- impl IProvider for Provider
+ impl IProvider<DIContainer> for Provider
{
fn provide(
&self,
di_container: &Rc<DIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainer>, InjectableError>;
}
}
@@ -459,13 +553,13 @@ mod tests
mock! {
Provider {}
- impl IProvider for Provider
+ impl IProvider<DIContainer> for Provider
{
fn provide(
&self,
di_container: &Rc<DIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainer>, InjectableError>;
}
}
@@ -556,13 +650,13 @@ mod tests
mock! {
Provider {}
- impl IProvider for Provider
+ impl IProvider<DIContainer> for Provider
{
fn provide(
&self,
di_container: &Rc<DIContainer>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainer>, InjectableError>;
}
}
diff --git a/src/di_container/blocking/prelude.rs b/src/di_container/blocking/prelude.rs
new file mode 100644
index 0000000..82db5e3
--- /dev/null
+++ b/src/di_container/blocking/prelude.rs
@@ -0,0 +1,2 @@
+//! Commonly used types.
+pub use crate::di_container::blocking::{DIContainer, IDIContainer};
diff --git a/src/interfaces/async_injectable.rs b/src/interfaces/async_injectable.rs
index dadb603..fb7f8ba 100644
--- a/src/interfaces/async_injectable.rs
+++ b/src/interfaces/async_injectable.rs
@@ -2,21 +2,23 @@
use std::fmt::Debug;
use std::sync::Arc;
+use crate::di_container::asynchronous::IAsyncDIContainer;
use crate::errors::injectable::InjectableError;
use crate::future::BoxFuture;
use crate::libs::intertrait::CastFromSync;
use crate::ptr::TransientPtr;
-use crate::AsyncDIContainer;
/// Interface for structs that can be injected into or be injected to.
-pub trait AsyncInjectable: CastFromSync
+pub trait AsyncInjectable<DIContainerType>: CastFromSync
+where
+ DIContainerType: IAsyncDIContainer,
{
/// Resolves the dependencies of the injectable.
///
/// # Errors
/// Will return `Err` if resolving the dependencies fails.
fn resolve<'di_container, 'fut>(
- di_container: &'di_container Arc<AsyncDIContainer>,
+ di_container: &'di_container Arc<DIContainerType>,
dependency_history: Vec<&'static str>,
) -> BoxFuture<'fut, Result<TransientPtr<Self>, InjectableError>>
where
@@ -24,7 +26,9 @@ pub trait AsyncInjectable: CastFromSync
'di_container: 'fut;
}
-impl Debug for dyn AsyncInjectable
+impl<DIContainerType> Debug for dyn AsyncInjectable<DIContainerType>
+where
+ DIContainerType: IAsyncDIContainer,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
diff --git a/src/interfaces/injectable.rs b/src/interfaces/injectable.rs
index f4c7fda..132935d 100644
--- a/src/interfaces/injectable.rs
+++ b/src/interfaces/injectable.rs
@@ -2,27 +2,31 @@
use std::fmt::Debug;
use std::rc::Rc;
+use crate::di_container::blocking::IDIContainer;
use crate::errors::injectable::InjectableError;
use crate::libs::intertrait::CastFrom;
use crate::ptr::TransientPtr;
-use crate::DIContainer;
/// Interface for structs that can be injected into or be injected to.
-pub trait Injectable: CastFrom
+pub trait Injectable<DIContainerType>: CastFrom
+where
+ DIContainerType: IDIContainer,
{
/// Resolves the dependencies of the injectable.
///
/// # Errors
/// Will return `Err` if resolving the dependencies fails.
fn resolve(
- di_container: &Rc<DIContainer>,
+ di_container: &Rc<DIContainerType>,
dependency_history: Vec<&'static str>,
) -> Result<TransientPtr<Self>, InjectableError>
where
Self: Sized;
}
-impl Debug for dyn Injectable
+impl<DIContainerType> Debug for dyn Injectable<DIContainerType>
+where
+ DIContainerType: IDIContainer,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
diff --git a/src/lib.rs b/src/lib.rs
index a3da74a..6827768 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,6 +57,7 @@ mod test_utils;
/// # Examples
/// ```
/// # use syrette::{di_container_bind, DIContainer, injectable};
+/// # use syrette::di_container::blocking::IDIContainer;
/// #
/// # trait INinja {}
/// #
diff --git a/src/provider/async.rs b/src/provider/async.rs
index ec05b06..5b4bf89 100644
--- a/src/provider/async.rs
+++ b/src/provider/async.rs
@@ -3,16 +3,18 @@ use std::sync::Arc;
use async_trait::async_trait;
+use crate::di_container::asynchronous::IAsyncDIContainer;
use crate::errors::injectable::InjectableError;
use crate::interfaces::async_injectable::AsyncInjectable;
use crate::ptr::{ThreadsafeSingletonPtr, TransientPtr};
-use crate::AsyncDIContainer;
#[derive(strum_macros::Display, Debug)]
-pub enum AsyncProvidable
+pub enum AsyncProvidable<DIContainerType>
+where
+ DIContainerType: IAsyncDIContainer,
{
- Transient(TransientPtr<dyn AsyncInjectable>),
- Singleton(ThreadsafeSingletonPtr<dyn AsyncInjectable>),
+ Transient(TransientPtr<dyn AsyncInjectable<DIContainerType>>),
+ Singleton(ThreadsafeSingletonPtr<dyn AsyncInjectable<DIContainerType>>),
#[cfg(feature = "factory")]
Factory(
crate::ptr::ThreadsafeFactoryPtr<
@@ -34,18 +36,22 @@ pub enum AsyncProvidable
}
#[async_trait]
-pub trait IAsyncProvider: Send + Sync
+pub trait IAsyncProvider<DIContainerType>: Send + Sync
+where
+ DIContainerType: IAsyncDIContainer,
{
async fn provide(
&self,
- di_container: &Arc<AsyncDIContainer>,
+ di_container: &Arc<DIContainerType>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>;
+ ) -> Result<AsyncProvidable<DIContainerType>, InjectableError>;
- fn do_clone(&self) -> Box<dyn IAsyncProvider>;
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>>;
}
-impl Clone for Box<dyn IAsyncProvider>
+impl<DIContainerType> Clone for Box<dyn IAsyncProvider<DIContainerType>>
+where
+ DIContainerType: IAsyncDIContainer,
{
fn clone(&self) -> Self
{
@@ -53,104 +59,127 @@ impl Clone for Box<dyn IAsyncProvider>
}
}
-pub struct AsyncTransientTypeProvider<InjectableType>
+pub struct AsyncTransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
injectable_phantom: PhantomData<InjectableType>,
+ di_container_phantom: PhantomData<DIContainerType>,
}
-impl<InjectableType> AsyncTransientTypeProvider<InjectableType>
+impl<InjectableType, DIContainerType>
+ AsyncTransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
pub fn new() -> Self
{
Self {
injectable_phantom: PhantomData,
+ di_container_phantom: PhantomData,
}
}
}
#[async_trait]
-impl<InjectableType> IAsyncProvider for AsyncTransientTypeProvider<InjectableType>
+impl<InjectableType, DIContainerType> IAsyncProvider<DIContainerType>
+ for AsyncTransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
async fn provide(
&self,
- di_container: &Arc<AsyncDIContainer>,
+ di_container: &Arc<DIContainerType>,
dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>
+ ) -> Result<AsyncProvidable<DIContainerType>, InjectableError>
{
Ok(AsyncProvidable::Transient(
InjectableType::resolve(di_container, dependency_history).await?,
))
}
- fn do_clone(&self) -> Box<dyn IAsyncProvider>
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>>
{
Box::new(self.clone())
}
}
-impl<InjectableType> Clone for AsyncTransientTypeProvider<InjectableType>
+impl<InjectableType, DIContainerType> Clone
+ for AsyncTransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
fn clone(&self) -> Self
{
Self {
injectable_phantom: self.injectable_phantom,
+ di_container_phantom: self.di_container_phantom,
}
}
}
-pub struct AsyncSingletonProvider<InjectableType>
+pub struct AsyncSingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
singleton: ThreadsafeSingletonPtr<InjectableType>,
+
+ di_container_phantom: PhantomData<DIContainerType>,
}
-impl<InjectableType> AsyncSingletonProvider<InjectableType>
+impl<InjectableType, DIContainerType>
+ AsyncSingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
pub fn new(singleton: ThreadsafeSingletonPtr<InjectableType>) -> Self
{
- Self { singleton }
+ Self {
+ singleton,
+ di_container_phantom: PhantomData,
+ }
}
}
#[async_trait]
-impl<InjectableType> IAsyncProvider for AsyncSingletonProvider<InjectableType>
+impl<InjectableType, DIContainerType> IAsyncProvider<DIContainerType>
+ for AsyncSingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
async fn provide(
&self,
- _di_container: &Arc<AsyncDIContainer>,
+ _di_container: &Arc<DIContainerType>,
_dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>
+ ) -> Result<AsyncProvidable<DIContainerType>, InjectableError>
{
Ok(AsyncProvidable::Singleton(self.singleton.clone()))
}
- fn do_clone(&self) -> Box<dyn IAsyncProvider>
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>>
{
Box::new(self.clone())
}
}
-impl<InjectableType> Clone for AsyncSingletonProvider<InjectableType>
+impl<InjectableType, DIContainerType> Clone
+ for AsyncSingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: AsyncInjectable,
+ InjectableType: AsyncInjectable<DIContainerType>,
+ DIContainerType: IAsyncDIContainer,
{
fn clone(&self) -> Self
{
Self {
singleton: self.singleton.clone(),
+ di_container_phantom: PhantomData,
}
}
}
@@ -188,13 +217,15 @@ impl AsyncFactoryProvider
#[cfg(feature = "factory")]
#[async_trait]
-impl IAsyncProvider for AsyncFactoryProvider
+impl<DIContainerType> IAsyncProvider<DIContainerType> for AsyncFactoryProvider
+where
+ DIContainerType: IAsyncDIContainer,
{
async fn provide(
&self,
- _di_container: &Arc<AsyncDIContainer>,
+ _di_container: &Arc<DIContainerType>,
_dependency_history: Vec<&'static str>,
- ) -> Result<AsyncProvidable, InjectableError>
+ ) -> Result<AsyncProvidable<DIContainerType>, InjectableError>
{
Ok(match self.variant {
AsyncFactoryVariant::Normal => AsyncProvidable::Factory(self.factory.clone()),
@@ -207,7 +238,7 @@ impl IAsyncProvider for AsyncFactoryProvider
})
}
- fn do_clone(&self) -> Box<dyn IAsyncProvider>
+ fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>>
{
Box::new(self.clone())
}
diff --git a/src/provider/blocking.rs b/src/provider/blocking.rs
index 16e8847..b768b55 100644
--- a/src/provider/blocking.rs
+++ b/src/provider/blocking.rs
@@ -1,16 +1,18 @@
use std::marker::PhantomData;
use std::rc::Rc;
+use crate::di_container::blocking::IDIContainer;
use crate::errors::injectable::InjectableError;
use crate::interfaces::injectable::Injectable;
use crate::ptr::{SingletonPtr, TransientPtr};
-use crate::DIContainer;
#[derive(strum_macros::Display, Debug)]
-pub enum Providable
+pub enum Providable<DIContainerType>
+where
+ DIContainerType: IDIContainer,
{
- Transient(TransientPtr<dyn Injectable>),
- Singleton(SingletonPtr<dyn Injectable>),
+ Transient(TransientPtr<dyn Injectable<DIContainerType>>),
+ Singleton(SingletonPtr<dyn Injectable<DIContainerType>>),
#[cfg(feature = "factory")]
Factory(crate::ptr::FactoryPtr<dyn crate::interfaces::any_factory::AnyFactory>),
#[cfg(feature = "factory")]
@@ -19,43 +21,52 @@ pub enum Providable
),
}
-pub trait IProvider
+pub trait IProvider<DIContainerType>
+where
+ DIContainerType: IDIContainer,
{
fn provide(
&self,
- di_container: &Rc<DIContainer>,
+ di_container: &Rc<DIContainerType>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>;
+ ) -> Result<Providable<DIContainerType>, InjectableError>;
}
-pub struct TransientTypeProvider<InjectableType>
+pub struct TransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: Injectable,
+ InjectableType: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
injectable_phantom: PhantomData<InjectableType>,
+ di_container_phantom: PhantomData<DIContainerType>,
}
-impl<InjectableType> TransientTypeProvider<InjectableType>
+impl<InjectableType, DIContainerType>
+ TransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: Injectable,
+ InjectableType: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
pub fn new() -> Self
{
Self {
injectable_phantom: PhantomData,
+ di_container_phantom: PhantomData,
}
}
}
-impl<InjectableType> IProvider for TransientTypeProvider<InjectableType>
+impl<InjectableType, DIContainerType> IProvider<DIContainerType>
+ for TransientTypeProvider<InjectableType, DIContainerType>
where
- InjectableType: Injectable,
+ InjectableType: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
fn provide(
&self,
- di_container: &Rc<DIContainer>,
+ di_container: &Rc<DIContainerType>,
dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>
+ ) -> Result<Providable<DIContainerType>, InjectableError>
{
Ok(Providable::Transient(InjectableType::resolve(
di_container,
@@ -64,32 +75,40 @@ where
}
}
-pub struct SingletonProvider<InjectableType>
+pub struct SingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: Injectable,
+ InjectableType: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
singleton: SingletonPtr<InjectableType>,
+ di_container_phantom: PhantomData<DIContainerType>,
}
-impl<InjectableType> SingletonProvider<InjectableType>
+impl<InjectableType, DIContainerType> SingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: Injectable,
+ InjectableType: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
pub fn new(singleton: SingletonPtr<InjectableType>) -> Self
{
- Self { singleton }
+ Self {
+ singleton,
+ di_container_phantom: PhantomData,
+ }
}
}
-impl<InjectableType> IProvider for SingletonProvider<InjectableType>
+impl<InjectableType, DIContainerType> IProvider<DIContainerType>
+ for SingletonProvider<InjectableType, DIContainerType>
where
- InjectableType: Injectable,
+ InjectableType: Injectable<DIContainerType>,
+ DIContainerType: IDIContainer,
{
fn provide(
&self,
- _di_container: &Rc<DIContainer>,
+ _di_container: &Rc<DIContainerType>,
_dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>
+ ) -> Result<Providable<DIContainerType>, InjectableError>
{
Ok(Providable::Singleton(self.singleton.clone()))
}
@@ -118,13 +137,15 @@ impl FactoryProvider
}
#[cfg(feature = "factory")]
-impl IProvider for FactoryProvider
+impl<DIContainerType> IProvider<DIContainerType> for FactoryProvider
+where
+ DIContainerType: IDIContainer,
{
fn provide(
&self,
- _di_container: &Rc<DIContainer>,
+ _di_container: &Rc<DIContainerType>,
_dependency_history: Vec<&'static str>,
- ) -> Result<Providable, InjectableError>
+ ) -> Result<Providable<DIContainerType>, InjectableError>
{
Ok(if self.is_default_factory {
Providable::DefaultFactory(self.factory.clone())
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 1fc7015..650e338 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -7,9 +7,9 @@ pub mod subjects
use syrette_macros::declare_interface;
+ use crate::di_container::blocking::IDIContainer;
use crate::interfaces::injectable::Injectable;
use crate::ptr::TransientPtr;
- use crate::DIContainer;
pub trait IUserManager
{
@@ -45,10 +45,12 @@ pub mod subjects
declare_interface!(UserManager -> IUserManager);
- impl Injectable for UserManager
+ impl<DIContainerType> Injectable<DIContainerType> for UserManager
+ where
+ DIContainerType: IDIContainer,
{
fn resolve(
- _di_container: &Rc<DIContainer>,
+ _di_container: &Rc<DIContainerType>,
_dependency_history: Vec<&'static str>,
) -> Result<TransientPtr<Self>, crate::errors::injectable::InjectableError>
where
@@ -109,10 +111,12 @@ pub mod subjects
declare_interface!(Number -> INumber);
- impl Injectable for Number
+ impl<DIContainerType> Injectable<DIContainerType> for Number
+ where
+ DIContainerType: IDIContainer,
{
fn resolve(
- _di_container: &Rc<DIContainer>,
+ _di_container: &Rc<DIContainerType>,
_dependency_history: Vec<&'static str>,
) -> Result<TransientPtr<Self>, crate::errors::injectable::InjectableError>
where
@@ -134,9 +138,9 @@ pub mod subjects_async
use async_trait::async_trait;
use syrette_macros::declare_interface;
+ use crate::di_container::asynchronous::IAsyncDIContainer;
use crate::interfaces::async_injectable::AsyncInjectable;
use crate::ptr::TransientPtr;
- use crate::AsyncDIContainer;
pub trait IUserManager: Send + Sync
{
@@ -173,10 +177,12 @@ pub mod subjects_async
declare_interface!(UserManager -> IUserManager);
#[async_trait]
- impl AsyncInjectable for UserManager
+ impl<DIContainerType> AsyncInjectable<DIContainerType> for UserManager
+ where
+ DIContainerType: IAsyncDIContainer,
{
async fn resolve(
- _: &Arc<AsyncDIContainer>,
+ _: &Arc<DIContainerType>,
_dependency_history: Vec<&'static str>,
) -> Result<TransientPtr<Self>, crate::errors::injectable::InjectableError>
where
@@ -238,10 +244,12 @@ pub mod subjects_async
declare_interface!(Number -> INumber, async = true);
#[async_trait]
- impl AsyncInjectable for Number
+ impl<DIContainerType> AsyncInjectable<DIContainerType> for Number
+ where
+ DIContainerType: IAsyncDIContainer,
{
async fn resolve(
- _: &Arc<AsyncDIContainer>,
+ _: &Arc<DIContainerType>,
_dependency_history: Vec<&'static str>,
) -> Result<TransientPtr<Self>, crate::errors::injectable::InjectableError>
where
@@ -251,3 +259,147 @@ pub mod subjects_async
}
}
}
+
+pub mod mocks
+{
+ #![allow(clippy::ref_option_ref)] // Caused by Mockall
+ #![allow(dead_code)] // Not all mock functions may be used
+
+ use mockall::mock;
+
+ pub mod blocking_di_container
+ {
+ use std::rc::Rc;
+
+ use super::*;
+ use crate::di_container::blocking::binding::builder::BindingBuilder;
+ use crate::di_container::blocking::details::DIContainerInternals;
+ use crate::di_container::blocking::IDIContainer;
+ use crate::errors::di_container::DIContainerError;
+ use crate::provider::blocking::IProvider;
+ use crate::ptr::SomePtr;
+
+ mock! {
+ pub DIContainer {}
+
+ impl IDIContainer for DIContainer {
+ fn bind<Interface>(self: &mut Rc<Self>) -> BindingBuilder<Interface, Self>
+ where
+ Interface: 'static + ?Sized;
+
+ fn get<Interface>(self: &Rc<Self>) -> Result<SomePtr<Interface>, DIContainerError>
+ where
+ Interface: 'static + ?Sized;
+
+ fn get_named<Interface>(
+ self: &Rc<Self>,
+ name: &'static str,
+ ) -> Result<SomePtr<Interface>, DIContainerError>
+ where
+ Interface: 'static + ?Sized;
+
+ #[doc(hidden)]
+ fn get_bound<Interface>(
+ self: &Rc<Self>,
+ dependency_history: Vec<&'static str>,
+ name: Option<&'static str>,
+ ) -> Result<SomePtr<Interface>, DIContainerError>
+ where
+ Interface: 'static + ?Sized;
+ }
+
+ impl DIContainerInternals for DIContainer
+ {
+ fn has_binding<Interface>(self: &Rc<Self>, name: Option<&'static str>) -> bool
+ where
+ Interface: ?Sized + 'static;
+
+ #[doc(hidden)]
+ fn set_binding<Interface>(
+ self: &Rc<Self>,
+ name: Option<&'static str>,
+ provider: Box<dyn IProvider<Self>>,
+ ) where
+ Interface: 'static + ?Sized;
+
+ fn remove_binding<Interface>(
+ self: &Rc<Self>,
+ name: Option<&'static str>,
+ ) -> Option<Box<dyn IProvider<Self>>>
+ where
+ Interface: 'static + ?Sized;
+ }
+ }
+ }
+
+ #[cfg(feature = "async")]
+ pub mod async_di_container
+ {
+ use std::sync::Arc;
+
+ use super::*;
+ use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder;
+ use crate::di_container::asynchronous::details::DIContainerInternals;
+ use crate::di_container::asynchronous::IAsyncDIContainer;
+ use crate::errors::async_di_container::AsyncDIContainerError;
+ use crate::provider::r#async::IAsyncProvider;
+ use crate::ptr::SomeThreadsafePtr;
+
+ mock! {
+ pub AsyncDIContainer {}
+
+ #[async_trait::async_trait]
+ impl IAsyncDIContainer for AsyncDIContainer {
+ fn bind<Interface>(self: &mut Arc<Self>) -> AsyncBindingBuilder<Interface, Self>
+ where
+ Interface: 'static + ?Sized + Send + Sync;
+
+ async fn get<Interface>(
+ self: &Arc<Self>,
+ ) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
+ where
+ Interface: 'static + ?Sized + Send + Sync;
+
+ async fn get_named<Interface>(
+ self: &Arc<Self>,
+ name: &'static str,
+ ) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
+ where
+ Interface: 'static + ?Sized + Send + Sync;
+
+ #[doc(hidden)]
+ async fn get_bound<Interface>(
+ self: &Arc<Self>,
+ dependency_history: Vec<&'static str>,
+ name: Option<&'static str>,
+ ) -> Result<SomeThreadsafePtr<Interface>, AsyncDIContainerError>
+ where
+ Interface: 'static + ?Sized + Send + Sync;
+ }
+
+ #[async_trait::async_trait]
+ impl DIContainerInternals for AsyncDIContainer {
+ async fn has_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ ) -> bool
+ where
+ Interface: ?Sized + 'static;
+
+ async fn set_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ provider: Box<dyn IAsyncProvider<Self>>,
+ ) where
+ Interface: 'static + ?Sized;
+
+ async fn remove_binding<Interface>(
+ self: &Arc<Self>,
+ name: Option<&'static str>,
+ ) -> Option<Box<dyn IAsyncProvider<Self>>>
+ where
+ Interface: 'static + ?Sized;
+ }
+ }
+ }
+}