aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-09-12 20:22:13 +0200
committerHampusM <hampus@hampusmat.com>2022-09-17 14:33:15 +0200
commitc1e682c25c24be3174d44ceb95b0537c38299d0c (patch)
tree6e59f37e1b98e68fad2e3e2fe4a428ac97fcf8b4 /src
parente8e48906a3899e71c9c9d86a3d4528cb7d17e5b9 (diff)
feat!: allow factories access to DI container
BREAKING CHANGE: Factory types should now be written with the Fn trait instead of the IFactory trait and the to_factory & to_default_factory methods of BindingBuilder now expect a function returning a factory function
Diffstat (limited to 'src')
-rw-r--r--src/di_container.rs173
-rw-r--r--src/provider/blocking.rs17
2 files changed, 128 insertions, 62 deletions
diff --git a/src/di_container.rs b/src/di_container.rs
index ddd3a4f..532a905 100644
--- a/src/di_container.rs
+++ b/src/di_container.rs
@@ -249,27 +249,36 @@ where
#[cfg(feature = "factory")]
pub fn to_factory<Args, Return>(
&self,
- factory_func: &'static dyn Fn<Args, Output = crate::ptr::TransientPtr<Return>>,
+ factory_func: &'static dyn Fn<
+ (std::rc::Rc<DIContainer>,),
+ Output = Box<dyn Fn<Args, Output = crate::ptr::TransientPtr<Return>>>,
+ >,
) -> Result<BindingWhenConfigurator<Interface>, BindingBuilderError>
where
Args: 'static,
Return: 'static + ?Sized,
- Interface: crate::interfaces::factory::IFactory<Args, Return>,
+ Interface: Fn<Args, Output = crate::ptr::TransientPtr<Return>>,
{
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
+ {
+ let bindings = self.di_container.bindings.borrow();
- if bindings_mut.has::<Interface>(None) {
- return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
- Interface,
- >()));
+ if bindings.has::<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>(
None,
Box::new(crate::provider::blocking::FactoryProvider::new(
crate::ptr::FactoryPtr::new(factory_impl),
+ false,
)),
);
@@ -287,25 +296,34 @@ where
#[cfg(feature = "factory")]
pub fn to_default_factory<Return>(
&self,
- factory_func: &'static dyn Fn<(), Output = crate::ptr::TransientPtr<Return>>,
+ factory_func: &'static dyn Fn<
+ (Rc<DIContainer>,),
+ Output = crate::ptr::TransientPtr<Return>,
+ >,
) -> Result<BindingWhenConfigurator<Interface>, BindingBuilderError>
where
Return: 'static + ?Sized,
{
- let mut bindings_mut = self.di_container.bindings.borrow_mut();
+ {
+ let bindings = self.di_container.bindings.borrow();
- if bindings_mut.has::<Interface>(None) {
- return Err(BindingBuilderError::BindingAlreadyExists(type_name::<
- Interface,
- >()));
+ if bindings.has::<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>(
None,
Box::new(crate::provider::blocking::FactoryProvider::new(
crate::ptr::FactoryPtr::new(factory_impl),
+ true,
)),
);
@@ -381,10 +399,11 @@ impl DIContainer
let binding_providable =
self.get_binding_providable::<Interface>(name, dependency_history)?;
- Self::handle_binding_providable(binding_providable)
+ self.handle_binding_providable(binding_providable)
}
fn handle_binding_providable<Interface>(
+ self: &Rc<Self>,
binding_providable: Providable,
) -> Result<SomePtr<Interface>, DIContainerError>
where
@@ -409,21 +428,29 @@ impl DIContainer
)),
#[cfg(feature = "factory")]
Providable::Factory(factory_binding) => {
- match factory_binding.clone().cast::<Interface>() {
- Ok(factory) => Ok(SomePtr::Factory(factory)),
- Err(_err) => {
- use crate::interfaces::factory::IFactory;
-
- let default_factory = factory_binding
- .cast::<dyn IFactory<(), Interface>>()
- .map_err(|_| DIContainerError::CastFailed {
- interface: type_name::<Interface>(),
- binding_kind: "factory",
- })?;
-
- Ok(SomePtr::Transient(default_factory()))
- }
- }
+ use crate::interfaces::factory::IFactory;
+
+ let factory = factory_binding
+ .cast::<dyn IFactory<(Rc<DIContainer>,), Interface>>()
+ .map_err(|_| DIContainerError::CastFailed {
+ interface: type_name::<Interface>(),
+ binding_kind: "factory",
+ })?;
+
+ Ok(SomePtr::Factory(factory(self.clone()).into()))
+ }
+ #[cfg(feature = "factory")]
+ Providable::DefaultFactory(factory_binding) => {
+ use crate::interfaces::factory::IFactory;
+
+ let default_factory = factory_binding
+ .cast::<dyn IFactory<(Rc<DIContainer>,), Interface>>()
+ .map_err(|_| DIContainerError::CastFailed {
+ interface: type_name::<Interface>(),
+ binding_kind: "default factory",
+ })?;
+
+ Ok(SomePtr::Transient(default_factory(self.clone())))
}
}
}
@@ -690,12 +717,16 @@ mod tests
assert_eq!(di_container.bindings.borrow().count(), 0);
- di_container.bind::<IUserManagerFactory>().to_factory(&|| {
- let user_manager: TransientPtr<dyn subjects::IUserManager> =
- TransientPtr::new(subjects::UserManager::new());
+ di_container
+ .bind::<IUserManagerFactory>()
+ .to_factory(&|_| {
+ Box::new(move || {
+ let user_manager: TransientPtr<dyn subjects::IUserManager> =
+ TransientPtr::new(subjects::UserManager::new());
- user_manager
- })?;
+ user_manager
+ })
+ })?;
assert_eq!(di_container.bindings.borrow().count(), 1);
@@ -715,11 +746,13 @@ mod tests
di_container
.bind::<IUserManagerFactory>()
- .to_factory(&|| {
- let user_manager: TransientPtr<dyn subjects::IUserManager> =
- TransientPtr::new(subjects::UserManager::new());
+ .to_factory(&|_| {
+ Box::new(move || {
+ let user_manager: TransientPtr<dyn subjects::IUserManager> =
+ TransientPtr::new(subjects::UserManager::new());
- user_manager
+ user_manager
+ })
})?
.when_named("awesome")?;
@@ -901,6 +934,8 @@ mod tests
#[cfg(feature = "factory")]
fn can_get_factory() -> Result<(), Box<dyn Error>>
{
+ use crate::ptr::FactoryPtr;
+
trait IUserManager
{
fn add_user(&mut self, user_id: i128);
@@ -940,8 +975,7 @@ mod tests
use crate as syrette;
#[crate::factory]
- type IUserManagerFactory =
- dyn crate::interfaces::factory::IFactory<(Vec<i128>,), dyn IUserManager>;
+ type IUserManagerFactory = dyn Fn(Vec<i128>) -> TransientPtr<dyn IUserManager>;
mock! {
Provider {}
@@ -958,17 +992,26 @@ mod tests
let di_container = DIContainer::new();
- let mut mock_provider = MockProvider::new();
+ let factory_func: &'static dyn Fn<
+ (std::rc::Rc<DIContainer>,),
+ Output = Box<
+ dyn Fn<(Vec<i128>,), Output = crate::ptr::TransientPtr<dyn IUserManager>>,
+ >,
+ > = &|_: Rc<DIContainer>| {
+ Box::new(move |users| {
+ let user_manager: TransientPtr<dyn IUserManager> =
+ TransientPtr::new(UserManager::new(users));
- mock_provider.expect_provide().returning(|_, _| {
- Ok(Providable::Factory(crate::ptr::FactoryPtr::new(
- CastableFactory::new(&|users| {
- let user_manager: TransientPtr<dyn IUserManager> =
- TransientPtr::new(UserManager::new(users));
+ user_manager
+ })
+ };
- user_manager
- }),
- )))
+ let mut mock_provider = MockProvider::new();
+
+ mock_provider.expect_provide().returning_st(|_, _| {
+ Ok(Providable::Factory(FactoryPtr::new(CastableFactory::new(
+ factory_func,
+ ))))
});
di_container
@@ -985,6 +1028,8 @@ mod tests
#[cfg(feature = "factory")]
fn can_get_factory_named() -> Result<(), Box<dyn Error>>
{
+ use crate::ptr::FactoryPtr;
+
trait IUserManager
{
fn add_user(&mut self, user_id: i128);
@@ -1024,8 +1069,7 @@ mod tests
use crate as syrette;
#[crate::factory]
- type IUserManagerFactory =
- dyn crate::interfaces::factory::IFactory<(Vec<i128>,), dyn IUserManager>;
+ type IUserManagerFactory = dyn Fn(Vec<i128>) -> TransientPtr<dyn IUserManager>;
mock! {
Provider {}
@@ -1042,17 +1086,26 @@ mod tests
let di_container = DIContainer::new();
- let mut mock_provider = MockProvider::new();
+ let factory_func: &'static dyn Fn<
+ (std::rc::Rc<DIContainer>,),
+ Output = Box<
+ dyn Fn<(Vec<i128>,), Output = crate::ptr::TransientPtr<dyn IUserManager>>,
+ >,
+ > = &|_: Rc<DIContainer>| {
+ Box::new(move |users| {
+ let user_manager: TransientPtr<dyn IUserManager> =
+ TransientPtr::new(UserManager::new(users));
- mock_provider.expect_provide().returning(|_, _| {
- Ok(Providable::Factory(crate::ptr::FactoryPtr::new(
- CastableFactory::new(&|users| {
- let user_manager: TransientPtr<dyn IUserManager> =
- TransientPtr::new(UserManager::new(users));
+ user_manager
+ })
+ };
- user_manager
- }),
- )))
+ let mut mock_provider = MockProvider::new();
+
+ mock_provider.expect_provide().returning_st(|_, _| {
+ Ok(Providable::Factory(FactoryPtr::new(CastableFactory::new(
+ factory_func,
+ ))))
});
di_container
diff --git a/src/provider/blocking.rs b/src/provider/blocking.rs
index 69bbe78..e00786b 100644
--- a/src/provider/blocking.rs
+++ b/src/provider/blocking.rs
@@ -14,6 +14,10 @@ pub enum Providable
Singleton(SingletonPtr<dyn Injectable>),
#[cfg(feature = "factory")]
Factory(crate::ptr::FactoryPtr<dyn crate::interfaces::any_factory::AnyFactory>),
+ #[cfg(feature = "factory")]
+ DefaultFactory(
+ crate::ptr::FactoryPtr<dyn crate::interfaces::any_factory::AnyFactory>,
+ ),
}
pub trait IProvider
@@ -96,6 +100,7 @@ where
pub struct FactoryProvider
{
factory: crate::ptr::FactoryPtr<dyn crate::interfaces::any_factory::AnyFactory>,
+ is_default_factory: bool,
}
#[cfg(feature = "factory")]
@@ -103,9 +108,13 @@ impl FactoryProvider
{
pub fn new(
factory: crate::ptr::FactoryPtr<dyn crate::interfaces::any_factory::AnyFactory>,
+ is_default_factory: bool,
) -> Self
{
- Self { factory }
+ Self {
+ factory,
+ is_default_factory,
+ }
}
}
@@ -118,6 +127,10 @@ impl IProvider for FactoryProvider
_dependency_history: Vec<&'static str>,
) -> Result<Providable, InjectableError>
{
- Ok(Providable::Factory(self.factory.clone()))
+ Ok(if self.is_default_factory {
+ Providable::DefaultFactory(self.factory.clone())
+ } else {
+ Providable::Factory(self.factory.clone())
+ })
}
}