aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-07-22 13:25:45 +0200
committerHampusM <hampus@hampusmat.com>2022-07-22 13:25:45 +0200
commit4cb3884e24b3cba3347ff93475bbabd6fe18d2fa (patch)
tree2fa5e6d81de9dc39bd11d64797914e5d305d98e2
parent157f38bc2287dcb9a8b21ef3d5e33c569dc5136e (diff)
refactor: make factories an optional feature
-rw-r--r--Cargo.toml7
-rw-r--r--README.md9
-rw-r--r--examples/basic/animals/cow.rs24
-rw-r--r--examples/basic/animals/human.rs20
-rw-r--r--examples/basic/animals/mod.rs1
-rw-r--r--examples/basic/bootstrap.rs7
-rw-r--r--examples/basic/interfaces/cow.rs10
-rw-r--r--examples/basic/interfaces/mod.rs1
-rw-r--r--examples/factory/bootstrap.rs24
-rw-r--r--examples/factory/interfaces/mod.rs1
-rw-r--r--examples/factory/interfaces/user.rs13
-rw-r--r--examples/factory/main.rs47
-rw-r--r--examples/factory/user.rs42
-rw-r--r--macros/src/lib.rs5
-rw-r--r--src/castable_factory.rs4
-rw-r--r--src/di_container.rs21
-rw-r--r--src/interfaces/any_factory.rs3
-rw-r--r--src/interfaces/mod.rs5
-rw-r--r--src/lib.rs6
-rw-r--r--src/provider.rs6
20 files changed, 175 insertions, 81 deletions
diff --git a/Cargo.toml b/Cargo.toml
index a202540..d4a4312 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,13 @@ repository = "https://git.hampusmat.com/syrette"
keywords = ["DI", "dependency-injection", "ioc", "inversion-of-control"]
edition = "2021"
+[features]
+factory = []
+
+[[example]]
+name = "factory"
+required-features = ["factory"]
+
[dependencies]
syrette_macros = { path = "./macros", version = "0.1.0" }
linkme = "0.3.0"
diff --git a/README.md b/README.md
index 34358cf..94eb526 100644
--- a/README.md
+++ b/README.md
@@ -13,11 +13,15 @@ From the [syrette Wikipedia article](https://en.wikipedia.org/wiki/Syrette).
## Features
- A [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) container
- Autowiring dependencies
-- Binding factories
- API inspired from the one of [InversifyJS](https://github.com/inversify/InversifyJS)
- Helpful error messages
- Enforces the use of interface traits
+## Optional features
+- Binding factories (Rust nightly required)
+
+To use these features, you must [enable it in Cargo](https://doc.rust-lang.org/cargo/reference/features.html#dependency-features).
+
## Motivation
Other DI libraries for Rust are either unmaintained ([di](https://crates.io/crates/di) for example),
overcomplicated and or bloated ([anthill-di](https://crates.io/crates/anthill-di) for example)
@@ -25,9 +29,6 @@ or has a weird API ([teloc](https://crates.io/crates/teloc) for example).
The goal of Syrette is to be a simple, useful, convenient and familiar DI library.
-## Notice
-Rust nightly is currently required.
-
## Example usage
```rust
use syrette::{injectable, DIContainer};
diff --git a/examples/basic/animals/cow.rs b/examples/basic/animals/cow.rs
deleted file mode 100644
index a75d750..0000000
--- a/examples/basic/animals/cow.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use crate::interfaces::cow::ICow;
-
-pub struct Cow
-{
- moo_cnt: i32,
-}
-
-impl Cow
-{
- pub fn new(moo_cnt: i32) -> Self
- {
- Self { moo_cnt }
- }
-}
-
-impl ICow for Cow
-{
- fn moo(&self)
- {
- for _ in 0..self.moo_cnt {
- println!("Moo");
- }
- }
-}
diff --git a/examples/basic/animals/human.rs b/examples/basic/animals/human.rs
index 5bd2f8f..00574a3 100644
--- a/examples/basic/animals/human.rs
+++ b/examples/basic/animals/human.rs
@@ -1,8 +1,7 @@
use syrette::injectable;
-use syrette::ptr::{FactoryPtr, InterfacePtr};
+use syrette::ptr::InterfacePtr;
use crate::interfaces::cat::ICat;
-use crate::interfaces::cow::{CowFactory, ICow};
use crate::interfaces::dog::IDog;
use crate::interfaces::human::IHuman;
@@ -10,23 +9,14 @@ pub struct Human
{
dog: InterfacePtr<dyn IDog>,
cat: InterfacePtr<dyn ICat>,
- cow_factory: FactoryPtr<CowFactory>,
}
#[injectable(IHuman)]
impl Human
{
- pub fn new(
- dog: InterfacePtr<dyn IDog>,
- cat: InterfacePtr<dyn ICat>,
- cow_factory: FactoryPtr<CowFactory>,
- ) -> Self
+ pub fn new(dog: InterfacePtr<dyn IDog>, cat: InterfacePtr<dyn ICat>) -> Self
{
- Self {
- dog,
- cat,
- cow_factory,
- }
+ Self { dog, cat }
}
}
@@ -41,9 +31,5 @@ impl IHuman for Human
println!("Hi kitty!");
self.cat.meow();
-
- let cow: Box<dyn ICow> = (self.cow_factory)(3);
-
- cow.moo();
}
}
diff --git a/examples/basic/animals/mod.rs b/examples/basic/animals/mod.rs
index 6511d17..5444978 100644
--- a/examples/basic/animals/mod.rs
+++ b/examples/basic/animals/mod.rs
@@ -1,4 +1,3 @@
pub mod cat;
-pub mod cow;
pub mod dog;
pub mod human;
diff --git a/examples/basic/bootstrap.rs b/examples/basic/bootstrap.rs
index a1a7b05..71ef713 100644
--- a/examples/basic/bootstrap.rs
+++ b/examples/basic/bootstrap.rs
@@ -2,13 +2,11 @@ use syrette::DIContainer;
// Concrete implementations
use crate::animals::cat::Cat;
-use crate::animals::cow::Cow;
use crate::animals::dog::Dog;
use crate::animals::human::Human;
//
// Interfaces
use crate::interfaces::cat::ICat;
-use crate::interfaces::cow::{CowFactory, ICow};
use crate::interfaces::dog::IDog;
use crate::interfaces::human::IHuman;
@@ -20,10 +18,5 @@ pub fn bootstrap() -> DIContainer
di_container.bind::<dyn ICat>().to::<Cat>();
di_container.bind::<dyn IHuman>().to::<Human>();
- di_container.bind::<CowFactory>().to_factory(&|moo_cnt| {
- let cow: Box<dyn ICow> = Box::new(Cow::new(moo_cnt));
- cow
- });
-
di_container
}
diff --git a/examples/basic/interfaces/cow.rs b/examples/basic/interfaces/cow.rs
deleted file mode 100644
index 59ce7b1..0000000
--- a/examples/basic/interfaces/cow.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use syrette::factory;
-use syrette::interfaces::factory::IFactory;
-
-pub trait ICow
-{
- fn moo(&self);
-}
-
-#[factory]
-pub type CowFactory = dyn IFactory<(i32,), dyn ICow>;
diff --git a/examples/basic/interfaces/mod.rs b/examples/basic/interfaces/mod.rs
index 6511d17..5444978 100644
--- a/examples/basic/interfaces/mod.rs
+++ b/examples/basic/interfaces/mod.rs
@@ -1,4 +1,3 @@
pub mod cat;
-pub mod cow;
pub mod dog;
pub mod human;
diff --git a/examples/factory/bootstrap.rs b/examples/factory/bootstrap.rs
new file mode 100644
index 0000000..5086b1a
--- /dev/null
+++ b/examples/factory/bootstrap.rs
@@ -0,0 +1,24 @@
+use syrette::ptr::InterfacePtr;
+use syrette::DIContainer;
+
+// Interfaces
+use crate::interfaces::user::{IUser, IUserFactory};
+//
+// Concrete implementations
+use crate::user::User;
+
+pub fn bootstrap() -> DIContainer
+{
+ let mut di_container: DIContainer = DIContainer::new();
+
+ di_container
+ .bind::<IUserFactory>()
+ .to_factory(&|name, date_of_birth, password| {
+ let user: InterfacePtr<dyn IUser> =
+ InterfacePtr::new(User::new(name, date_of_birth, password));
+
+ user
+ });
+
+ di_container
+}
diff --git a/examples/factory/interfaces/mod.rs b/examples/factory/interfaces/mod.rs
new file mode 100644
index 0000000..22d12a3
--- /dev/null
+++ b/examples/factory/interfaces/mod.rs
@@ -0,0 +1 @@
+pub mod user;
diff --git a/examples/factory/interfaces/user.rs b/examples/factory/interfaces/user.rs
new file mode 100644
index 0000000..70cd632
--- /dev/null
+++ b/examples/factory/interfaces/user.rs
@@ -0,0 +1,13 @@
+use syrette::factory;
+use syrette::interfaces::factory::IFactory;
+
+pub trait IUser
+{
+ fn get_name(&self) -> &'static str;
+ fn get_date_of_birth(&self) -> &'static str;
+ fn get_password(&self) -> &'static str;
+}
+
+#[factory]
+pub type IUserFactory =
+ dyn IFactory<(&'static str, &'static str, &'static str), dyn IUser>;
diff --git a/examples/factory/main.rs b/examples/factory/main.rs
new file mode 100644
index 0000000..c659f3e
--- /dev/null
+++ b/examples/factory/main.rs
@@ -0,0 +1,47 @@
+#![deny(clippy::all)]
+#![deny(clippy::pedantic)]
+#![allow(clippy::module_name_repetitions)]
+
+mod bootstrap;
+mod interfaces;
+mod user;
+
+use bootstrap::bootstrap;
+use interfaces::user::IUser;
+use interfaces::user::IUserFactory;
+use syrette::ptr::FactoryPtr;
+use syrette::ptr::InterfacePtr;
+
+fn add_users(
+ users: &mut Vec<InterfacePtr<dyn IUser>>,
+ user_factory: &FactoryPtr<IUserFactory>,
+)
+{
+ users.push(user_factory("Bob", "1983-04-13", "abc1234"));
+ users.push(user_factory("Anna", "1998-01-20", "IlovemYCat"));
+ users.push(user_factory("David", "2000-11-05", "12345678"));
+}
+
+fn main()
+{
+ println!("Hello, world!");
+
+ let di_container = bootstrap();
+
+ let user_factory = di_container.get_factory::<IUserFactory>().unwrap();
+
+ let mut users = Vec::<InterfacePtr<dyn IUser>>::new();
+
+ add_users(&mut users, &user_factory);
+
+ println!("Printing user information");
+
+ for user in users {
+ println!(
+ "{}, born {}, password is '{}'",
+ user.get_name(),
+ user.get_date_of_birth(),
+ user.get_password()
+ );
+ }
+}
diff --git a/examples/factory/user.rs b/examples/factory/user.rs
new file mode 100644
index 0000000..121ad25
--- /dev/null
+++ b/examples/factory/user.rs
@@ -0,0 +1,42 @@
+use crate::interfaces::user::IUser;
+
+pub struct User
+{
+ name: &'static str,
+ date_of_birth: &'static str,
+ password: &'static str,
+}
+
+impl User
+{
+ pub fn new(
+ name: &'static str,
+ date_of_birth: &'static str,
+ password: &'static str,
+ ) -> Self
+ {
+ Self {
+ name,
+ date_of_birth,
+ password,
+ }
+ }
+}
+
+impl IUser for User
+{
+ fn get_name(&self) -> &'static str
+ {
+ self.name.clone()
+ }
+
+ fn get_date_of_birth(&self) -> &'static str
+ {
+ self.date_of_birth.clone()
+ }
+
+ fn get_password(&self) -> &'static str
+ {
+ self.password.clone()
+ }
+}
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index ed1a509..73fb2dc 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -12,7 +12,6 @@ mod injectable_macro_args;
mod libs;
use declare_interface_args::DeclareInterfaceArgs;
-use factory_type_alias::FactoryTypeAlias;
use injectable_impl::InjectableImpl;
use injectable_macro_args::InjectableMacroArgs;
use libs::intertrait_macros::gen_caster::generate_caster;
@@ -52,7 +51,7 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
#[proc_macro_attribute]
pub fn factory(_: TokenStream, type_alias_stream: TokenStream) -> TokenStream
{
- let FactoryTypeAlias {
+ let factory_type_alias::FactoryTypeAlias {
type_alias,
factory_interface,
arg_types,
@@ -73,7 +72,7 @@ pub fn factory(_: TokenStream, type_alias_stream: TokenStream) -> TokenStream
syrette::castable_factory::CastableFactory<
#arg_types,
#return_type
- > -> syrette::castable_factory::AnyFactory
+ > -> syrette::interfaces::any_factory::AnyFactory
);
}
.into()
diff --git a/src/castable_factory.rs b/src/castable_factory.rs
index 5d582bb..c50456c 100644
--- a/src/castable_factory.rs
+++ b/src/castable_factory.rs
@@ -1,9 +1,7 @@
+use crate::interfaces::any_factory::AnyFactory;
use crate::interfaces::factory::IFactory;
-use crate::libs::intertrait::CastFrom;
use crate::ptr::InterfacePtr;
-pub trait AnyFactory: CastFrom {}
-
pub struct CastableFactory<Args, ReturnInterface>
where
Args: 'static,
diff --git a/src/di_container.rs b/src/di_container.rs
index 6982a10..ae6a851 100644
--- a/src/di_container.rs
+++ b/src/di_container.rs
@@ -5,14 +5,13 @@ use std::rc::Rc;
use error_stack::{Report, ResultExt};
+#[cfg(feature = "factory")]
use crate::castable_factory::CastableFactory;
use crate::errors::di_container::DIContainerError;
-use crate::interfaces::factory::IFactory;
use crate::interfaces::injectable::Injectable;
use crate::libs::intertrait::cast_box::CastBox;
-use crate::libs::intertrait::cast_rc::CastRc;
-use crate::provider::{FactoryProvider, IProvider, InjectableTypeProvider, Providable};
-use crate::ptr::{FactoryPtr, InterfacePtr};
+use crate::provider::{IProvider, InjectableTypeProvider, Providable};
+use crate::ptr::InterfacePtr;
/// Binding builder for type `Interface` inside a [`DIContainer`].
pub struct BindingBuilder<'di_container_lt, Interface>
@@ -51,13 +50,14 @@ where
/// Creates a binding of factory type `Interface` to a factory inside of the
/// associated [`DIContainer`].
+ #[cfg(feature = "factory")]
pub fn to_factory<Args, Return>(
&mut self,
factory_func: &'static dyn Fn<Args, Output = InterfacePtr<Return>>,
) where
Args: 'static,
Return: 'static + ?Sized,
- Interface: IFactory<Args, Return>,
+ Interface: crate::interfaces::factory::IFactory<Args, Return>,
{
let interface_typeid = TypeId::of::<Interface>();
@@ -65,7 +65,9 @@ where
self.di_container.bindings.insert(
interface_typeid,
- Rc::new(FactoryProvider::new(FactoryPtr::new(factory_impl))),
+ Rc::new(crate::provider::FactoryProvider::new(
+ crate::ptr::FactoryPtr::new(factory_impl),
+ )),
);
}
}
@@ -197,9 +199,10 @@ impl DIContainer
/// - Resolving the binding for `Interface` fails
/// - Casting the binding for `Interface` fails
/// - The binding for `Interface` is not a factory
+ #[cfg(feature = "factory")]
pub fn get_factory<Interface>(
&self,
- ) -> error_stack::Result<FactoryPtr<Interface>, DIContainerError>
+ ) -> error_stack::Result<crate::ptr::FactoryPtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -222,6 +225,8 @@ impl DIContainer
match binding_providable {
Providable::Factory(binding_factory) => {
+ use crate::libs::intertrait::cast_rc::CastRc;
+
let factory_box_result = binding_factory.cast::<Interface>();
match factory_box_result {
@@ -306,6 +311,7 @@ mod tests
}
#[test]
+ #[cfg(feature = "factory")]
fn can_bind_to_factory()
{
trait IUserManager
@@ -423,6 +429,7 @@ mod tests
}
#[test]
+ #[cfg(feature = "factory")]
fn can_get_factory() -> error_stack::Result<(), DIContainerError>
{
trait IUserManager
diff --git a/src/interfaces/any_factory.rs b/src/interfaces/any_factory.rs
new file mode 100644
index 0000000..41063e1
--- /dev/null
+++ b/src/interfaces/any_factory.rs
@@ -0,0 +1,3 @@
+use crate::libs::intertrait::CastFrom;
+
+pub trait AnyFactory: CastFrom {}
diff --git a/src/interfaces/mod.rs b/src/interfaces/mod.rs
index 921bb9c..497521e 100644
--- a/src/interfaces/mod.rs
+++ b/src/interfaces/mod.rs
@@ -1,2 +1,5 @@
-pub mod factory;
+pub mod any_factory;
pub mod injectable;
+
+#[cfg(feature = "factory")]
+pub mod factory;
diff --git a/src/lib.rs b/src/lib.rs
index 992f276..5724f10 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(unboxed_closures, fn_traits)]
+#![cfg_attr(feature = "factory", feature(unboxed_closures, fn_traits))]
#![deny(clippy::all)]
#![deny(clippy::pedantic)]
@@ -6,12 +6,14 @@
//!
//! Syrette is a collection of utilities useful for performing dependency injection.
-pub mod castable_factory;
pub mod di_container;
pub mod errors;
pub mod interfaces;
pub mod ptr;
+#[cfg(feature = "factory")]
+pub mod castable_factory;
+
pub use di_container::*;
pub use syrette_macros::*;
diff --git a/src/provider.rs b/src/provider.rs
index 3b7e04c..bd17474 100644
--- a/src/provider.rs
+++ b/src/provider.rs
@@ -1,8 +1,8 @@
#![allow(clippy::module_name_repetitions)]
use std::marker::PhantomData;
-use crate::castable_factory::AnyFactory;
use crate::errors::injectable::ResolveError;
+use crate::interfaces::any_factory::AnyFactory;
use crate::interfaces::injectable::Injectable;
use crate::ptr::{FactoryPtr, InterfacePtr};
use crate::DIContainer;
@@ -12,6 +12,7 @@ extern crate error_stack;
pub enum Providable
{
Injectable(InterfacePtr<dyn Injectable>),
+ #[allow(dead_code)]
Factory(FactoryPtr<dyn AnyFactory>),
}
@@ -57,11 +58,13 @@ where
}
}
+#[cfg(feature = "factory")]
pub struct FactoryProvider
{
factory: FactoryPtr<dyn AnyFactory>,
}
+#[cfg(feature = "factory")]
impl FactoryProvider
{
pub fn new(factory: FactoryPtr<dyn AnyFactory>) -> Self
@@ -70,6 +73,7 @@ impl FactoryProvider
}
}
+#[cfg(feature = "factory")]
impl IProvider for FactoryProvider
{
fn provide(