From 9e01cdf341a7866180b3a63d745f3b2d7578d28a Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 23 Oct 2022 18:12:23 +0200 Subject: refactor!: reduce DI container coupling BREAKING CHANGE: You now have to import the DI containers's interfaces to use the DI containers's methods --- src/di_container/asynchronous/mod.rs | 217 +++++++++++++++++++++++++++-------- 1 file changed, 166 insertions(+), 51 deletions(-) (limited to 'src/di_container/asynchronous/mod.rs') diff --git a/src/di_container/asynchronous/mod.rs b/src/di_container/asynchronous/mod.rs index b6653a5..14e6abe 100644 --- a/src/di_container/asynchronous/mod.rs +++ b/src/di_container/asynchronous/mod.rs @@ -5,7 +5,8 @@ //! use std::collections::HashMap; //! use std::error::Error; //! -//! use syrette::{injectable, AsyncDIContainer}; +//! use syrette::di_container::asynchronous::prelude::*; +//! use syrette::injectable; //! //! trait IDatabaseService: Send + Sync //! { @@ -53,6 +54,7 @@ use std::any::type_name; use std::sync::Arc; +use async_trait::async_trait; use tokio::sync::Mutex; use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder; @@ -65,11 +67,64 @@ use crate::provider::r#async::{AsyncProvidable, IAsyncProvider}; use crate::ptr::{SomeThreadsafePtr, TransientPtr}; pub mod binding; +pub mod prelude; + +/// Dependency injection container interface. +#[async_trait] +pub trait IAsyncDIContainer: + Sized + 'static + Send + Sync + details::DIContainerInternals +{ + /// Returns a new [`AsyncBindingBuilder`] for the given interface. + #[must_use] + fn bind(self: &mut Arc) -> AsyncBindingBuilder + where + Interface: 'static + ?Sized + Send + Sync; + + /// 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 + fn get<'a, 'b, Interface>( + self: &'a Arc, + ) -> BoxFuture<'b, Result, AsyncDIContainerError>> + where + Interface: 'static + 'b + ?Sized + Send + Sync, + 'a: 'b, + Self: 'b; + + /// 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 + fn get_named<'a, 'b, Interface>( + self: &'a Arc, + name: &'static str, + ) -> BoxFuture<'b, Result, AsyncDIContainerError>> + where + Interface: 'static + 'b + ?Sized + Send + Sync, + 'a: 'b, + Self: 'b; + + #[doc(hidden)] + async fn get_bound( + self: &Arc, + dependency_history: Vec<&'static str>, + name: Option<&'static str>, + ) -> Result, AsyncDIContainerError> + where + Interface: 'static + ?Sized + Send + Sync; +} /// Dependency injection container. pub struct AsyncDIContainer { - bindings: Mutex>, + bindings: Mutex>>, } impl AsyncDIContainer @@ -82,51 +137,43 @@ impl AsyncDIContainer bindings: Mutex::new(DIContainerBindingMap::new()), }) } +} - /// Returns a new [`AsyncBindingBuilder`] for the given interface. +#[async_trait] +impl IAsyncDIContainer for AsyncDIContainer +{ #[must_use] - pub fn bind(self: &mut Arc) -> AsyncBindingBuilder + fn bind(self: &mut Arc) -> AsyncBindingBuilder where Interface: 'static + ?Sized + Send + Sync, { - AsyncBindingBuilder::::new(self.clone()) + AsyncBindingBuilder::new(self.clone()) } - /// 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 - pub async fn get( - self: &Arc, - ) -> Result, AsyncDIContainerError> + fn get<'a, 'b, Interface>( + self: &'a Arc, + ) -> BoxFuture<'b, Result, AsyncDIContainerError>> where - Interface: 'static + ?Sized + Send + Sync, + Interface: 'static + 'b + ?Sized + Send + Sync, + 'a: 'b, + Self: 'b, { - self.get_bound::(Vec::new(), None).await + Box::pin(async { self.get_bound::(Vec::new(), None).await }) } - /// 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 - pub async fn get_named( - self: &Arc, + fn get_named<'a, 'b, Interface>( + self: &'a Arc, name: &'static str, - ) -> Result, AsyncDIContainerError> + ) -> BoxFuture<'b, Result, AsyncDIContainerError>> where - Interface: 'static + ?Sized + Send + Sync, + Interface: 'static + 'b + ?Sized + Send + Sync, + 'a: 'b, + Self: 'b, { - self.get_bound::(Vec::new(), Some(name)).await + Box::pin(async { self.get_bound::(Vec::new(), Some(name)).await }) } - #[doc(hidden)] - pub async fn get_bound( + async fn get_bound( self: &Arc, dependency_history: Vec<&'static str>, name: Option<&'static str>, @@ -140,10 +187,44 @@ impl AsyncDIContainer self.handle_binding_providable(binding_providable).await } +} + +#[async_trait] +impl details::DIContainerInternals for AsyncDIContainer +{ + async fn has_binding(self: &Arc, name: Option<&'static str>) -> bool + where + Interface: ?Sized + 'static, + { + self.bindings.lock().await.has::(name) + } + + async fn set_binding( + self: &Arc, + name: Option<&'static str>, + provider: Box>, + ) where + Interface: 'static + ?Sized, + { + self.bindings.lock().await.set::(name, provider); + } + async fn remove_binding( + self: &Arc, + name: Option<&'static str>, + ) -> Option>> + where + Interface: 'static + ?Sized, + { + self.bindings.lock().await.remove::(name) + } +} + +impl AsyncDIContainer +{ async fn handle_binding_providable( self: &Arc, - binding_providable: AsyncProvidable, + binding_providable: AsyncProvidable, ) -> Result, AsyncDIContainerError> where Interface: 'static + ?Sized + Send + Sync, @@ -261,7 +342,7 @@ impl AsyncDIContainer self: &Arc, name: Option<&'static str>, dependency_history: Vec<&'static str>, - ) -> Result + ) -> Result, AsyncDIContainerError> where Interface: 'static + ?Sized + Send + Sync, { @@ -294,6 +375,40 @@ impl AsyncDIContainer } } +pub(crate) mod details +{ + use std::sync::Arc; + + use async_trait::async_trait; + + use crate::provider::r#async::IAsyncProvider; + + #[async_trait] + pub trait DIContainerInternals + { + async fn has_binding( + self: &Arc, + name: Option<&'static str>, + ) -> bool + where + Interface: ?Sized + 'static; + + async fn set_binding( + self: &Arc, + name: Option<&'static str>, + provider: Box>, + ) where + Interface: 'static + ?Sized; + + async fn remove_binding( + self: &Arc, + name: Option<&'static str>, + ) -> Option>> + where + Interface: 'static + ?Sized; + } +} + #[cfg(test)] mod tests { @@ -314,15 +429,15 @@ mod tests Provider {} #[async_trait] - impl IAsyncProvider for Provider + impl IAsyncProvider for Provider { async fn provide( &self, di_container: &Arc, dependency_history: Vec<&'static str>, - ) -> Result; + ) -> Result, InjectableError>; - fn do_clone(&self) -> Box; + fn do_clone(&self) -> Box>; } } @@ -365,15 +480,15 @@ mod tests Provider {} #[async_trait] - impl IAsyncProvider for Provider + impl IAsyncProvider for Provider { async fn provide( &self, di_container: &Arc, dependency_history: Vec<&'static str>, - ) -> Result; + ) -> Result, InjectableError>; - fn do_clone(&self) -> Box; + fn do_clone(&self) -> Box>; } } @@ -419,15 +534,15 @@ mod tests Provider {} #[async_trait] - impl IAsyncProvider for Provider + impl IAsyncProvider for Provider { async fn provide( &self, di_container: &Arc, dependency_history: Vec<&'static str>, - ) -> Result; + ) -> Result, InjectableError>; - fn do_clone(&self) -> Box; + fn do_clone(&self) -> Box>; } } @@ -483,15 +598,15 @@ mod tests Provider {} #[async_trait] - impl IAsyncProvider for Provider + impl IAsyncProvider for Provider { async fn provide( &self, di_container: &Arc, dependency_history: Vec<&'static str>, - ) -> Result; + ) -> Result, InjectableError>; - fn do_clone(&self) -> Box; + fn do_clone(&self) -> Box>; } } @@ -593,15 +708,15 @@ mod tests Provider {} #[async_trait] - impl IAsyncProvider for Provider + impl IAsyncProvider for Provider { async fn provide( &self, di_container: &Arc, dependency_history: Vec<&'static str>, - ) -> Result; + ) -> Result, InjectableError>; - fn do_clone(&self) -> Box; + fn do_clone(&self) -> Box>; } } @@ -704,15 +819,15 @@ mod tests Provider {} #[async_trait] - impl IAsyncProvider for Provider + impl IAsyncProvider for Provider { async fn provide( &self, di_container: &Arc, dependency_history: Vec<&'static str>, - ) -> Result; + ) -> Result, InjectableError>; - fn do_clone(&self) -> Box; + fn do_clone(&self) -> Box>; } } -- cgit v1.2.3-18-g5258