diff options
Diffstat (limited to 'src/di_container/blocking')
-rw-r--r-- | src/di_container/blocking/binding.rs (renamed from src/di_container/blocking/binding/mod.rs) | 0 | ||||
-rw-r--r-- | src/di_container/blocking/mod.rs | 722 |
2 files changed, 0 insertions, 722 deletions
diff --git a/src/di_container/blocking/binding/mod.rs b/src/di_container/blocking/binding.rs index 6a09bff..6a09bff 100644 --- a/src/di_container/blocking/binding/mod.rs +++ b/src/di_container/blocking/binding.rs diff --git a/src/di_container/blocking/mod.rs b/src/di_container/blocking/mod.rs deleted file mode 100644 index d8b0d59..0000000 --- a/src/di_container/blocking/mod.rs +++ /dev/null @@ -1,722 +0,0 @@ -//! Blocking dependency injection container. -//! -//! # Examples -//! ``` -//! use std::collections::HashMap; -//! use std::error::Error; -//! -//! use syrette::{injectable, DIContainer}; -//! -//! trait IDatabaseService -//! { -//! fn get_all_records(&self, table_name: String) -> HashMap<String, String>; -//! } -//! -//! struct DatabaseService {} -//! -//! #[injectable(IDatabaseService)] -//! impl DatabaseService -//! { -//! fn new() -> Self -//! { -//! Self {} -//! } -//! } -//! -//! impl IDatabaseService for DatabaseService -//! { -//! fn get_all_records(&self, table_name: String) -> HashMap<String, String> -//! { -//! // Do stuff here -//! HashMap::<String, String>::new() -//! } -//! } -//! -//! fn main() -> Result<(), Box<dyn Error>> -//! { -//! let mut di_container = DIContainer::new(); -//! -//! di_container -//! .bind::<dyn IDatabaseService>() -//! .to::<DatabaseService>() -//! .map_err(|err| err.to_string())?; -//! -//! let database_service = di_container -//! .get::<dyn IDatabaseService>() -//! .map_err(|err| err.to_string())? -//! .transient()?; -//! -//! Ok(()) -//! } -//! ``` -use std::any::type_name; - -use crate::di_container::binding_storage::DIContainerBindingStorage; -use crate::di_container::blocking::binding::builder::BindingBuilder; -use crate::di_container::BindingOptions; -use crate::errors::di_container::DIContainerError; -use crate::private::cast::boxed::CastBox; -use crate::private::cast::rc::CastRc; -use crate::provider::blocking::{IProvider, Providable}; -use crate::ptr::SomePtr; -use crate::util::use_double; - -use_double!(crate::dependency_history::DependencyHistory); - -pub mod binding; - -#[cfg(not(test))] -pub(crate) type BindingOptionsWithLt<'a> = BindingOptions<'a>; - -#[cfg(test)] -pub(crate) type BindingOptionsWithLt = BindingOptions<'static>; - -/// Blocking dependency injection container. -#[derive(Default)] -pub struct DIContainer -{ - binding_storage: DIContainerBindingStorage<dyn IProvider<Self>>, -} - -impl DIContainer -{ - /// Returns a new `DIContainer`. - #[must_use] - pub fn new() -> Self - { - Self { - binding_storage: DIContainerBindingStorage::new(), - } - } -} - -#[cfg_attr(test, mockall::automock)] -impl DIContainer -{ - /// Returns a new [`BindingBuilder`] for the given interface. - /// - /// # Examples - /// ``` - /// # use syrette::{DIContainer, injectable}; - /// # - /// # struct DiskWriter {} - /// # - /// # #[injectable] - /// # impl DiskWriter - /// # { - /// # fn new() -> Self - /// # { - /// # Self {} - /// # } - /// # } - /// # - /// # fn main() -> Result<(), Box<dyn std::error::Error>> { - /// let mut di_container = DIContainer::new(); - /// - /// di_container.bind::<DiskWriter>().to::<DiskWriter>()?; - /// # - /// # Ok(()) - /// # } - /// ``` - #[allow(clippy::missing_panics_doc)] - pub fn bind<Interface>(&mut self) -> BindingBuilder<'_, Interface> - where - Interface: 'static + ?Sized, - { - #[cfg(test)] - panic!("Nope"); - - #[cfg(not(test))] - BindingBuilder::new(self, DependencyHistory::new) - } - - /// 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 - /// - /// # Examples - /// ``` - /// # use syrette::{DIContainer, injectable}; - /// # - /// # struct DeviceManager {} - /// # - /// # #[injectable] - /// # impl DeviceManager - /// # { - /// # fn new() -> Self - /// # { - /// # Self {} - /// # } - /// # } - /// # - /// # fn main() -> Result<(), Box<dyn std::error::Error>> { - /// let mut di_container = DIContainer::new(); - /// - /// di_container.bind::<DeviceManager>().to::<DeviceManager>()?; - /// - /// let device_manager = di_container.get::<DeviceManager>()?.transient(); - /// # - /// # Ok(()) - /// # } - /// ``` - pub fn get<Interface>(&self) -> Result<SomePtr<Interface>, DIContainerError> - where - Interface: 'static + ?Sized, - { - self.get_bound::<Interface>(DependencyHistory::new(), BindingOptions::new()) - } - - /// 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 - /// - /// # Examples - /// ``` - /// # use syrette::{DIContainer, injectable}; - /// # - /// # struct DeviceManager {} - /// # - /// # #[injectable] - /// # impl DeviceManager - /// # { - /// # fn new() -> Self - /// # { - /// # Self {} - /// # } - /// # } - /// # - /// # fn main() -> Result<(), Box<dyn std::error::Error>> { - /// let mut di_container = DIContainer::new(); - /// - /// di_container - /// .bind::<DeviceManager>() - /// .to::<DeviceManager>()? - /// .in_transient_scope() - /// .when_named("usb")?; - /// - /// let device_manager = di_container.get_named::<DeviceManager>("usb")?.transient(); - /// # - /// # Ok(()) - /// # } - /// ``` - pub fn get_named<Interface>( - &self, - name: &'static str, - ) -> Result<SomePtr<Interface>, DIContainerError> - where - Interface: 'static + ?Sized, - { - self.get_bound::<Interface>( - DependencyHistory::new(), - BindingOptions::new().name(name), - ) - } - - /// Returns the type bound with `Interface` where the binding has the specified - /// options. - /// - /// `dependency_history` is passed to the bound type when it is being resolved. - /// - /// # Errors - /// Will return `Err` if: - /// - No binding for `Interface` exists - /// - Resolving the binding for `Interface` fails - /// - Casting the binding for `Interface` fails - /// - /// # Examples - /// ```no_run - /// # use syrette::di_container::blocking::DIContainer; - /// # use syrette::dependency_history::DependencyHistory; - /// # use syrette::di_container::BindingOptions; - /// # - /// # struct EventHandler {} - /// # struct Button {} - /// # - /// # fn main() -> Result<(), Box<dyn std::error::Error>> { - /// # let di_container = DIContainer::new(); - /// # - /// let mut dependency_history = DependencyHistory::new(); - /// - /// dependency_history.push::<EventHandler>(); - /// - /// di_container.get_bound::<Button>( - /// dependency_history, - /// BindingOptions::new().name("huge_red"), - /// )?; - /// # - /// # Ok(()) - /// # } - /// ``` - pub fn get_bound<Interface>( - &self, - dependency_history: DependencyHistory, - binding_options: BindingOptionsWithLt, - ) -> Result<SomePtr<Interface>, DIContainerError> - where - Interface: 'static + ?Sized, - { - let binding_providable = self - .get_binding_providable::<Interface>(binding_options, dependency_history)?; - - match binding_providable { - Providable::Transient(transient_binding) => Ok(SomePtr::Transient( - transient_binding.cast::<Interface>().map_err(|_| { - DIContainerError::CastFailed { - interface: type_name::<Interface>(), - binding_kind: "transient", - } - })?, - )), - Providable::Singleton(singleton_binding) => Ok(SomePtr::Singleton( - singleton_binding.cast::<Interface>().map_err(|_| { - DIContainerError::CastFailed { - interface: type_name::<Interface>(), - binding_kind: "singleton", - } - })?, - )), - #[cfg(feature = "factory")] - Providable::Factory(factory_binding) => { - use crate::castable_function::CastableFunction; - - let factory = factory_binding - .as_any() - .downcast_ref::<CastableFunction<Interface, Self>>() - .ok_or_else(|| DIContainerError::CastFailed { - interface: type_name::<Interface>(), - binding_kind: "factory", - })?; - - Ok(SomePtr::Factory(factory.call(self).into())) - } - #[cfg(feature = "factory")] - Providable::DefaultFactory(factory_binding) => { - use crate::castable_function::CastableFunction; - use crate::ptr::TransientPtr; - - type DefaultFactoryFn<Interface> = - CastableFunction<dyn Fn() -> TransientPtr<Interface>, DIContainer>; - - let default_factory = factory_binding - .as_any() - .downcast_ref::<DefaultFactoryFn<Interface>>() - .ok_or_else(|| DIContainerError::CastFailed { - interface: type_name::<Interface>(), - binding_kind: "default factory", - })?; - - Ok(SomePtr::Transient(default_factory.call(self)())) - } - } - } - - fn has_binding<Interface>(&self, binding_options: BindingOptionsWithLt) -> bool - where - Interface: ?Sized + 'static, - { - self.binding_storage.has::<Interface>(binding_options) - } - - fn set_binding<Interface>( - &mut self, - binding_options: BindingOptions<'static>, - provider: Box<dyn IProvider<Self>>, - ) where - Interface: 'static + ?Sized, - { - self.binding_storage - .set::<Interface>(binding_options, provider); - } - - fn remove_binding<Interface>( - &mut self, - binding_options: BindingOptions<'static>, - ) -> Option<Box<dyn IProvider<Self>>> - where - Interface: 'static + ?Sized, - { - self.binding_storage.remove::<Interface>(binding_options) - } -} - -impl DIContainer -{ - fn get_binding_providable<Interface>( - &self, - binding_options: BindingOptionsWithLt, - dependency_history: DependencyHistory, - ) -> Result<Providable<Self>, DIContainerError> - where - Interface: 'static + ?Sized, - { - let name = binding_options.name; - - self.binding_storage - .get::<Interface>(binding_options) - .map_or_else( - || { - Err(DIContainerError::BindingNotFound { - interface: type_name::<Interface>(), - name: name.as_ref().map(ToString::to_string), - }) - }, - Ok, - )? - .provide(self, dependency_history) - .map_err(|err| DIContainerError::BindingResolveFailed { - reason: err, - interface: type_name::<Interface>(), - }) - } -} - -#[cfg(test)] -mod tests -{ - use super::*; - use crate::provider::blocking::MockIProvider; - use crate::ptr::{SingletonPtr, TransientPtr}; - use crate::test_utils::subjects; - - #[test] - fn can_get() - { - let mut di_container = DIContainer::new(); - - let mut mock_provider = MockIProvider::new(); - - mock_provider.expect_provide().returning(|_, _| { - Ok(Providable::Transient(TransientPtr::new( - subjects::UserManager::new(), - ))) - }); - - di_container - .binding_storage - .set::<dyn subjects::IUserManager>( - BindingOptions::new(), - Box::new(mock_provider), - ); - - di_container - .get::<dyn subjects::IUserManager>() - .unwrap() - .transient() - .unwrap(); - } - - #[test] - fn can_get_named() - { - let mut di_container = DIContainer::new(); - - let mut mock_provider = MockIProvider::new(); - - mock_provider.expect_provide().returning(|_, _| { - Ok(Providable::Transient(TransientPtr::new( - subjects::UserManager::new(), - ))) - }); - - di_container - .binding_storage - .set::<dyn subjects::IUserManager>( - BindingOptions::new().name("special"), - Box::new(mock_provider), - ); - - di_container - .get_named::<dyn subjects::IUserManager>("special") - .unwrap() - .transient() - .unwrap(); - } - - #[test] - fn can_get_singleton() - { - let mut di_container = DIContainer::new(); - - let mut mock_provider = MockIProvider::new(); - - let mut singleton = SingletonPtr::new(subjects::Number::new()); - - SingletonPtr::get_mut(&mut singleton).unwrap().num = 2820; - - mock_provider - .expect_provide() - .returning_st(move |_, _| Ok(Providable::Singleton(singleton.clone()))); - - di_container - .binding_storage - .set::<dyn subjects::INumber>(BindingOptions::new(), Box::new(mock_provider)); - - let first_number_rc = di_container - .get::<dyn subjects::INumber>() - .unwrap() - .singleton() - .unwrap(); - - assert_eq!(first_number_rc.get(), 2820); - - let second_number_rc = di_container - .get::<dyn subjects::INumber>() - .unwrap() - .singleton() - .unwrap(); - - assert_eq!(first_number_rc.as_ref(), second_number_rc.as_ref()); - } - - #[test] - fn can_get_singleton_named() - { - let mut di_container = DIContainer::new(); - - let mut mock_provider = MockIProvider::new(); - - let mut singleton = SingletonPtr::new(subjects::Number::new()); - - SingletonPtr::get_mut(&mut singleton).unwrap().num = 2820; - - mock_provider - .expect_provide() - .returning_st(move |_, _| Ok(Providable::Singleton(singleton.clone()))); - - di_container.binding_storage.set::<dyn subjects::INumber>( - BindingOptions::new().name("cool"), - Box::new(mock_provider), - ); - - let first_number_rc = di_container - .get_named::<dyn subjects::INumber>("cool") - .unwrap() - .singleton() - .unwrap(); - - assert_eq!(first_number_rc.get(), 2820); - - let second_number_rc = di_container - .get_named::<dyn subjects::INumber>("cool") - .unwrap() - .singleton() - .unwrap(); - - assert_eq!(first_number_rc.as_ref(), second_number_rc.as_ref()); - } - - #[test] - #[cfg(feature = "factory")] - fn can_get_factory() - { - use crate::castable_function::CastableFunction; - use crate::ptr::FactoryPtr; - - trait IUserManager - { - fn add_user(&mut self, user_id: i128); - - fn remove_user(&mut self, user_id: i128); - } - - struct UserManager - { - users: Vec<i128>, - } - - impl UserManager - { - fn new(users: Vec<i128>) -> Self - { - Self { users } - } - } - - impl IUserManager for UserManager - { - fn add_user(&mut self, user_id: i128) - { - self.users.push(user_id); - } - - fn remove_user(&mut self, user_id: i128) - { - let user_index = - self.users.iter().position(|user| *user == user_id).unwrap(); - - self.users.remove(user_index); - } - } - - type IUserManagerFactory = dyn Fn(Vec<i128>) -> TransientPtr<dyn IUserManager>; - - let mut di_container = DIContainer::new(); - - let factory_func: &dyn Fn(&DIContainer) -> Box<IUserManagerFactory> = &|_| { - Box::new(move |users| { - let user_manager: TransientPtr<dyn IUserManager> = - TransientPtr::new(UserManager::new(users)); - - user_manager - }) - }; - - let mut mock_provider = MockIProvider::new(); - - mock_provider.expect_provide().returning_st(|_, _| { - Ok(Providable::Factory(FactoryPtr::new(CastableFunction::new( - factory_func, - )))) - }); - - di_container - .binding_storage - .set::<IUserManagerFactory>(BindingOptions::new(), Box::new(mock_provider)); - - di_container - .get::<IUserManagerFactory>() - .unwrap() - .factory() - .unwrap(); - } - - #[test] - #[cfg(feature = "factory")] - fn can_get_factory_named() - { - use crate::castable_function::CastableFunction; - use crate::ptr::FactoryPtr; - - trait IUserManager - { - fn add_user(&mut self, user_id: i128); - - fn remove_user(&mut self, user_id: i128); - } - - struct UserManager - { - users: Vec<i128>, - } - - impl UserManager - { - fn new(users: Vec<i128>) -> Self - { - Self { users } - } - } - - impl IUserManager for UserManager - { - fn add_user(&mut self, user_id: i128) - { - self.users.push(user_id); - } - - fn remove_user(&mut self, user_id: i128) - { - let user_index = - self.users.iter().position(|user| *user == user_id).unwrap(); - - self.users.remove(user_index); - } - } - - type IUserManagerFactory = dyn Fn(Vec<i128>) -> TransientPtr<dyn IUserManager>; - - let mut di_container = DIContainer::new(); - - let factory_func: &dyn Fn(&DIContainer) -> Box<IUserManagerFactory> = &|_| { - Box::new(move |users| { - let user_manager: TransientPtr<dyn IUserManager> = - TransientPtr::new(UserManager::new(users)); - - user_manager - }) - }; - - let mut mock_provider = MockIProvider::new(); - - mock_provider.expect_provide().returning_st(|_, _| { - Ok(Providable::Factory(FactoryPtr::new(CastableFunction::new( - factory_func, - )))) - }); - - di_container.binding_storage.set::<IUserManagerFactory>( - BindingOptions::new().name("special"), - Box::new(mock_provider), - ); - - di_container - .get_named::<IUserManagerFactory>("special") - .unwrap() - .factory() - .unwrap(); - } - - #[test] - fn has_binding_works() - { - let mut di_container = DIContainer::new(); - - // No binding is present yet - assert!(!di_container.has_binding::<subjects::Ninja>(BindingOptions::new())); - - di_container.binding_storage.set::<subjects::Ninja>( - BindingOptions::new(), - Box::new(MockIProvider::new()), - ); - - assert!(di_container.has_binding::<subjects::Ninja>(BindingOptions::new())); - } - - #[test] - fn set_binding_works() - { - let mut di_container = DIContainer::new(); - - di_container.set_binding::<subjects::Ninja>( - BindingOptions::new(), - Box::new(MockIProvider::new()), - ); - - assert!(di_container - .binding_storage - .has::<subjects::Ninja>(BindingOptions::new())); - } - - #[test] - fn remove_binding_works() - { - let mut di_container = DIContainer::new(); - - di_container.binding_storage.set::<subjects::Ninja>( - BindingOptions::new(), - Box::new(MockIProvider::new()), - ); - - assert!( - // Formatting is weird without this comment - di_container - .remove_binding::<subjects::Ninja>(BindingOptions::new()) - .is_some() - ); - - assert!( - // Formatting is weird without this comment - !di_container - .binding_storage - .has::<subjects::Ninja>(BindingOptions::new()) - ); - } -} |