aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
+ );
+ }
+}