From e8e48906a3899e71c9c9d86a3d4528cb7d17e5b9 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 17 Sep 2022 12:57:18 +0200 Subject: refactor!: make DI container be used inside of a Rc BREAKING CHANGE: The DI container is to be used inside of a Rc & it also no longer implements Default --- examples/basic/bootstrap.rs | 5 +- examples/factory/bootstrap.rs | 5 +- examples/generics/bootstrap.rs | 4 +- examples/named/bootstrap.rs | 6 +- examples/unbound/bootstrap.rs | 6 +- examples/with-3rd-party/bootstrap.rs | 5 +- macros/src/injectable_impl.rs | 2 +- src/di_container.rs | 225 ++++++++++++++++++----------------- src/interfaces/injectable.rs | 3 +- src/provider/blocking.rs | 9 +- 10 files changed, 145 insertions(+), 125 deletions(-) diff --git a/examples/basic/bootstrap.rs b/examples/basic/bootstrap.rs index 4e02dc3..30f6df3 100644 --- a/examples/basic/bootstrap.rs +++ b/examples/basic/bootstrap.rs @@ -1,4 +1,5 @@ use std::error::Error; +use std::rc::Rc; use syrette::DIContainer; @@ -12,9 +13,9 @@ use crate::interfaces::cat::ICat; use crate::interfaces::dog::IDog; use crate::interfaces::human::IHuman; -pub fn bootstrap() -> Result> +pub fn bootstrap() -> Result, Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); di_container .bind::() diff --git a/examples/factory/bootstrap.rs b/examples/factory/bootstrap.rs index ad8c4d3..19fad81 100644 --- a/examples/factory/bootstrap.rs +++ b/examples/factory/bootstrap.rs @@ -1,4 +1,5 @@ use std::error::Error; +use std::rc::Rc; use syrette::ptr::TransientPtr; use syrette::DIContainer; @@ -11,9 +12,9 @@ use crate::interfaces::user_manager::IUserManager; use crate::user::User; use crate::user_manager::UserManager; -pub fn bootstrap() -> Result> +pub fn bootstrap() -> Result, Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); di_container .bind::() diff --git a/examples/generics/bootstrap.rs b/examples/generics/bootstrap.rs index 072350e..752a39b 100644 --- a/examples/generics/bootstrap.rs +++ b/examples/generics/bootstrap.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use syrette::{di_container_bind, DIContainer}; // Interfaces @@ -6,7 +8,7 @@ use crate::interfaces::printer::IPrinter; // Implementations use crate::printer::Printer; -pub fn bootstrap() -> DIContainer +pub fn bootstrap() -> Rc { let mut di_container = DIContainer::new(); diff --git a/examples/named/bootstrap.rs b/examples/named/bootstrap.rs index b5fa39d..5f63b47 100644 --- a/examples/named/bootstrap.rs +++ b/examples/named/bootstrap.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use anyhow::Result; use syrette::DIContainer; @@ -7,9 +9,9 @@ use crate::katana::Katana; use crate::ninja::Ninja; use crate::shuriken::Shuriken; -pub fn bootstrap() -> Result +pub fn bootstrap() -> Result> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); di_container .bind::() diff --git a/examples/unbound/bootstrap.rs b/examples/unbound/bootstrap.rs index 30366a6..8df6678 100644 --- a/examples/unbound/bootstrap.rs +++ b/examples/unbound/bootstrap.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use anyhow::Result; use syrette::DIContainer; @@ -11,9 +13,9 @@ use crate::interfaces::animal_store::IAnimalStore; use crate::interfaces::dog::IDog; use crate::interfaces::human::IHuman; -pub fn bootstrap() -> Result +pub fn bootstrap() -> Result> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); di_container .bind::() diff --git a/examples/with-3rd-party/bootstrap.rs b/examples/with-3rd-party/bootstrap.rs index 49de7fa..a4bd84a 100644 --- a/examples/with-3rd-party/bootstrap.rs +++ b/examples/with-3rd-party/bootstrap.rs @@ -1,4 +1,5 @@ use std::error::Error; +use std::rc::Rc; use syrette::ptr::TransientPtr; use syrette::{declare_default_factory, DIContainer}; @@ -12,9 +13,9 @@ use crate::ninja::Ninja; declare_default_factory!(Shuriken); -pub fn bootstrap() -> Result> +pub fn bootstrap() -> Result, Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); di_container.bind::().to::()?; diff --git a/macros/src/injectable_impl.rs b/macros/src/injectable_impl.rs index 3565ef9..af1fa68 100644 --- a/macros/src/injectable_impl.rs +++ b/macros/src/injectable_impl.rs @@ -121,7 +121,7 @@ impl InjectableImpl impl #generics syrette::interfaces::injectable::Injectable for #self_type { fn resolve( - #di_container_var: &syrette::DIContainer, + #di_container_var: &std::rc::Rc, mut #dependency_history_var: Vec<&'static str>, ) -> Result< syrette::ptr::TransientPtr, diff --git a/src/di_container.rs b/src/di_container.rs index df95be4..ddd3a4f 100644 --- a/src/di_container.rs +++ b/src/di_container.rs @@ -50,7 +50,9 @@ //! } //! ``` use std::any::type_name; +use std::cell::RefCell; use std::marker::PhantomData; +use std::rc::Rc; #[cfg(feature = "factory")] use crate::castable_factory::blocking::CastableFactory; @@ -72,19 +74,19 @@ use crate::provider::blocking::{ use crate::ptr::{SingletonPtr, SomePtr}; /// When configurator for a binding for type 'Interface' inside a [`DIContainer`]. -pub struct BindingWhenConfigurator<'di_container, Interface> +pub struct BindingWhenConfigurator where Interface: 'static + ?Sized, { - di_container: &'di_container mut DIContainer, + di_container: Rc, interface_phantom: PhantomData, } -impl<'di_container, Interface> BindingWhenConfigurator<'di_container, Interface> +impl BindingWhenConfigurator where Interface: 'static + ?Sized, { - fn new(di_container: &'di_container mut DIContainer) -> Self + fn new(di_container: Rc) -> Self { Self { di_container, @@ -97,50 +99,45 @@ where /// # Errors /// Will return Err if no binding for the interface already exists. pub fn when_named( - &mut self, + &self, name: &'static str, ) -> Result<(), BindingWhenConfiguratorError> { - let binding = self - .di_container - .bindings - .remove::(None) - .map_or_else( - || { - Err(BindingWhenConfiguratorError::BindingNotFound(type_name::< - Interface, - >( - ))) - }, - Ok, - )?; + let mut bindings_mut = self.di_container.bindings.borrow_mut(); - self.di_container - .bindings - .set::(Some(name), binding); + let binding = bindings_mut.remove::(None).map_or_else( + || { + Err(BindingWhenConfiguratorError::BindingNotFound(type_name::< + Interface, + >( + ))) + }, + Ok, + )?; + + bindings_mut.set::(Some(name), binding); Ok(()) } } /// Scope configurator for a binding for type 'Interface' inside a [`DIContainer`]. -pub struct BindingScopeConfigurator<'di_container, Interface, Implementation> +pub struct BindingScopeConfigurator where Interface: 'static + ?Sized, Implementation: Injectable, { - di_container: &'di_container mut DIContainer, + di_container: Rc, interface_phantom: PhantomData, implementation_phantom: PhantomData, } -impl<'di_container, Interface, Implementation> - BindingScopeConfigurator<'di_container, Interface, Implementation> +impl BindingScopeConfigurator where Interface: 'static + ?Sized, Implementation: Injectable, { - fn new(di_container: &'di_container mut DIContainer) -> Self + fn new(di_container: Rc) -> Self { Self { di_container, @@ -152,14 +149,17 @@ where /// Configures the binding to be in a transient scope. /// /// This is the default. - pub fn in_transient_scope(&mut self) -> BindingWhenConfigurator + #[allow(clippy::must_use_candidate)] + pub fn in_transient_scope(&self) -> BindingWhenConfigurator { - self.di_container.bindings.set::( + let mut bindings_mut = self.di_container.bindings.borrow_mut(); + + bindings_mut.set::( None, Box::new(TransientTypeProvider::::new()), ); - BindingWhenConfigurator::new(self.di_container) + BindingWhenConfigurator::new(self.di_container.clone()) } /// Configures the binding to be in a singleton scope. @@ -167,36 +167,36 @@ where /// # Errors /// Will return Err if resolving the implementation fails. pub fn in_singleton_scope( - &mut self, + &self, ) -> Result, BindingScopeConfiguratorError> { let singleton: SingletonPtr = SingletonPtr::from( - Implementation::resolve(self.di_container, Vec::new()) + Implementation::resolve(&self.di_container, Vec::new()) .map_err(BindingScopeConfiguratorError::SingletonResolveFailed)?, ); - self.di_container - .bindings - .set::(None, Box::new(SingletonProvider::new(singleton))); + let mut bindings_mut = self.di_container.bindings.borrow_mut(); - Ok(BindingWhenConfigurator::new(self.di_container)) + bindings_mut.set::(None, Box::new(SingletonProvider::new(singleton))); + + Ok(BindingWhenConfigurator::new(self.di_container.clone())) } } /// Binding builder for type `Interface` inside a [`DIContainer`]. -pub struct BindingBuilder<'di_container, Interface> +pub struct BindingBuilder where Interface: 'static + ?Sized, { - di_container: &'di_container mut DIContainer, + di_container: Rc, interface_phantom: PhantomData, } -impl<'di_container, Interface> BindingBuilder<'di_container, Interface> +impl BindingBuilder where Interface: 'static + ?Sized, { - fn new(di_container: &'di_container mut DIContainer) -> Self + fn new(di_container: Rc) -> Self { Self { di_container, @@ -214,19 +214,24 @@ where /// Will return Err if the associated [`DIContainer`] already have a binding for /// the interface. pub fn to( - &mut self, + &self, ) -> Result, BindingBuilderError> where Implementation: Injectable, { - if self.di_container.bindings.has::(None) { - return Err(BindingBuilderError::BindingAlreadyExists(type_name::< - Interface, - >())); + { + let bindings = self.di_container.bindings.borrow(); + + if bindings.has::(None) { + return Err(BindingBuilderError::BindingAlreadyExists(type_name::< + Interface, + >( + ))); + } } - let mut binding_scope_configurator = - BindingScopeConfigurator::new(self.di_container); + let binding_scope_configurator = + BindingScopeConfigurator::new(self.di_container.clone()); binding_scope_configurator.in_transient_scope(); @@ -243,7 +248,7 @@ where /// the interface. #[cfg(feature = "factory")] pub fn to_factory( - &mut self, + &self, factory_func: &'static dyn Fn>, ) -> Result, BindingBuilderError> where @@ -251,7 +256,9 @@ where Return: 'static + ?Sized, Interface: crate::interfaces::factory::IFactory, { - if self.di_container.bindings.has::(None) { + let mut bindings_mut = self.di_container.bindings.borrow_mut(); + + if bindings_mut.has::(None) { return Err(BindingBuilderError::BindingAlreadyExists(type_name::< Interface, >())); @@ -259,14 +266,14 @@ where let factory_impl = CastableFactory::new(factory_func); - self.di_container.bindings.set::( + bindings_mut.set::( None, Box::new(crate::provider::blocking::FactoryProvider::new( crate::ptr::FactoryPtr::new(factory_impl), )), ); - Ok(BindingWhenConfigurator::new(self.di_container)) + Ok(BindingWhenConfigurator::new(self.di_container.clone())) } /// Creates a binding of type `Interface` to a factory that takes no arguments @@ -279,13 +286,15 @@ where /// the interface. #[cfg(feature = "factory")] pub fn to_default_factory( - &mut self, + &self, factory_func: &'static dyn Fn<(), Output = crate::ptr::TransientPtr>, ) -> Result, BindingBuilderError> where Return: 'static + ?Sized, { - if self.di_container.bindings.has::(None) { + let mut bindings_mut = self.di_container.bindings.borrow_mut(); + + if bindings_mut.has::(None) { return Err(BindingBuilderError::BindingAlreadyExists(type_name::< Interface, >())); @@ -293,40 +302,40 @@ where let factory_impl = CastableFactory::new(factory_func); - self.di_container.bindings.set::( + bindings_mut.set::( None, Box::new(crate::provider::blocking::FactoryProvider::new( crate::ptr::FactoryPtr::new(factory_impl), )), ); - Ok(BindingWhenConfigurator::new(self.di_container)) + Ok(BindingWhenConfigurator::new(self.di_container.clone())) } } /// Dependency injection container. pub struct DIContainer { - bindings: DIContainerBindingMap, + bindings: RefCell>, } impl DIContainer { /// Returns a new `DIContainer`. #[must_use] - pub fn new() -> Self + pub fn new() -> Rc { - Self { - bindings: DIContainerBindingMap::new(), - } + Rc::new(Self { + bindings: RefCell::new(DIContainerBindingMap::new()), + }) } /// Returns a new [`BindingBuilder`] for the given interface. - pub fn bind(&mut self) -> BindingBuilder + pub fn bind(self: &mut Rc) -> BindingBuilder where Interface: 'static + ?Sized, { - BindingBuilder::::new(self) + BindingBuilder::::new(self.clone()) } /// Returns the type bound with `Interface`. @@ -336,7 +345,7 @@ impl DIContainer /// - No binding for `Interface` exists /// - Resolving the binding for fails /// - Casting the binding for fails - pub fn get(&self) -> Result, DIContainerError> + pub fn get(self: &Rc) -> Result, DIContainerError> where Interface: 'static + ?Sized, { @@ -351,7 +360,7 @@ impl DIContainer /// - Resolving the binding fails /// - Casting the binding for fails pub fn get_named( - &self, + self: &Rc, name: &'static str, ) -> Result, DIContainerError> where @@ -362,7 +371,7 @@ impl DIContainer #[doc(hidden)] pub fn get_bound( - &self, + self: &Rc, dependency_history: Vec<&'static str>, name: Option<&'static str>, ) -> Result, DIContainerError> @@ -420,7 +429,7 @@ impl DIContainer } fn get_binding_providable( - &self, + self: &Rc, name: Option<&'static str>, dependency_history: Vec<&'static str>, ) -> Result @@ -428,6 +437,7 @@ impl DIContainer Interface: 'static + ?Sized, { self.bindings + .borrow() .get::(name) .map_or_else( || { @@ -446,14 +456,6 @@ impl DIContainer } } -impl Default for DIContainer -{ - fn default() -> Self - { - Self::new() - } -} - #[cfg(test)] mod tests { @@ -471,6 +473,7 @@ mod tests //! Test subjects. use std::fmt::Debug; + use std::rc::Rc; use syrette_macros::declare_interface; @@ -515,7 +518,7 @@ mod tests impl Injectable for UserManager { fn resolve( - _di_container: &DIContainer, + _di_container: &Rc, _dependency_history: Vec<&'static str>, ) -> Result, crate::errors::injectable::InjectableError> where @@ -579,7 +582,7 @@ mod tests impl Injectable for Number { fn resolve( - _di_container: &DIContainer, + _di_container: &Rc, _dependency_history: Vec<&'static str>, ) -> Result, crate::errors::injectable::InjectableError> where @@ -593,15 +596,15 @@ mod tests #[test] fn can_bind_to() -> Result<(), Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container .bind::() .to::()?; - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -609,16 +612,16 @@ mod tests #[test] fn can_bind_to_transient() -> Result<(), Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container .bind::() .to::()? .in_transient_scope(); - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -626,9 +629,9 @@ mod tests #[test] fn can_bind_to_transient_when_named() -> Result<(), Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container .bind::() @@ -636,7 +639,7 @@ mod tests .in_transient_scope() .when_named("regular")?; - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -644,16 +647,16 @@ mod tests #[test] fn can_bind_to_singleton() -> Result<(), Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container .bind::() .to::()? .in_singleton_scope()?; - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -661,9 +664,9 @@ mod tests #[test] fn can_bind_to_singleton_when_named() -> Result<(), Box> { - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container .bind::() @@ -671,7 +674,7 @@ mod tests .in_singleton_scope()? .when_named("cool")?; - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -683,9 +686,9 @@ mod tests type IUserManagerFactory = dyn crate::interfaces::factory::IFactory<(), dyn subjects::IUserManager>; - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container.bind::().to_factory(&|| { let user_manager: TransientPtr = @@ -694,7 +697,7 @@ mod tests user_manager })?; - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -706,9 +709,9 @@ mod tests type IUserManagerFactory = dyn crate::interfaces::factory::IFactory<(), dyn subjects::IUserManager>; - let mut di_container: DIContainer = DIContainer::new(); + let mut di_container = DIContainer::new(); - assert_eq!(di_container.bindings.count(), 0); + assert_eq!(di_container.bindings.borrow().count(), 0); di_container .bind::() @@ -720,7 +723,7 @@ mod tests })? .when_named("awesome")?; - assert_eq!(di_container.bindings.count(), 1); + assert_eq!(di_container.bindings.borrow().count(), 1); Ok(()) } @@ -735,13 +738,13 @@ mod tests { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } } - let mut di_container: DIContainer = DIContainer::new(); + let di_container = DIContainer::new(); let mut mock_provider = MockProvider::new(); @@ -753,6 +756,7 @@ mod tests di_container .bindings + .borrow_mut() .set::(None, Box::new(mock_provider)); di_container @@ -772,13 +776,13 @@ mod tests { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } } - let mut di_container: DIContainer = DIContainer::new(); + let di_container = DIContainer::new(); let mut mock_provider = MockProvider::new(); @@ -790,6 +794,7 @@ mod tests di_container .bindings + .borrow_mut() .set::(Some("special"), Box::new(mock_provider)); di_container @@ -809,13 +814,13 @@ mod tests { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } } - let mut di_container: DIContainer = DIContainer::new(); + let di_container = DIContainer::new(); let mut mock_provider = MockProvider::new(); @@ -829,6 +834,7 @@ mod tests di_container .bindings + .borrow_mut() .set::(None, Box::new(mock_provider)); let first_number_rc = di_container.get::()?.singleton()?; @@ -853,13 +859,13 @@ mod tests { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } } - let mut di_container: DIContainer = DIContainer::new(); + let di_container = DIContainer::new(); let mut mock_provider = MockProvider::new(); @@ -873,6 +879,7 @@ mod tests di_container .bindings + .borrow_mut() .set::(Some("cool"), Box::new(mock_provider)); let first_number_rc = di_container @@ -943,13 +950,13 @@ mod tests { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } } - let mut di_container: DIContainer = DIContainer::new(); + let di_container = DIContainer::new(); let mut mock_provider = MockProvider::new(); @@ -966,6 +973,7 @@ mod tests di_container .bindings + .borrow_mut() .set::(None, Box::new(mock_provider)); di_container.get::()?.factory()?; @@ -1026,13 +1034,13 @@ mod tests { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } } - let mut di_container: DIContainer = DIContainer::new(); + let di_container = DIContainer::new(); let mut mock_provider = MockProvider::new(); @@ -1049,6 +1057,7 @@ mod tests di_container .bindings + .borrow_mut() .set::(Some("special"), Box::new(mock_provider)); di_container diff --git a/src/interfaces/injectable.rs b/src/interfaces/injectable.rs index f90b79d..f4c7fda 100644 --- a/src/interfaces/injectable.rs +++ b/src/interfaces/injectable.rs @@ -1,5 +1,6 @@ //! Interface for structs that can be injected into or be injected to. use std::fmt::Debug; +use std::rc::Rc; use crate::errors::injectable::InjectableError; use crate::libs::intertrait::CastFrom; @@ -14,7 +15,7 @@ pub trait Injectable: CastFrom /// # Errors /// Will return `Err` if resolving the dependencies fails. fn resolve( - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result, InjectableError> where diff --git a/src/provider/blocking.rs b/src/provider/blocking.rs index 13674b9..69bbe78 100644 --- a/src/provider/blocking.rs +++ b/src/provider/blocking.rs @@ -1,5 +1,6 @@ #![allow(clippy::module_name_repetitions)] use std::marker::PhantomData; +use std::rc::Rc; use crate::errors::injectable::InjectableError; use crate::interfaces::injectable::Injectable; @@ -19,7 +20,7 @@ pub trait IProvider { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result; } @@ -49,7 +50,7 @@ where { fn provide( &self, - di_container: &DIContainer, + di_container: &Rc, dependency_history: Vec<&'static str>, ) -> Result { @@ -83,7 +84,7 @@ where { fn provide( &self, - _di_container: &DIContainer, + _di_container: &Rc, _dependency_history: Vec<&'static str>, ) -> Result { @@ -113,7 +114,7 @@ impl IProvider for FactoryProvider { fn provide( &self, - _di_container: &DIContainer, + _di_container: &Rc, _dependency_history: Vec<&'static str>, ) -> Result { -- cgit v1.2.3-18-g5258