aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-08-20 17:08:58 +0200
committerHampusM <hampus@hampusmat.com>2022-08-21 18:17:50 +0200
commitb31422d48a600ccccb682567f5eb11fc0bca547c (patch)
treefe3618522478249ef56c955e870e6525053f8ffa /src
parentb749754dc1818a95e0baf0214b969fb99df4e7ab (diff)
feat: allow bind interface to default factory
This commit will allow interface traits to be bound to default factories. Default factories being factories that doesn't take any arguments
Diffstat (limited to 'src')
-rw-r--r--src/di_container.rs44
-rw-r--r--src/lib.rs67
2 files changed, 111 insertions, 0 deletions
diff --git a/src/di_container.rs b/src/di_container.rs
index eaa0366..84fb9e0 100644
--- a/src/di_container.rs
+++ b/src/di_container.rs
@@ -181,6 +181,39 @@ where
Ok(())
}
+
+ /// Creates a binding of type `Interface` to a factory that takes no arguments
+ /// inside of the associated [`DIContainer`].
+ ///
+ /// *This function is only available if Syrette is built with the "factory" feature.*
+ ///
+ /// # Errors
+ /// Will return Err if the associated [`DIContainer`] already have a binding for
+ /// the interface.
+ #[cfg(feature = "factory")]
+ pub fn to_default_factory<Return>(
+ &mut self,
+ factory_func: &'static dyn Fn<(), Output = TransientPtr<Return>>,
+ ) -> error_stack::Result<(), BindingBuilderError>
+ where
+ Return: 'static + ?Sized,
+ {
+ let factory_impl = CastableFactory::new(factory_func);
+
+ self.di_container
+ .bindings
+ .set::<Interface>(Box::new(crate::provider::FactoryProvider::new(
+ crate::ptr::FactoryPtr::new(factory_impl),
+ )))
+ .ok_or_else(|| {
+ report!(BindingBuilderError).attach_printable(format!(
+ "Binding already exists for interface '{}'",
+ type_name::<Interface>()
+ ))
+ })?;
+
+ Ok(())
+ }
}
/// Dependency injection container.
@@ -290,6 +323,17 @@ impl DIContainer
.map_err(unable_to_cast_binding::<Interface>);
}
+ #[cfg(feature = "factory")]
+ if let Providable::Factory(binding_factory) = binding_providable {
+ use crate::interfaces::factory::IFactory;
+
+ let factory = binding_factory
+ .cast::<dyn IFactory<(), Interface>>()
+ .map_err(unable_to_cast_binding::<Interface>)?;
+
+ return Ok(factory());
+ }
+
Err(report!(DIContainerError).attach_printable(format!(
"Binding for interface '{}' is not transient",
type_name::<Interface>()
diff --git a/src/lib.rs b/src/lib.rs
index 89688f1..78506bc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,3 +45,70 @@ macro_rules! di_container_bind {
syrette::declare_interface!($implementation -> $interface);
};
}
+
+/// Shortcut for declaring a default factory.
+///
+/// A default factory is a factory that doesn't take any arguments.
+///
+/// More tedious ways to accomplish what this macro does would either be by using
+/// the [`factory`] macro or by manually declaring the interfaces
+/// with the [`declare_interface`] macro.
+///
+/// *This macro is only available if Syrette is built with the "factory" feature.*
+///
+/// # Arguments
+/// - Interface trait
+///
+/// # Examples
+/// ```
+/// use syrette::declare_default_factory;
+///
+/// trait IParser {
+/// // Methods and etc here...
+/// }
+///
+/// declare_default_factory!(IParser);
+/// ```
+///
+/// The expanded equivelent of this would be
+///
+/// ```
+/// use syrette::declare_default_factory;
+///
+/// trait IParser {
+/// // Methods and etc here...
+/// }
+///
+/// syrette::declare_interface!(
+/// syrette::castable_factory::CastableFactory<
+/// (),
+/// dyn IParser,
+/// > -> syrette::interfaces::factory::IFactory<(), dyn IParser>
+/// );
+///
+/// syrette::declare_interface!(
+/// syrette::castable_factory::CastableFactory<
+/// (),
+/// dyn IParser,
+/// > -> syrette::interfaces::any_factory::AnyFactory
+/// );
+/// ```
+#[macro_export]
+#[cfg(feature = "factory")]
+macro_rules! declare_default_factory {
+ ($interface: path) => {
+ syrette::declare_interface!(
+ syrette::castable_factory::CastableFactory<
+ (),
+ dyn $interface,
+ > -> syrette::interfaces::factory::IFactory<(), dyn $interface>
+ );
+
+ syrette::declare_interface!(
+ syrette::castable_factory::CastableFactory<
+ (),
+ dyn $interface,
+ > -> syrette::interfaces::any_factory::AnyFactory
+ );
+ }
+}