aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-08-20 17:01:12 +0200
committerHampusM <hampus@hampusmat.com>2023-08-20 17:01:12 +0200
commit0b4232d343e2214ead8fa62583bff2e948173ddf (patch)
treef809051c9933a132971ab91244e83d1f9d387ad6
parentbe2c39b452b8b1e024300caff1ce8f11d54b27ce (diff)
feat: expose DI container get_bound methods to public API
-rw-r--r--macros/src/injectable/implementation.rs34
-rw-r--r--src/di_container/asynchronous/mod.rs85
-rw-r--r--src/di_container/binding_storage.rs11
-rw-r--r--src/di_container/blocking/mod.rs66
-rw-r--r--src/di_container/mod.rs33
-rw-r--r--src/errors/di_container.rs4
-rw-r--r--src/test_utils.rs9
7 files changed, 194 insertions, 48 deletions
diff --git a/macros/src/injectable/implementation.rs b/macros/src/injectable/implementation.rs
index bf168a4..9e97f45 100644
--- a/macros/src/injectable/implementation.rs
+++ b/macros/src/injectable/implementation.rs
@@ -420,14 +420,18 @@ impl<Dep: IDependency> InjectableImpl<Dep>
let method_call = parse_str::<ExprMethodCall>(
format!(
- "{}.get_bound::<{}>({}.clone(), {})",
+ concat!(
+ "{}.get_bound::<{}>({}.clone(), ",
+ "syrette::di_container::BindingOptions::new(){})"
+ ),
DI_CONTAINER_VAR_NAME,
dep_interface_str,
DEPENDENCY_HISTORY_VAR_NAME,
- dependency.get_name().as_ref().map_or_else(
- || "None".to_string(),
- |name| format!("Some(\"{}\")", name.value())
- )
+ dependency
+ .get_name()
+ .as_ref()
+ .map(|name| format!(".name(\"{}\")", name.value()))
+ .unwrap_or_default()
)
.as_str(),
)?;
@@ -900,7 +904,10 @@ mod tests
parse2::<Expr>(output)?,
parse2::<Expr>(quote! {
#di_container_var_ident
- .get_bound::<Foo>(#dep_history_var_ident.clone(), None)
+ .get_bound::<Foo>(
+ #dep_history_var_ident.clone(),
+ syrette::di_container::BindingOptions::new()
+ )
.map_err(|err| InjectableError::ResolveFailed {
reason: Box::new(err),
affected: self_type_name
@@ -948,7 +955,10 @@ mod tests
parse2::<Expr>(output)?,
parse2::<Expr>(quote! {
#di_container_var_ident
- .get_bound::<Foo>(#dep_history_var_ident.clone(), Some("special"))
+ .get_bound::<Foo>(
+ #dep_history_var_ident.clone(),
+ syrette::di_container::BindingOptions::new().name("special")
+ )
.map_err(|err| InjectableError::ResolveFailed {
reason: Box::new(err),
affected: self_type_name
@@ -994,7 +1004,10 @@ mod tests
parse2::<Expr>(output)?,
parse2::<Expr>(quote! {
#di_container_var_ident
- .get_bound::<Foo>(#dep_history_var_ident.clone(), None)
+ .get_bound::<Foo>(
+ #dep_history_var_ident.clone(),
+ syrette::di_container::BindingOptions::new()
+ )
.await
.map_err(|err| InjectableError::AsyncResolveFailed {
reason: Box::new(err),
@@ -1044,7 +1057,10 @@ mod tests
parse2::<Expr>(output)?,
parse2::<Expr>(quote! {
#di_container_var_ident
- .get_bound::<Foo>(#dep_history_var_ident.clone(), Some("foobar"))
+ .get_bound::<Foo>(
+ #dep_history_var_ident.clone(),
+ syrette::di_container::BindingOptions::new().name("foobar")
+ )
.await
.map_err(|err| InjectableError::AsyncResolveFailed {
reason: Box::new(err),
diff --git a/src/di_container/asynchronous/mod.rs b/src/di_container/asynchronous/mod.rs
index 2939ddd..e5f7f5d 100644
--- a/src/di_container/asynchronous/mod.rs
+++ b/src/di_container/asynchronous/mod.rs
@@ -59,6 +59,7 @@ use async_trait::async_trait;
use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder;
use crate::di_container::binding_storage::DIContainerBindingStorage;
+use crate::di_container::BindingOptions;
use crate::errors::async_di_container::AsyncDIContainerError;
use crate::future::BoxFuture;
use crate::private::cast::arc::CastArc;
@@ -116,14 +117,50 @@ pub trait IAsyncDIContainer:
'a: 'b,
Self: 'b;
- #[doc(hidden)]
- async fn get_bound<Interface>(
- self: &Arc<Self>,
+ /// 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
+ /// ```
+ /// # use syrette::di_container::asynchronous::AsyncDIContainer;
+ /// # use syrette::di_container::asynchronous::IAsyncDIContainer;
+ /// # use syrette::dependency_history::DependencyHistory;
+ /// # use syrette::di_container::BindingOptions;
+ /// #
+ /// # struct EventHandler {}
+ /// # struct Button {}
+ /// #
+ /// # Box::pin(async {
+ /// # let di_container = AsyncDIContainer::new();
+ /// #
+ /// let mut dependency_history = DependencyHistory::new();
+ ///
+ /// dependency_history.push::<EventHandler>();
+ ///
+ /// di_container
+ /// .get_bound::<Button>(dependency_history, BindingOptions::new().name("huge"))
+ /// .await?;
+ /// #
+ /// # Ok::<_, Box<dyn std::error::Error>>(())
+ /// # });
+ /// ```
+ fn get_bound<'this, 'fut, Interface>(
+ self: &'this Arc<Self>,
dependency_history: DependencyHistory,
- name: Option<&'static str>,
- ) -> Result<SomePtr<Interface>, AsyncDIContainerError>
+ binding_options: BindingOptions<'static>,
+ ) -> BoxFuture<'fut, Result<SomePtr<Interface>, AsyncDIContainerError>>
where
- Interface: 'static + ?Sized + Send + Sync;
+ Interface: 'static + 'this + ?Sized + Send + Sync,
+ 'this: 'fut,
+ Self: 'fut;
}
/// Async dependency injection container.
@@ -163,7 +200,7 @@ impl IAsyncDIContainer for AsyncDIContainer
Self: 'b,
{
Box::pin(async {
- self.get_bound::<Interface>(DependencyHistory::new(), None)
+ self.get_bound::<Interface>(DependencyHistory::new(), BindingOptions::new())
.await
})
}
@@ -178,24 +215,34 @@ impl IAsyncDIContainer for AsyncDIContainer
Self: 'b,
{
Box::pin(async {
- self.get_bound::<Interface>(DependencyHistory::new(), Some(name))
- .await
+ self.get_bound::<Interface>(
+ DependencyHistory::new(),
+ BindingOptions::new().name(name),
+ )
+ .await
})
}
- async fn get_bound<Interface>(
- self: &Arc<Self>,
+ fn get_bound<'this, 'fut, Interface>(
+ self: &'this Arc<Self>,
dependency_history: DependencyHistory,
- name: Option<&'static str>,
- ) -> Result<SomePtr<Interface>, AsyncDIContainerError>
+ binding_options: BindingOptions<'static>,
+ ) -> BoxFuture<'fut, Result<SomePtr<Interface>, AsyncDIContainerError>>
where
- Interface: 'static + ?Sized + Send + Sync,
+ Interface: 'static + 'this + ?Sized + Send + Sync,
+ 'this: 'fut,
+ Self: 'fut,
{
- let binding_providable = self
- .get_binding_providable::<Interface>(name, dependency_history)
- .await?;
-
- self.handle_binding_providable(binding_providable).await
+ Box::pin(async move {
+ let binding_providable = self
+ .get_binding_providable::<Interface>(
+ binding_options.name,
+ dependency_history,
+ )
+ .await?;
+
+ self.handle_binding_providable(binding_providable).await
+ })
}
}
diff --git a/src/di_container/binding_storage.rs b/src/di_container/binding_storage.rs
index 2bc208f..3c3c565 100644
--- a/src/di_container/binding_storage.rs
+++ b/src/di_container/binding_storage.rs
@@ -6,7 +6,7 @@ pub struct DIContainerBindingStorage<Provider>
where
Provider: 'static + ?Sized,
{
- inner: AHashMap<BindingIdentification, Box<Provider>>,
+ inner: AHashMap<BindingIdentification<'static>, Box<Provider>>,
}
impl<Provider> DIContainerBindingStorage<Provider>
@@ -21,7 +21,10 @@ where
}
#[allow(clippy::borrowed_box)]
- pub fn get<Interface>(&self, name: Option<&'static str>) -> Option<&Box<Provider>>
+ pub fn get<'me, Interface>(
+ &'me self,
+ name: Option<&'me str>,
+ ) -> Option<&'me Box<Provider>>
where
Interface: 'static + ?Sized,
{
@@ -77,10 +80,10 @@ where
}
#[derive(Debug, PartialEq, Eq, Hash)]
-struct BindingIdentification
+struct BindingIdentification<'a>
{
type_id: TypeId,
- name: Option<&'static str>,
+ name: Option<&'a str>,
}
#[cfg(test)]
diff --git a/src/di_container/blocking/mod.rs b/src/di_container/blocking/mod.rs
index 5a27f78..5b0acc8 100644
--- a/src/di_container/blocking/mod.rs
+++ b/src/di_container/blocking/mod.rs
@@ -56,6 +56,7 @@ use std::rc::Rc;
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;
@@ -103,16 +104,57 @@ pub trait IDIContainer: Sized + 'static + details::DIContainerInternals
where
Interface: 'static + ?Sized;
- #[doc(hidden)]
+ /// 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::di_container::blocking::IDIContainer;
+ /// # 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(())
+ /// # }
+ /// ```
fn get_bound<Interface>(
self: &Rc<Self>,
dependency_history: DependencyHistory,
- name: Option<&'static str>,
+ binding_options: BindingOptionsWithLt,
) -> Result<SomePtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized;
}
+#[cfg(not(test))]
+pub(crate) type BindingOptionsWithLt<'a> = BindingOptions<'a>;
+
+#[cfg(test)]
+pub(crate) type BindingOptionsWithLt = BindingOptions<'static>;
+
/// Blocking dependency injection container.
pub struct DIContainer
{
@@ -144,7 +186,7 @@ impl IDIContainer for DIContainer
where
Interface: 'static + ?Sized,
{
- self.get_bound::<Interface>(DependencyHistory::new(), None)
+ self.get_bound::<Interface>(DependencyHistory::new(), BindingOptions::new())
}
fn get_named<Interface>(
@@ -154,20 +196,24 @@ impl IDIContainer for DIContainer
where
Interface: 'static + ?Sized,
{
- self.get_bound::<Interface>(DependencyHistory::new(), Some(name))
+ self.get_bound::<Interface>(
+ DependencyHistory::new(),
+ BindingOptions::new().name(name),
+ )
}
- #[doc(hidden)]
fn get_bound<Interface>(
self: &Rc<Self>,
dependency_history: DependencyHistory,
- name: Option<&'static str>,
+ binding_options: BindingOptions,
) -> Result<SomePtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
- let binding_providable =
- self.get_binding_providable::<Interface>(name, dependency_history)?;
+ let binding_providable = self.get_binding_providable::<Interface>(
+ binding_options.name,
+ dependency_history,
+ )?;
#[cfg(feature = "factory")]
return self.handle_binding_providable(binding_providable);
@@ -270,7 +316,7 @@ impl DIContainer
fn get_binding_providable<Interface>(
self: &Rc<Self>,
- name: Option<&'static str>,
+ name: Option<&str>,
dependency_history: DependencyHistory,
) -> Result<Providable<Self>, DIContainerError>
where
@@ -283,7 +329,7 @@ impl DIContainer
|| {
Err(DIContainerError::BindingNotFound {
interface: type_name::<Interface>(),
- name,
+ name: name.as_ref().map(ToString::to_string),
})
},
Ok,
diff --git a/src/di_container/mod.rs b/src/di_container/mod.rs
index 5820bc8..63733f5 100644
--- a/src/di_container/mod.rs
+++ b/src/di_container/mod.rs
@@ -6,5 +6,38 @@ pub mod asynchronous;
pub mod blocking;
+/// DI container binding options.
+///
+/// # Examples
+/// ```
+/// # use syrette::di_container::BindingOptions;
+/// #
+/// BindingOptions::new().name("foo");
+/// ```
+#[derive(Debug, Default, Clone)]
+pub struct BindingOptions<'a>
+{
+ name: Option<&'a str>,
+}
+
+impl<'a> BindingOptions<'a>
+{
+ /// Returns a new `BindingOptions`.
+ #[must_use]
+ pub fn new() -> Self
+ {
+ Self { name: None }
+ }
+
+ /// Returns `Self` with the specified name set.
+ #[must_use]
+ pub fn name(mut self, name: &'a str) -> Self
+ {
+ self.name = Some(name);
+
+ self
+ }
+}
+
// Private.
pub(crate) mod binding_storage;
diff --git a/src/errors/di_container.rs b/src/errors/di_container.rs
index 311917a..7e29ffa 100644
--- a/src/errors/di_container.rs
+++ b/src/errors/di_container.rs
@@ -38,7 +38,7 @@ pub enum DIContainerError
/// No binding exists for a interface (and optionally a name).
#[error(
"No binding exists for interface '{interface}' {}",
- .name.map_or_else(String::new, |name| format!("with name '{name}'"))
+ name.as_ref().map(|name| format!("with name '{name}'")).unwrap_or_default()
)]
BindingNotFound
{
@@ -46,7 +46,7 @@ pub enum DIContainerError
interface: &'static str,
/// The name of the binding if one exists.
- name: Option<&'static str>,
+ name: Option<String>,
},
}
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 1fe4417..1e0e04d 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -288,7 +288,7 @@ pub mod mocks
use super::*;
use crate::di_container::blocking::binding::builder::BindingBuilder;
use crate::di_container::blocking::details::DIContainerInternals;
- use crate::di_container::blocking::IDIContainer;
+ use crate::di_container::blocking::{BindingOptionsWithLt, IDIContainer};
use crate::errors::di_container::DIContainerError;
use crate::provider::blocking::IProvider;
use crate::ptr::SomePtr;
@@ -317,10 +317,10 @@ pub mod mocks
Interface: 'static + ?Sized;
#[doc(hidden)]
- fn get_bound<Interface>(
+ fn get_bound<'opts, Interface>(
self: &Rc<Self>,
dependency_history: DependencyHistory,
- name: Option<&'static str>,
+ binding_options: BindingOptionsWithLt,
) -> Result<SomePtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized;
@@ -359,6 +359,7 @@ pub mod mocks
use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder;
use crate::di_container::asynchronous::details::DIContainerInternals;
use crate::di_container::asynchronous::IAsyncDIContainer;
+ use crate::di_container::BindingOptions;
use crate::errors::async_di_container::AsyncDIContainerError;
use crate::provider::r#async::IAsyncProvider;
use crate::ptr::SomePtr;
@@ -394,7 +395,7 @@ pub mod mocks
async fn get_bound<Interface>(
self: &Arc<Self>,
dependency_history: DependencyHistory,
- name: Option<&'static str>,
+ binding_options: BindingOptions<'static>
) -> Result<SomePtr<Interface>, AsyncDIContainerError>
where
Interface: 'static + ?Sized + Send + Sync;