diff options
author | HampusM <hampus@hampusmat.com> | 2022-10-29 14:38:51 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-10-29 14:40:11 +0200 |
commit | aa548ded39c7ba1927019c748c359523b21d59e8 (patch) | |
tree | 779d104f85009dd831e6af6e7a523258a1ab5be9 /src/provider | |
parent | da94fd3b7dd2265f10957d0f5276881beb057d82 (diff) |
refactor!: add dependency history type
BREAKING CHANGE: Binding builders & configurators now take dependency history type arguments, the DetectedCircular variant of InjectableError now contains a dependency history field & the injectable traits take dependency history instead of a Vec
Diffstat (limited to 'src/provider')
-rw-r--r-- | src/provider/async.rs | 161 | ||||
-rw-r--r-- | src/provider/blocking.rs | 124 |
2 files changed, 177 insertions, 108 deletions
diff --git a/src/provider/async.rs b/src/provider/async.rs index 8d482cd..557617b 100644 --- a/src/provider/async.rs +++ b/src/provider/async.rs @@ -3,18 +3,24 @@ use std::sync::Arc; use async_trait::async_trait; +use crate::dependency_history::IDependencyHistory; use crate::di_container::asynchronous::IAsyncDIContainer; use crate::errors::injectable::InjectableError; use crate::interfaces::async_injectable::AsyncInjectable; use crate::ptr::{ThreadsafeSingletonPtr, TransientPtr}; #[derive(strum_macros::Display, Debug)] -pub enum AsyncProvidable<DIContainerType> +pub enum AsyncProvidable<DIContainerType, DependencyHistoryType> where - DIContainerType: IAsyncDIContainer, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { - Transient(TransientPtr<dyn AsyncInjectable<DIContainerType>>), - Singleton(ThreadsafeSingletonPtr<dyn AsyncInjectable<DIContainerType>>), + Transient(TransientPtr<dyn AsyncInjectable<DIContainerType, DependencyHistoryType>>), + Singleton( + ThreadsafeSingletonPtr< + dyn AsyncInjectable<DIContainerType, DependencyHistoryType>, + >, + ), #[cfg(feature = "factory")] Factory( crate::ptr::ThreadsafeFactoryPtr< @@ -37,22 +43,26 @@ where #[async_trait] #[cfg_attr(test, mockall::automock, allow(dead_code))] -pub trait IAsyncProvider<DIContainerType>: Send + Sync +pub trait IAsyncProvider<DIContainerType, DependencyHistoryType>: Send + Sync where - DIContainerType: IAsyncDIContainer, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { async fn provide( &self, di_container: &Arc<DIContainerType>, - dependency_history: Vec<&'static str>, - ) -> Result<AsyncProvidable<DIContainerType>, InjectableError>; + dependency_history: DependencyHistoryType, + ) -> Result<AsyncProvidable<DIContainerType, DependencyHistoryType>, InjectableError>; - fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>>; + fn do_clone(&self) + -> Box<dyn IAsyncProvider<DIContainerType, DependencyHistoryType>>; } -impl<DIContainerType> Clone for Box<dyn IAsyncProvider<DIContainerType>> +impl<DIContainerType, DependencyHistoryType> Clone + for Box<dyn IAsyncProvider<DIContainerType, DependencyHistoryType>> where - DIContainerType: IAsyncDIContainer, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { fn clone(&self) -> Self { @@ -60,127 +70,148 @@ where } } -pub struct AsyncTransientTypeProvider<InjectableType, DIContainerType> -where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, +pub struct AsyncTransientTypeProvider< + InjectableType, + DIContainerType, + DependencyHistoryType, +> where + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { injectable_phantom: PhantomData<InjectableType>, di_container_phantom: PhantomData<DIContainerType>, + dependency_history_phantom: PhantomData<DependencyHistoryType>, } -impl<InjectableType, DIContainerType> - AsyncTransientTypeProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + AsyncTransientTypeProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { pub fn new() -> Self { Self { injectable_phantom: PhantomData, di_container_phantom: PhantomData, + dependency_history_phantom: PhantomData, } } } #[async_trait] -impl<InjectableType, DIContainerType> IAsyncProvider<DIContainerType> - for AsyncTransientTypeProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + IAsyncProvider<DIContainerType, DependencyHistoryType> + for AsyncTransientTypeProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync + 'static, { async fn provide( &self, di_container: &Arc<DIContainerType>, - dependency_history: Vec<&'static str>, - ) -> Result<AsyncProvidable<DIContainerType>, InjectableError> + dependency_history: DependencyHistoryType, + ) -> Result<AsyncProvidable<DIContainerType, DependencyHistoryType>, InjectableError> { Ok(AsyncProvidable::Transient( InjectableType::resolve(di_container, dependency_history).await?, )) } - fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>> + fn do_clone(&self) + -> Box<dyn IAsyncProvider<DIContainerType, DependencyHistoryType>> { Box::new(self.clone()) } } -impl<InjectableType, DIContainerType> Clone - for AsyncTransientTypeProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> Clone + for AsyncTransientTypeProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { fn clone(&self) -> Self { Self { injectable_phantom: self.injectable_phantom, - di_container_phantom: self.di_container_phantom, + di_container_phantom: PhantomData, + dependency_history_phantom: PhantomData, } } } -pub struct AsyncSingletonProvider<InjectableType, DIContainerType> +pub struct AsyncSingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { singleton: ThreadsafeSingletonPtr<InjectableType>, di_container_phantom: PhantomData<DIContainerType>, + dependency_history_phantom: PhantomData<DependencyHistoryType>, } -impl<InjectableType, DIContainerType> - AsyncSingletonProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + AsyncSingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { pub fn new(singleton: ThreadsafeSingletonPtr<InjectableType>) -> Self { Self { singleton, di_container_phantom: PhantomData, + dependency_history_phantom: PhantomData, } } } #[async_trait] -impl<InjectableType, DIContainerType> IAsyncProvider<DIContainerType> - for AsyncSingletonProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + IAsyncProvider<DIContainerType, DependencyHistoryType> + for AsyncSingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync + 'static, { async fn provide( &self, _di_container: &Arc<DIContainerType>, - _dependency_history: Vec<&'static str>, - ) -> Result<AsyncProvidable<DIContainerType>, InjectableError> + _dependency_history: DependencyHistoryType, + ) -> Result<AsyncProvidable<DIContainerType, DependencyHistoryType>, InjectableError> { Ok(AsyncProvidable::Singleton(self.singleton.clone())) } - fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>> + fn do_clone(&self) + -> Box<dyn IAsyncProvider<DIContainerType, DependencyHistoryType>> { Box::new(self.clone()) } } -impl<InjectableType, DIContainerType> Clone - for AsyncSingletonProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> Clone + for AsyncSingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: AsyncInjectable<DIContainerType>, - DIContainerType: IAsyncDIContainer, + InjectableType: AsyncInjectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync, { fn clone(&self) -> Self { Self { singleton: self.singleton.clone(), di_container_phantom: PhantomData, + dependency_history_phantom: PhantomData, } } } @@ -218,15 +249,17 @@ impl AsyncFactoryProvider #[cfg(feature = "factory")] #[async_trait] -impl<DIContainerType> IAsyncProvider<DIContainerType> for AsyncFactoryProvider +impl<DIContainerType, DependencyHistoryType> + IAsyncProvider<DIContainerType, DependencyHistoryType> for AsyncFactoryProvider where - DIContainerType: IAsyncDIContainer, + DIContainerType: IAsyncDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory + Send + Sync + 'static, { async fn provide( &self, _di_container: &Arc<DIContainerType>, - _dependency_history: Vec<&'static str>, - ) -> Result<AsyncProvidable<DIContainerType>, InjectableError> + _dependency_history: DependencyHistoryType, + ) -> Result<AsyncProvidable<DIContainerType, DependencyHistoryType>, InjectableError> { Ok(match self.variant { AsyncFactoryVariant::Normal => AsyncProvidable::Factory(self.factory.clone()), @@ -239,7 +272,8 @@ where }) } - fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerType>> + fn do_clone(&self) + -> Box<dyn IAsyncProvider<DIContainerType, DependencyHistoryType>> { Box::new(self.clone()) } @@ -263,6 +297,7 @@ mod tests use std::error::Error; use super::*; + use crate::test_utils::mocks::MockDependencyHistory; use crate::test_utils::{mocks, subjects_async}; #[tokio::test] @@ -270,7 +305,8 @@ mod tests { let transient_type_provider = AsyncTransientTypeProvider::< subjects_async::UserManager, - mocks::async_di_container::MockAsyncDIContainer, + mocks::async_di_container::MockAsyncDIContainer<mocks::MockDependencyHistory>, + mocks::MockDependencyHistory, >::new(); let di_container = mocks::async_di_container::MockAsyncDIContainer::new(); @@ -278,7 +314,7 @@ mod tests assert!( matches!( transient_type_provider - .provide(&Arc::new(di_container), vec![]) + .provide(&Arc::new(di_container), MockDependencyHistory::new()) .await?, AsyncProvidable::Transient(_) ), @@ -293,7 +329,8 @@ mod tests { let singleton_provider = AsyncSingletonProvider::< subjects_async::UserManager, - mocks::async_di_container::MockAsyncDIContainer, + mocks::async_di_container::MockAsyncDIContainer<mocks::MockDependencyHistory>, + mocks::MockDependencyHistory, >::new(ThreadsafeSingletonPtr::new( subjects_async::UserManager {}, )); @@ -303,7 +340,7 @@ mod tests assert!( matches!( singleton_provider - .provide(&Arc::new(di_container), vec![]) + .provide(&Arc::new(di_container), MockDependencyHistory::new()) .await?, AsyncProvidable::Singleton(_) ), @@ -345,7 +382,9 @@ mod tests assert!( matches!( - factory_provider.provide(&di_container, vec![]).await?, + factory_provider + .provide(&di_container, mocks::MockDependencyHistory::new()) + .await?, AsyncProvidable::Factory(_) ), "The provided type is not a factory" @@ -354,7 +393,7 @@ mod tests assert!( matches!( default_factory_provider - .provide(&di_container, vec![]) + .provide(&di_container, MockDependencyHistory::new()) .await?, AsyncProvidable::DefaultFactory(_) ), @@ -364,7 +403,7 @@ mod tests assert!( matches!( async_default_factory_provider - .provide(&di_container, vec![]) + .provide(&di_container, MockDependencyHistory::new()) .await?, AsyncProvidable::AsyncDefaultFactory(_) ), diff --git a/src/provider/blocking.rs b/src/provider/blocking.rs index e1e2aad..ebe0c37 100644 --- a/src/provider/blocking.rs +++ b/src/provider/blocking.rs @@ -1,18 +1,20 @@ use std::marker::PhantomData; use std::rc::Rc; +use crate::dependency_history::IDependencyHistory; use crate::di_container::blocking::IDIContainer; use crate::errors::injectable::InjectableError; use crate::interfaces::injectable::Injectable; use crate::ptr::{SingletonPtr, TransientPtr}; #[derive(strum_macros::Display, Debug)] -pub enum Providable<DIContainerType> +pub enum Providable<DIContainerType, DependencyHistoryType> where - DIContainerType: IDIContainer, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { - Transient(TransientPtr<dyn Injectable<DIContainerType>>), - Singleton(SingletonPtr<dyn Injectable<DIContainerType>>), + Transient(TransientPtr<dyn Injectable<DIContainerType, DependencyHistoryType>>), + Singleton(SingletonPtr<dyn Injectable<DIContainerType, DependencyHistoryType>>), #[cfg(feature = "factory")] Factory(crate::ptr::FactoryPtr<dyn crate::interfaces::any_factory::AnyFactory>), #[cfg(feature = "factory")] @@ -22,52 +24,59 @@ where } #[cfg_attr(test, mockall::automock, allow(dead_code))] -pub trait IProvider<DIContainerType> +pub trait IProvider<DIContainerType, DependencyHistoryType> where - DIContainerType: IDIContainer, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { fn provide( &self, di_container: &Rc<DIContainerType>, - dependency_history: Vec<&'static str>, - ) -> Result<Providable<DIContainerType>, InjectableError>; + dependency_history: DependencyHistoryType, + ) -> Result<Providable<DIContainerType, DependencyHistoryType>, InjectableError>; } -pub struct TransientTypeProvider<InjectableType, DIContainerType> +pub struct TransientTypeProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: Injectable<DIContainerType>, - DIContainerType: IDIContainer, + InjectableType: Injectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { injectable_phantom: PhantomData<InjectableType>, di_container_phantom: PhantomData<DIContainerType>, + dependency_history_phantom: PhantomData<DependencyHistoryType>, } -impl<InjectableType, DIContainerType> - TransientTypeProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + TransientTypeProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: Injectable<DIContainerType>, - DIContainerType: IDIContainer, + InjectableType: Injectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { pub fn new() -> Self { Self { injectable_phantom: PhantomData, di_container_phantom: PhantomData, + dependency_history_phantom: PhantomData, } } } -impl<InjectableType, DIContainerType> IProvider<DIContainerType> - for TransientTypeProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + IProvider<DIContainerType, DependencyHistoryType> + for TransientTypeProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: Injectable<DIContainerType>, - DIContainerType: IDIContainer, + InjectableType: Injectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { fn provide( &self, di_container: &Rc<DIContainerType>, - dependency_history: Vec<&'static str>, - ) -> Result<Providable<DIContainerType>, InjectableError> + dependency_history: DependencyHistoryType, + ) -> Result<Providable<DIContainerType, DependencyHistoryType>, InjectableError> { Ok(Providable::Transient(InjectableType::resolve( di_container, @@ -76,40 +85,48 @@ where } } -pub struct SingletonProvider<InjectableType, DIContainerType> +pub struct SingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: Injectable<DIContainerType>, - DIContainerType: IDIContainer, + InjectableType: Injectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { singleton: SingletonPtr<InjectableType>, + di_container_phantom: PhantomData<DIContainerType>, + dependency_history_phantom: PhantomData<DependencyHistoryType>, } -impl<InjectableType, DIContainerType> SingletonProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + SingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: Injectable<DIContainerType>, - DIContainerType: IDIContainer, + InjectableType: Injectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { pub fn new(singleton: SingletonPtr<InjectableType>) -> Self { Self { singleton, di_container_phantom: PhantomData, + dependency_history_phantom: PhantomData, } } } -impl<InjectableType, DIContainerType> IProvider<DIContainerType> - for SingletonProvider<InjectableType, DIContainerType> +impl<InjectableType, DIContainerType, DependencyHistoryType> + IProvider<DIContainerType, DependencyHistoryType> + for SingletonProvider<InjectableType, DIContainerType, DependencyHistoryType> where - InjectableType: Injectable<DIContainerType>, - DIContainerType: IDIContainer, + InjectableType: Injectable<DIContainerType, DependencyHistoryType>, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { fn provide( &self, _di_container: &Rc<DIContainerType>, - _dependency_history: Vec<&'static str>, - ) -> Result<Providable<DIContainerType>, InjectableError> + _dependency_history: DependencyHistoryType, + ) -> Result<Providable<DIContainerType, DependencyHistoryType>, InjectableError> { Ok(Providable::Singleton(self.singleton.clone())) } @@ -138,15 +155,17 @@ impl FactoryProvider } #[cfg(feature = "factory")] -impl<DIContainerType> IProvider<DIContainerType> for FactoryProvider +impl<DIContainerType, DependencyHistoryType> + IProvider<DIContainerType, DependencyHistoryType> for FactoryProvider where - DIContainerType: IDIContainer, + DIContainerType: IDIContainer<DependencyHistoryType>, + DependencyHistoryType: IDependencyHistory, { fn provide( &self, _di_container: &Rc<DIContainerType>, - _dependency_history: Vec<&'static str>, - ) -> Result<Providable<DIContainerType>, InjectableError> + _dependency_history: DependencyHistoryType, + ) -> Result<Providable<DIContainerType, DependencyHistoryType>, InjectableError> { Ok(if self.is_default_factory { Providable::DefaultFactory(self.factory.clone()) @@ -169,14 +188,18 @@ mod tests { let transient_type_provider = TransientTypeProvider::< subjects::UserManager, - mocks::blocking_di_container::MockDIContainer, + mocks::blocking_di_container::MockDIContainer<mocks::MockDependencyHistory>, + mocks::MockDependencyHistory, >::new(); let di_container = mocks::blocking_di_container::MockDIContainer::new(); + let dependency_history_mock = mocks::MockDependencyHistory::new(); + assert!( matches!( - transient_type_provider.provide(&Rc::new(di_container), vec![])?, + transient_type_provider + .provide(&Rc::new(di_container), dependency_history_mock)?, Providable::Transient(_) ), "The provided type is not transient" @@ -188,17 +211,22 @@ mod tests #[test] fn singleton_provider_works() -> Result<(), Box<dyn Error>> { - let singleton_provider = - SingletonProvider::< - subjects::UserManager, - mocks::blocking_di_container::MockDIContainer, - >::new(SingletonPtr::new(subjects::UserManager {})); + let singleton_provider = SingletonProvider::< + subjects::UserManager, + mocks::blocking_di_container::MockDIContainer<mocks::MockDependencyHistory>, + mocks::MockDependencyHistory, + >::new(SingletonPtr::new( + subjects::UserManager {}, + )); let di_container = mocks::blocking_di_container::MockDIContainer::new(); assert!( matches!( - singleton_provider.provide(&Rc::new(di_container), vec![])?, + singleton_provider.provide( + &Rc::new(di_container), + mocks::MockDependencyHistory::new() + )?, Providable::Singleton(_) ), "The provided type is not a singleton" @@ -227,7 +255,8 @@ mod tests assert!( matches!( - factory_provider.provide(&di_container, vec![])?, + factory_provider + .provide(&di_container, mocks::MockDependencyHistory::new())?, Providable::Factory(_) ), "The provided type is not a factory" @@ -235,7 +264,8 @@ mod tests assert!( matches!( - default_factory_provider.provide(&di_container, vec![])?, + default_factory_provider + .provide(&di_container, mocks::MockDependencyHistory::new())?, Providable::DefaultFactory(_) ), "The provided type is not a default factory" |