diff options
author | HampusM <hampus@hampusmat.com> | 2022-09-12 20:22:13 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-09-17 14:33:15 +0200 |
commit | c1e682c25c24be3174d44ceb95b0537c38299d0c (patch) | |
tree | 6e59f37e1b98e68fad2e3e2fe4a428ac97fcf8b4 /src | |
parent | e8e48906a3899e71c9c9d86a3d4528cb7d17e5b9 (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.rs | 173 | ||||
-rw-r--r-- | src/provider/blocking.rs | 17 |
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()) + }) } } |