diff options
-rw-r--r-- | Cargo.lock | 41 | ||||
-rw-r--r-- | Cargo.toml | 8 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | examples/async-factory/main.rs | 2 | ||||
-rw-r--r-- | examples/async/animals.rs (renamed from examples/async/animals/mod.rs) | 0 | ||||
-rw-r--r-- | examples/async/bootstrap.rs | 2 | ||||
-rw-r--r-- | examples/async/interfaces.rs (renamed from examples/async/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | examples/basic/animals.rs (renamed from examples/basic/animals/mod.rs) | 0 | ||||
-rw-r--r-- | examples/basic/interfaces.rs (renamed from examples/basic/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | examples/factory/interfaces.rs (renamed from examples/factory/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | examples/generics/interfaces.rs (renamed from examples/generics/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | examples/named/interfaces.rs (renamed from examples/named/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | examples/with-3rd-party/bootstrap.rs | 2 | ||||
-rw-r--r-- | examples/with-3rd-party/interfaces.rs (renamed from examples/with-3rd-party/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | macros/Cargo.toml | 9 | ||||
-rw-r--r-- | macros/src/injectable.rs (renamed from macros/src/injectable/mod.rs) | 0 | ||||
-rw-r--r-- | macros/src/injectable/dependency.rs | 35 | ||||
-rw-r--r-- | macros/src/injectable/implementation.rs | 57 | ||||
-rw-r--r-- | macros/src/lib.rs | 4 | ||||
-rw-r--r-- | macros/src/util.rs | 67 | ||||
-rw-r--r-- | macros/src/util/error.rs | 48 | ||||
-rw-r--r-- | macros/src/util/mod.rs | 29 | ||||
-rw-r--r-- | src/any_factory.rs | 13 | ||||
-rw-r--r-- | src/castable_function.rs (renamed from src/castable_factory/mod.rs) | 23 | ||||
-rw-r--r-- | src/castable_function/threadsafe.rs (renamed from src/castable_factory/threadsafe.rs) | 30 | ||||
-rw-r--r-- | src/di_container.rs (renamed from src/di_container/mod.rs) | 0 | ||||
-rw-r--r-- | src/di_container/asynchronous.rs (renamed from src/di_container/asynchronous/mod.rs) | 84 | ||||
-rw-r--r-- | src/di_container/asynchronous/binding.rs (renamed from src/di_container/asynchronous/binding/mod.rs) | 0 | ||||
-rw-r--r-- | src/di_container/asynchronous/binding/builder.rs | 100 | ||||
-rw-r--r-- | src/di_container/blocking.rs (renamed from src/di_container/blocking/mod.rs) | 56 | ||||
-rw-r--r-- | src/di_container/blocking/binding.rs (renamed from src/di_container/blocking/binding/mod.rs) | 0 | ||||
-rw-r--r-- | src/di_container/blocking/binding/builder.rs | 55 | ||||
-rw-r--r-- | src/errors.rs (renamed from src/errors/mod.rs) | 0 | ||||
-rw-r--r-- | src/interfaces.rs (renamed from src/interfaces/mod.rs) | 0 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/private.rs (renamed from src/private/mod.rs) | 0 | ||||
-rw-r--r-- | src/private/cast.rs (renamed from src/private/cast/mod.rs) | 0 | ||||
-rw-r--r-- | src/provider.rs (renamed from src/provider/mod.rs) | 0 | ||||
-rw-r--r-- | src/provider/async.rs | 136 | ||||
-rw-r--r-- | src/provider/blocking.rs | 74 | ||||
-rw-r--r-- | src/test_utils.rs | 4 |
41 files changed, 453 insertions, 447 deletions
@@ -19,13 +19,15 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ + "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -51,7 +53,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.32", ] [[package]] @@ -196,7 +198,7 @@ checksum = "1d5adefdb2c04ca9173223070228ff26a04667003619257b8442f192d9986218" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.32", ] [[package]] @@ -485,9 +487,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -519,6 +521,7 @@ version = "0.5.1" dependencies = [ "mockall", "once_cell", + "paste", "pretty_assertions", "proc-macro-error", "proc-macro2", @@ -559,7 +562,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.32", ] [[package]] @@ -593,7 +596,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.32", ] [[package]] @@ -616,7 +619,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.32", ] [[package]] @@ -723,3 +726,23 @@ name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] @@ -40,14 +40,14 @@ required-features = ["async", "factory"] syrette_macros = { path = "./macros", version = "0.5.1" } linkme = "0.3.0" once_cell = "1.4" -ahash = "0.7.6" +ahash = "0.8.11" thiserror = "1.0.32" strum = "0.24.1" strum_macros = "0.24.3" paste = "1.0.8" async-trait = { version = "0.1.57", optional = true } -[dev_dependencies] +[dev-dependencies] mockall = "0.11.4" anyhow = "1.0.62" third-party-lib = { path = "./examples/with-3rd-party/third-party-lib" } @@ -59,3 +59,7 @@ members = [ "examples/with-3rd-party/third-party-lib", ] +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ["cfg(doc_cfg)", "cfg(tarpaulin_include)"] + @@ -7,6 +7,18 @@ The convenient dependency injection & inversion of control framework for Rust. +<div class="warning"> + +Currently, This crate does not work on nightly versions of Rust. This is because Nightly +versions uses rust-lld. See [Linkme issue #94](https://github.com/dtolnay/linkme/issues/94). + +A temporary fix for this is to build with `RUSTFLAGS="-C link-args=-znostart-stop-gc"` +</div> + +## Changelog +You can find out what changes have been made in various versions +[here](https://github.com/HampusMat/Syrette/blob/master/CHANGELOG.md). + ## Namesake From the [syrette Wikipedia article](https://en.wikipedia.org/wiki/Syrette). > A syrette is a device for injecting liquid through a needle. @@ -178,9 +190,6 @@ A type or trait that represents a type (itself in the case of it being a type). **Factory**<br> A function that creates new instances of a specific type or trait. -**Default factory**<br> -A function that takes no arguments that creates new instances of a specific type or trait. - ## Rust version requirements Syrette requires Rust >= 1.62.1 to work. This is mainly due to the dependency on [Linkme](https://crates.io/crates/linkme). diff --git a/examples/async-factory/main.rs b/examples/async-factory/main.rs index 2b796cc..795e50c 100644 --- a/examples/async-factory/main.rs +++ b/examples/async-factory/main.rs @@ -84,7 +84,7 @@ async fn main() -> Result<()> di_container .bind::<dyn IPerson>() - .to_async_default_factory(&|_| { + .to_async_dynamic_value(&|_| { Box::new(|| { Box::pin(async { // Do some time demanding thing... diff --git a/examples/async/animals/mod.rs b/examples/async/animals.rs index 5444978..5444978 100644 --- a/examples/async/animals/mod.rs +++ b/examples/async/animals.rs diff --git a/examples/async/bootstrap.rs b/examples/async/bootstrap.rs index 07e1bf8..5abeac7 100644 --- a/examples/async/bootstrap.rs +++ b/examples/async/bootstrap.rs @@ -20,7 +20,7 @@ pub async fn bootstrap() -> Result<AsyncDIContainer, anyhow::Error> .in_singleton_scope() .await?; - di_container.bind::<dyn ICat>().to_default_factory(&|_| { + di_container.bind::<dyn ICat>().to_dynamic_value(&|_| { Box::new(|| { let cat: TransientPtr<dyn ICat> = TransientPtr::new(Cat::new()); diff --git a/examples/async/interfaces/mod.rs b/examples/async/interfaces.rs index ea0a26d..ea0a26d 100644 --- a/examples/async/interfaces/mod.rs +++ b/examples/async/interfaces.rs diff --git a/examples/basic/animals/mod.rs b/examples/basic/animals.rs index 5444978..5444978 100644 --- a/examples/basic/animals/mod.rs +++ b/examples/basic/animals.rs diff --git a/examples/basic/interfaces/mod.rs b/examples/basic/interfaces.rs index 5444978..5444978 100644 --- a/examples/basic/interfaces/mod.rs +++ b/examples/basic/interfaces.rs diff --git a/examples/factory/interfaces/mod.rs b/examples/factory/interfaces.rs index 2342750..2342750 100644 --- a/examples/factory/interfaces/mod.rs +++ b/examples/factory/interfaces.rs diff --git a/examples/generics/interfaces/mod.rs b/examples/generics/interfaces.rs index 3f31bdf..3f31bdf 100644 --- a/examples/generics/interfaces/mod.rs +++ b/examples/generics/interfaces.rs diff --git a/examples/named/interfaces/mod.rs b/examples/named/interfaces.rs index 6a0108d..6a0108d 100644 --- a/examples/named/interfaces/mod.rs +++ b/examples/named/interfaces.rs diff --git a/examples/with-3rd-party/bootstrap.rs b/examples/with-3rd-party/bootstrap.rs index 26386f5..5d2f713 100644 --- a/examples/with-3rd-party/bootstrap.rs +++ b/examples/with-3rd-party/bootstrap.rs @@ -15,7 +15,7 @@ pub fn bootstrap() -> Result<DIContainer, Box<dyn Error>> di_container .bind::<Shuriken>() - .to_default_factory(&|_| Box::new(|| TransientPtr::new(Shuriken::new())))?; + .to_dynamic_value(&|_| Box::new(|| TransientPtr::new(Shuriken::new())))?; Ok(di_container) } diff --git a/examples/with-3rd-party/interfaces/mod.rs b/examples/with-3rd-party/interfaces.rs index c060c34..c060c34 100644 --- a/examples/with-3rd-party/interfaces/mod.rs +++ b/examples/with-3rd-party/interfaces.rs diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 12f3f0b..adf4eda 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["di", "dependency-injection", "ioc", "inversion-of-control"] edition = "2021" [lib] -proc_macro = true +proc-macro = true [package.metadata.docs.rs] all-features = true @@ -28,15 +28,20 @@ uuid = { version = "0.8", features = ["v4"] } once_cell = "1.13.1" thiserror = "1.0.37" proc-macro-error = "1.0.4" +paste = "1.0.8" [target.'cfg(syrette_macros_logging)'.dependencies] tracing = "0.1.37" tracing-subscriber = "0.3.17" -[dev_dependencies] +[dev-dependencies] syrette = { version = "0.5.1", path = ".." } mockall = "0.11.4" pretty_assertions = "1.3.0" syn = { version = "1.0.96", features = ["full", "extra-traits"] } utility-macros = { git = "https://git.hampusmat.com/utility-macros" } +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ["cfg(doc_cfg)", "cfg(tarpaulin_include)", "cfg(syrette_macros_logging)"] + diff --git a/macros/src/injectable/mod.rs b/macros/src/injectable.rs index 0e6ddfd..0e6ddfd 100644 --- a/macros/src/injectable/mod.rs +++ b/macros/src/injectable.rs diff --git a/macros/src/injectable/dependency.rs b/macros/src/injectable/dependency.rs index 8e22f21..30c156f 100644 --- a/macros/src/injectable/dependency.rs +++ b/macros/src/injectable/dependency.rs @@ -6,23 +6,6 @@ use crate::injectable::named_attr_input::NamedAttrInput; use crate::util::error::diagnostic_error_enum; use crate::util::syn_path::SynPathExt; -/// Interface for a dependency of a `Injectable`. -#[cfg_attr(test, mockall::automock)] -pub trait IDependency: Sized -{ - /// Build a new `Dependency` from a argument in a constructor method. - fn build(ctor_method_arg: &FnArg) -> Result<Self, DependencyError>; - - /// Returns the interface type. - fn get_interface(&self) -> &Type; - - /// Returns the pointer type identity. - fn get_ptr(&self) -> &Ident; - - /// Returns optional name of the dependency. - fn get_name(&self) -> &Option<LitStr>; -} - /// Representation of a dependency of a injectable type. /// /// Found as a argument in the constructor method of a `Injectable`. @@ -34,9 +17,11 @@ pub struct Dependency name: Option<LitStr>, } -impl IDependency for Dependency +#[cfg_attr(test, mockall::automock)] +impl Dependency { - fn build(ctor_method_arg: &FnArg) -> Result<Self, DependencyError> + /// Build a new `Dependency` from a argument in a constructor method. + pub fn build(ctor_method_arg: &FnArg) -> Result<Self, DependencyError> { let typed_ctor_method_arg = match ctor_method_arg { FnArg::Typed(typed_arg) => Ok(typed_arg), @@ -116,17 +101,23 @@ impl IDependency for Dependency }) } - fn get_interface(&self) -> &Type + /// Returns the dependency's interface type. + #[allow(dead_code)] // Mock function is never used + pub fn get_interface(&self) -> &Type { &self.interface } - fn get_ptr(&self) -> &Ident + /// Returns the dependency's pointer type name. + #[allow(dead_code)] // Mock function is never used + pub fn get_ptr(&self) -> &Ident { &self.ptr } - fn get_name(&self) -> &Option<LitStr> + /// Returns the dependency's name. + #[allow(dead_code)] // Mock function is never used + pub fn get_name(&self) -> &Option<LitStr> { &self.name } diff --git a/macros/src/injectable/implementation.rs b/macros/src/injectable/implementation.rs index a98d1ce..a67b4a3 100644 --- a/macros/src/injectable/implementation.rs +++ b/macros/src/injectable/implementation.rs @@ -16,7 +16,7 @@ use syn::{ Type, }; -use crate::injectable::dependency::{DependencyError, IDependency}; +use crate::injectable::dependency::DependencyError; use crate::util::error::diagnostic_error_enum; use crate::util::item_impl::find_impl_method_by_name_mut; use crate::util::string::camelcase_to_snakecase; @@ -28,19 +28,22 @@ use crate::util::syn_ext::{ MethodTurbofishExt, }; use crate::util::syn_path::{syn_path, SynPathExt}; +use crate::util::use_double; + +use_double!(crate::injectable::dependency::Dependency); const DI_CONTAINER_VAR_NAME: &str = "di_container"; const DEPENDENCY_HISTORY_VAR_NAME: &str = "dependency_history"; -pub struct InjectableImpl<Dep: IDependency> +pub struct InjectableImpl { - dependencies: Vec<Dep>, + dependencies: Vec<Dependency>, original_impl: ItemImpl, constructor_method: ImplItemMethod, } -impl<Dep: IDependency> InjectableImpl<Dep> +impl InjectableImpl { #[cfg(not(tarpaulin_include))] pub fn new( @@ -334,7 +337,7 @@ impl<Dep: IDependency> InjectableImpl<Dep> } fn create_get_dep_method_calls( - dependencies: &[Dep], + dependencies: &[Dependency], is_async: bool, di_container_var: &Ident, dependency_history_var: &Ident, @@ -353,7 +356,7 @@ impl<Dep: IDependency> InjectableImpl<Dep> .collect() } - fn create_binding_options(dependency: &Dep) -> Expr + fn create_binding_options(dependency: &Dependency) -> Expr { let binding_options_new = Expr::Call(ExprCall::new( Expr::Path(ExprPath::new(syn_path!( @@ -373,7 +376,7 @@ impl<Dep: IDependency> InjectableImpl<Dep> } fn create_single_get_dep_method_call( - dependency: &Dep, + dependency: &Dependency, is_async: bool, di_container_var: &Ident, dependency_history_var: &Ident, @@ -432,12 +435,12 @@ impl<Dep: IDependency> InjectableImpl<Dep> fn build_dependencies( ctor_method: &ImplItemMethod, - ) -> Result<Vec<Dep>, DependencyError> + ) -> Result<Vec<Dependency>, DependencyError> { let ctor_method_args = &ctor_method.sig.inputs; let dependencies_result: Result<Vec<_>, _> = - ctor_method_args.iter().map(Dep::build).collect(); + ctor_method_args.iter().map(Dependency::build).collect(); let deps = dependencies_result?; @@ -582,7 +585,7 @@ mod tests }; use super::*; - use crate::injectable::dependency::MockIDependency; + use crate::injectable::dependency::MockDependency; use crate::injectable::named_attr_input::NamedAttrInput; use crate::test_utils::{ create_path, @@ -650,14 +653,14 @@ mod tests let _lock = get_lock(&TEST_MUTEX); - let build_context = MockIDependency::build_context(); + let build_context = MockDependency::build_context(); build_context .expect() - .returning(|_| Ok(MockIDependency::new())); + .returning(|_| Ok(MockDependency::new())); - let dependencies = InjectableImpl::<MockIDependency>::build_dependencies(&method) - .expect("Expected Ok"); + let dependencies = + InjectableImpl::build_dependencies(&method).expect("Expected Ok"); assert_eq!(dependencies.len(), 2); } @@ -719,15 +722,15 @@ mod tests let _lock = get_lock(&TEST_MUTEX); - let build_context = MockIDependency::build_context(); + let build_context = MockDependency::build_context(); build_context .expect() - .returning(|_| Ok(MockIDependency::new())) + .returning(|_| Ok(MockDependency::new())) .times(2); - let dependencies = InjectableImpl::<MockIDependency>::build_dependencies(&method) - .expect("Expected Ok"); + let dependencies = + InjectableImpl::build_dependencies(&method).expect("Expected Ok"); assert_eq!(dependencies.len(), 2); } @@ -804,7 +807,7 @@ mod tests }, }; - InjectableImpl::<MockIDependency>::remove_method_argument_attrs(&mut method); + InjectableImpl::remove_method_argument_attrs(&mut method); assert_eq!( method.sig.inputs.first().unwrap().clone(), @@ -830,7 +833,7 @@ mod tests #[test] fn can_create_single_get_dep_method_call() { - let mut mock_dependency = MockIDependency::new(); + let mut mock_dependency = MockDependency::new(); mock_dependency .expect_get_interface() @@ -848,7 +851,7 @@ mod tests let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME); let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME); - let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call( + let output = InjectableImpl::create_single_get_dep_method_call( &mock_dependency, false, &format_ident!("{}", DI_CONTAINER_VAR_NAME), @@ -880,7 +883,7 @@ mod tests #[test] fn can_create_single_get_dep_method_call_with_name() { - let mut mock_dependency = MockIDependency::new(); + let mut mock_dependency = MockDependency::new(); mock_dependency .expect_get_interface() @@ -900,7 +903,7 @@ mod tests let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME); let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME); - let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call( + let output = InjectableImpl::create_single_get_dep_method_call( &mock_dependency, false, &format_ident!("{}", DI_CONTAINER_VAR_NAME), @@ -932,7 +935,7 @@ mod tests #[test] fn can_create_single_get_dep_method_call_async() { - let mut mock_dependency = MockIDependency::new(); + let mut mock_dependency = MockDependency::new(); mock_dependency .expect_get_interface() @@ -950,7 +953,7 @@ mod tests let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME); let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME); - let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call( + let output = InjectableImpl::create_single_get_dep_method_call( &mock_dependency, true, &format_ident!("{}", DI_CONTAINER_VAR_NAME), @@ -983,7 +986,7 @@ mod tests #[test] fn can_create_single_get_dep_method_call_async_with_name() { - let mut mock_dependency = MockIDependency::new(); + let mut mock_dependency = MockDependency::new(); mock_dependency .expect_get_interface() @@ -1003,7 +1006,7 @@ mod tests let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME); let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME); - let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call( + let output = InjectableImpl::create_single_get_dep_method_call( &mock_dependency, true, &format_ident!("{}", DI_CONTAINER_VAR_NAME), diff --git a/macros/src/lib.rs b/macros/src/lib.rs index e55e23f..b9b6ea5 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -23,7 +23,6 @@ use syn::{ use crate::caster::generate_caster; use crate::declare_interface_args::DeclareInterfaceArgs; -use crate::injectable::dependency::Dependency; use crate::injectable::dummy::expand_dummy_blocking_impl; use crate::injectable::implementation::{InjectableImpl, InjectableImplError}; use crate::injectable::macro_args::InjectableMacroArgs; @@ -255,8 +254,7 @@ pub fn injectable(args_stream: TokenStream, input_stream: TokenStream) -> TokenS ); } - let injectable_impl = - InjectableImpl::<Dependency>::new(item_impl, &constructor).unwrap_or_abort(); + let injectable_impl = InjectableImpl::new(item_impl, &constructor).unwrap_or_abort(); injectable_impl.validate(is_async).unwrap_or_abort(); diff --git a/macros/src/util.rs b/macros/src/util.rs new file mode 100644 index 0000000..3557896 --- /dev/null +++ b/macros/src/util.rs @@ -0,0 +1,67 @@ +pub mod error; +pub mod item_impl; +pub mod iterator_ext; +pub mod string; +pub mod syn_ext; +pub mod syn_path; +pub mod tokens; + +macro_rules! to_option { + ($($tokens: tt)+) => { + Some($($tokens)+) + }; + + () => { + None + }; +} + +macro_rules! or { + (($($tokens: tt)+) else ($($default: tt)*)) => { + $($tokens)* + }; + + (() else ($($default: tt)*)) => { + $($default)* + }; +} + +/// Imports the specified item, prepending 'Mock' to the item identifier if the `test` +/// configuration option is set. +/// +/// # Examples +/// ```ignore +/// use_double!(crate::dependency_history::DependencyHistory); +/// ``` +/// <br> +/// +/// Expands to the following when `cfg(not(test))` +/// ```ignore +/// use crate::dependency_history::DependencyHistory; +/// ``` +/// <br> +/// +/// Expands to the following when `cfg(test)` +/// ```ignore +/// use crate::dependency_history::MockDependencyHistory as DependencyHistory; +/// ``` +macro_rules! use_double { + ($([$($part: ident),*])? $item_path_part: ident :: $($next_part: tt)+) => { + use_double!( + [$($($part,)*)? $item_path_part] + $($next_part)+ + ); + }; + + ([$($part: ident),*] $item_path_part: ident) => { + #[cfg(not(test))] + use $($part::)* $item_path_part; + + ::paste::paste! { + #[cfg(test)] + use $($part::)* [<Mock $item_path_part>] as $item_path_part; + } + }; +} + +pub(crate) use {or, to_option, use_double}; diff --git a/macros/src/util/error.rs b/macros/src/util/error.rs index d068661..b9f67c4 100644 --- a/macros/src/util/error.rs +++ b/macros/src/util/error.rs @@ -1,3 +1,6 @@ +use proc_macro2::Span; +use proc_macro_error::Diagnostic; + /// Used to create a error enum that converts into a [`Diagnostic`]. /// /// [`Diagnostic`]: proc_macro_error::Diagnostic @@ -30,22 +33,17 @@ macro_rules! diagnostic_error_enum { #[must_use] fn from(err: $name) -> Self { - let (error, span, notes, helps, errs, source): ( - String, - ::proc_macro2::Span, - Vec<(String, ::proc_macro2::Span)>, - Vec<(String, ::proc_macro2::Span)>, - Vec<(String, ::proc_macro2::Span)>, - Option<::proc_macro_error::Diagnostic> - ) = match err { + use $crate::util::error::DiagnosticErrorVariantInfo; + + let DiagnosticErrorVariantInfo { + error, span, notes, helps, errs, source + } = match err { $( - $name::$variant { - $($variant_field),* - } => { - ( - format!($($error)*), - $error_span, - vec![$( + $name::$variant { $($variant_field),* } => { + DiagnosticErrorVariantInfo { + error: format!($($error)*), + span: $error_span, + notes: vec![$( ( format!($($note)*), $crate::util::or!( @@ -54,7 +52,7 @@ macro_rules! diagnostic_error_enum { ) ) ),*], - vec![$( + helps: vec![$( ( format!($($help)*), $crate::util::or!( @@ -63,7 +61,7 @@ macro_rules! diagnostic_error_enum { ) ) ),*], - vec![$( + errs: vec![$( ( format!($($err)*), $crate::util::or!( @@ -72,8 +70,8 @@ macro_rules! diagnostic_error_enum { ) ) ),*], - $crate::util::to_option!($($source.into())?) - ) + source: $crate::util::to_option!($($source.into())?) + } } ),* }; @@ -109,8 +107,18 @@ macro_rules! diagnostic_error_enum { diagnostic } } - }; } +/// Used by [`diagnostic_error_enum`]. +pub struct DiagnosticErrorVariantInfo +{ + pub error: String, + pub span: Span, + pub notes: Vec<(String, Span)>, + pub helps: Vec<(String, Span)>, + pub errs: Vec<(String, Span)>, + pub source: Option<Diagnostic>, +} + pub(crate) use diagnostic_error_enum; diff --git a/macros/src/util/mod.rs b/macros/src/util/mod.rs deleted file mode 100644 index 7ab2185..0000000 --- a/macros/src/util/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -pub mod error; -pub mod item_impl; -pub mod iterator_ext; -pub mod string; -pub mod syn_ext; -pub mod syn_path; -pub mod tokens; - -macro_rules! to_option { - ($($tokens: tt)+) => { - Some($($tokens)+) - }; - - () => { - None - }; -} - -macro_rules! or { - (($($tokens: tt)+) else ($($default: tt)*)) => { - $($tokens)* - }; - - (() else ($($default: tt)*)) => { - $($default)* - }; -} - -pub(crate) use {or, to_option}; diff --git a/src/any_factory.rs b/src/any_factory.rs deleted file mode 100644 index 3aee98f..0000000 --- a/src/any_factory.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Interface for any factory to ever exist. - -use std::any::Any; -use std::fmt::Debug; - -/// Interface for any factory to ever exist. -pub trait AnyFactory: Any + Debug -{ - fn as_any(&self) -> &dyn Any; -} - -/// Interface for any threadsafe factory to ever exist. -pub trait AnyThreadsafeFactory: AnyFactory + Send + Sync + Debug {} diff --git a/src/castable_factory/mod.rs b/src/castable_function.rs index 196dc14..4c2f0db 100644 --- a/src/castable_factory/mod.rs +++ b/src/castable_function.rs @@ -1,13 +1,18 @@ use std::any::{type_name, Any}; use std::fmt::Debug; -use crate::any_factory::AnyFactory; use crate::ptr::TransientPtr; #[cfg(feature = "async")] pub mod threadsafe; -pub struct CastableFactory<ReturnInterface, DIContainerT> +/// Interface for any castable function. +pub trait AnyCastableFunction: Any + Debug +{ + fn as_any(&self) -> &dyn Any; +} + +pub struct CastableFunction<ReturnInterface, DIContainerT> where ReturnInterface: 'static + ?Sized, DIContainerT: 'static, @@ -15,7 +20,7 @@ where func: &'static dyn Fn(&DIContainerT) -> TransientPtr<ReturnInterface>, } -impl<ReturnInterface, DIContainerT> CastableFactory<ReturnInterface, DIContainerT> +impl<ReturnInterface, DIContainerT> CastableFunction<ReturnInterface, DIContainerT> where ReturnInterface: 'static + ?Sized, { @@ -32,8 +37,8 @@ where } } -impl<ReturnInterface, DIContainerT> AnyFactory - for CastableFactory<ReturnInterface, DIContainerT> +impl<ReturnInterface, DIContainerT> AnyCastableFunction + for CastableFunction<ReturnInterface, DIContainerT> where ReturnInterface: 'static + ?Sized, DIContainerT: 'static, @@ -45,7 +50,7 @@ where } impl<ReturnInterface, DIContainerT> Debug - for CastableFactory<ReturnInterface, DIContainerT> + for CastableFunction<ReturnInterface, DIContainerT> where ReturnInterface: 'static + ?Sized, { @@ -55,7 +60,7 @@ where let ret = type_name::<TransientPtr<ReturnInterface>>(); formatter.write_fmt(format_args!( - "CastableFactory (&DIContainer) -> {ret} {{ ... }}" + "CastableFunction (&DIContainer) -> {ret} {{ ... }}" )) } } @@ -75,13 +80,13 @@ mod tests #[test] fn can_call() { - let castable_factory = CastableFactory::new(&|_: &MockDIContainer| { + let castable_func = CastableFunction::new(&|_: &MockDIContainer| { TransientPtr::new(Bacon { heal_amount: 27 }) }); let mock_di_container = MockDIContainer::new(); - let output = castable_factory.call(&mock_di_container); + let output = castable_func.call(&mock_di_container); assert_eq!(output, TransientPtr::new(Bacon { heal_amount: 27 })); } diff --git a/src/castable_factory/threadsafe.rs b/src/castable_function/threadsafe.rs index 5935d75..7543396 100644 --- a/src/castable_factory/threadsafe.rs +++ b/src/castable_function/threadsafe.rs @@ -1,10 +1,16 @@ use std::any::{type_name, Any}; use std::fmt::Debug; -use crate::any_factory::{AnyFactory, AnyThreadsafeFactory}; +use crate::castable_function::AnyCastableFunction; use crate::ptr::TransientPtr; -pub struct ThreadsafeCastableFactory<ReturnInterface, DIContainerT> +/// Interface for any threadsafe castable function. +pub trait AnyThreadsafeCastableFunction: + AnyCastableFunction + Send + Sync + Debug +{ +} + +pub struct ThreadsafeCastableFunction<ReturnInterface, DIContainerT> where DIContainerT: 'static, ReturnInterface: 'static + ?Sized, @@ -13,7 +19,7 @@ where } impl<ReturnInterface, DIContainerT> - ThreadsafeCastableFactory<ReturnInterface, DIContainerT> + ThreadsafeCastableFunction<ReturnInterface, DIContainerT> where DIContainerT: 'static, ReturnInterface: 'static + ?Sized, @@ -33,8 +39,8 @@ where } } -impl<ReturnInterface, DIContainerT> AnyFactory - for ThreadsafeCastableFactory<ReturnInterface, DIContainerT> +impl<ReturnInterface, DIContainerT> AnyCastableFunction + for ThreadsafeCastableFunction<ReturnInterface, DIContainerT> where DIContainerT: 'static, ReturnInterface: 'static + ?Sized, @@ -45,8 +51,8 @@ where } } -impl<ReturnInterface, DIContainerT> AnyThreadsafeFactory - for ThreadsafeCastableFactory<ReturnInterface, DIContainerT> +impl<ReturnInterface, DIContainerT> AnyThreadsafeCastableFunction + for ThreadsafeCastableFunction<ReturnInterface, DIContainerT> where DIContainerT: 'static, ReturnInterface: 'static + ?Sized, @@ -54,7 +60,7 @@ where } impl<ReturnInterface, DIContainerT> Debug - for ThreadsafeCastableFactory<ReturnInterface, DIContainerT> + for ThreadsafeCastableFunction<ReturnInterface, DIContainerT> where DIContainerT: 'static, ReturnInterface: 'static + ?Sized, @@ -65,7 +71,7 @@ where let ret = type_name::<TransientPtr<ReturnInterface>>(); formatter.write_fmt(format_args!( - "ThreadsafeCastableFactory (&AsyncDIContainer) -> {ret} {{ ... }}", + "ThreadsafeCastableFunction(&AsyncDIContainer) -> {ret} {{ ... }}", )) } } @@ -85,14 +91,14 @@ mod tests #[test] fn can_call() { - let castable_factory = - ThreadsafeCastableFactory::new(&|_: &MockAsyncDIContainer| { + let castable_function = + ThreadsafeCastableFunction::new(&|_: &MockAsyncDIContainer| { TransientPtr::new(Bacon { heal_amount: 27 }) }); let mock_di_container = MockAsyncDIContainer::new(); - let output = castable_factory.call(&mock_di_container); + let output = castable_function.call(&mock_di_container); assert_eq!(output, TransientPtr::new(Bacon { heal_amount: 27 })); } diff --git a/src/di_container/mod.rs b/src/di_container.rs index 4e60505..4e60505 100644 --- a/src/di_container/mod.rs +++ b/src/di_container.rs diff --git a/src/di_container/asynchronous/mod.rs b/src/di_container/asynchronous.rs index 3e29ef6..6cb54f3 100644 --- a/src/di_container/asynchronous/mod.rs +++ b/src/di_container/asynchronous.rs @@ -51,15 +51,17 @@ //! ``` use std::any::type_name; +use crate::castable_function::threadsafe::ThreadsafeCastableFunction; 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; use crate::private::cast::boxed::CastBox; use crate::private::cast::error::CastError; -use crate::provider::r#async::{AsyncProvidable, IAsyncProvider}; -use crate::ptr::SomePtr; +use crate::provider::r#async::{AsyncProvidable, IAsyncProvider, ProvidableFunctionKind}; +use crate::ptr::{SomePtr, TransientPtr}; use crate::util::use_double; use_double!(crate::dependency_history::DependencyHistory); @@ -347,12 +349,10 @@ impl AsyncDIContainer )) } #[cfg(feature = "factory")] - AsyncProvidable::Factory(factory_binding) => { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - - let factory = factory_binding + AsyncProvidable::Function(func_bound, ProvidableFunctionKind::UserCalled) => { + let factory = func_bound .as_any() - .downcast_ref::<ThreadsafeCastableFactory<Interface, Self>>() + .downcast_ref::<ThreadsafeCastableFunction<Interface, Self>>() .ok_or_else(|| AsyncDIContainerError::CastFailed { interface: type_name::<Interface>(), binding_kind: "factory", @@ -360,48 +360,42 @@ impl AsyncDIContainer Ok(SomePtr::ThreadsafeFactory(factory.call(self).into())) } - #[cfg(feature = "factory")] - AsyncProvidable::DefaultFactory(binding) => { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - use crate::ptr::TransientPtr; - - type DefaultFactoryFn<Interface> = ThreadsafeCastableFactory< + AsyncProvidable::Function(func_bound, ProvidableFunctionKind::Instant) => { + type Func<Interface> = ThreadsafeCastableFunction< dyn Fn() -> TransientPtr<Interface> + Send + Sync, AsyncDIContainer, >; - let default_factory = binding + let dynamic_val_func = func_bound .as_any() - .downcast_ref::<DefaultFactoryFn<Interface>>() + .downcast_ref::<Func<Interface>>() .ok_or_else(|| AsyncDIContainerError::CastFailed { - interface: type_name::<DefaultFactoryFn<Interface>>(), - binding_kind: "default factory", + interface: type_name::<Func<Interface>>(), + binding_kind: "dynamic value func", })?; - Ok(SomePtr::Transient(default_factory.call(self)())) + Ok(SomePtr::Transient(dynamic_val_func.call(self)())) } - #[cfg(feature = "factory")] - AsyncProvidable::AsyncDefaultFactory(binding) => { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - use crate::future::BoxFuture; - use crate::ptr::TransientPtr; - - type AsyncDefaultFactoryFn<Interface> = ThreadsafeCastableFactory< - dyn Fn<(), Output = BoxFuture<'static, TransientPtr<Interface>>> - + Send - + Sync, + AsyncProvidable::Function( + func_bound, + ProvidableFunctionKind::AsyncInstant, + ) => { + type Func<Interface> = ThreadsafeCastableFunction< + dyn Fn() -> BoxFuture<'static, TransientPtr<Interface>> + Send + Sync, AsyncDIContainer, >; - let async_default_factory = binding + let async_dynamic_value_func = func_bound .as_any() - .downcast_ref::<AsyncDefaultFactoryFn<Interface>>() + .downcast_ref::<Func<Interface>>() .ok_or_else(|| AsyncDIContainerError::CastFailed { - interface: type_name::<AsyncDefaultFactoryFn<Interface>>(), - binding_kind: "async default factory", + interface: type_name::<Func<Interface>>(), + binding_kind: "async dynamic value function", })?; - Ok(SomePtr::Transient(async_default_factory.call(self)().await)) + Ok(SomePtr::Transient( + async_dynamic_value_func.call(self)().await, + )) } } } @@ -652,7 +646,10 @@ mod tests } } - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; + use std::sync::Arc; + + use crate::castable_function::threadsafe::ThreadsafeCastableFunction; + use crate::provider::r#async::ProvidableFunctionKind; type IUserManagerFactory = dyn Fn(Vec<i128>) -> TransientPtr<dyn IUserManager> + Send + Sync; @@ -672,10 +669,9 @@ mod tests }; inner_mock_provider.expect_provide().returning(|_, _| { - Ok(AsyncProvidable::Factory( - crate::ptr::ThreadsafeFactoryPtr::new( - ThreadsafeCastableFactory::new(factory_func), - ), + Ok(AsyncProvidable::Function( + Arc::new(ThreadsafeCastableFunction::new(factory_func)), + ProvidableFunctionKind::UserCalled, )) }); @@ -734,7 +730,10 @@ mod tests } } - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; + use std::sync::Arc; + + use crate::castable_function::threadsafe::ThreadsafeCastableFunction; + use crate::provider::r#async::ProvidableFunctionKind; type IUserManagerFactory = dyn Fn(Vec<i128>) -> TransientPtr<dyn IUserManager> + Send + Sync; @@ -754,10 +753,9 @@ mod tests }; inner_mock_provider.expect_provide().returning(|_, _| { - Ok(AsyncProvidable::Factory( - crate::ptr::ThreadsafeFactoryPtr::new( - ThreadsafeCastableFactory::new(factory_func), - ), + Ok(AsyncProvidable::Function( + Arc::new(ThreadsafeCastableFunction::new(factory_func)), + ProvidableFunctionKind::UserCalled, )) }); diff --git a/src/di_container/asynchronous/binding/mod.rs b/src/di_container/asynchronous/binding.rs index 6a09bff..6a09bff 100644 --- a/src/di_container/asynchronous/binding/mod.rs +++ b/src/di_container/asynchronous/binding.rs diff --git a/src/di_container/asynchronous/binding/builder.rs b/src/di_container/asynchronous/binding/builder.rs index f42e6a1..db1b576 100644 --- a/src/di_container/asynchronous/binding/builder.rs +++ b/src/di_container/asynchronous/binding/builder.rs @@ -1,13 +1,17 @@ //! Binding builder for types inside of a [`AsyncDIContainer`]. use std::any::type_name; use std::marker::PhantomData; +use std::sync::Arc; +use crate::castable_function::threadsafe::ThreadsafeCastableFunction; use crate::di_container::asynchronous::binding::scope_configurator::AsyncBindingScopeConfigurator; -#[cfg(feature = "factory")] use crate::di_container::asynchronous::binding::when_configurator::AsyncBindingWhenConfigurator; use crate::di_container::BindingOptions; use crate::errors::async_di_container::AsyncBindingBuilderError; +use crate::future::BoxFuture; use crate::interfaces::async_injectable::AsyncInjectable; +use crate::provider::r#async::{AsyncFunctionProvider, ProvidableFunctionKind}; +use crate::ptr::TransientPtr; use crate::util::use_double; use_double!(crate::dependency_history::DependencyHistory); @@ -173,8 +177,10 @@ where Interface: Fn<Args, Output = Return> + Send + Sync, FactoryFunc: Fn(&AsyncDIContainer) -> BoxFn<Args, Return> + Send + Sync, { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - use crate::provider::r#async::AsyncFactoryVariant; + use std::sync::Arc; + + use crate::castable_function::threadsafe::ThreadsafeCastableFunction; + use crate::provider::r#async::ProvidableFunctionKind; if self .di_container @@ -186,13 +192,13 @@ where ))); } - let factory_impl = ThreadsafeCastableFactory::new(factory_func); + let factory_impl = ThreadsafeCastableFunction::new(factory_func); self.di_container.set_binding::<Interface>( BindingOptions::new(), - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::Normal, + Box::new(crate::provider::r#async::AsyncFunctionProvider::new( + Arc::new(factory_impl), + ProvidableFunctionKind::UserCalled, )), ); @@ -270,9 +276,6 @@ where + Send + Sync, { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - use crate::provider::r#async::AsyncFactoryVariant; - if self .di_container .has_binding::<Interface>(BindingOptions::new()) @@ -283,21 +286,21 @@ where ))); } - let factory_impl = ThreadsafeCastableFactory::new(factory_func); + let factory_impl = ThreadsafeCastableFunction::new(factory_func); self.di_container.set_binding::<Interface>( BindingOptions::new(), - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::Normal, + Box::new(AsyncFunctionProvider::new( + Arc::new(factory_impl), + ProvidableFunctionKind::UserCalled, )), ); Ok(AsyncBindingWhenConfigurator::new(self.di_container)) } - /// Creates a binding of type `Interface` to a factory that takes no arguments - /// inside of the associated [`AsyncDIContainer`]. + /// Creates a binding of type `Interface` to a value resolved using the given + /// function. /// /// # Errors /// Will return Err if the associated [`AsyncDIContainer`] already have a binding @@ -325,7 +328,7 @@ where /// # { /// # let mut di_container = AsyncDIContainer::new(); /// # - /// di_container.bind::<dyn Foo>().to_default_factory(&|_| { + /// di_container.bind::<dyn Foo>().to_dynamic_value(&|_| { /// Box::new(|| { /// let bar = TransientPtr::new(Bar { /// num: 42, @@ -339,24 +342,20 @@ where /// # Ok(()) /// # } /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub fn to_default_factory<Return, FactoryFunc>( + pub fn to_dynamic_value<Func>( self, - factory_func: &'static FactoryFunc, + func: &'static Func, ) -> Result< AsyncBindingWhenConfigurator<'di_container, Interface>, AsyncBindingBuilderError, > where - Return: 'static + ?Sized, - FactoryFunc: Fn(&AsyncDIContainer) -> BoxFn<(), crate::ptr::TransientPtr<Return>> + Func: Fn( + &AsyncDIContainer, + ) -> Box<dyn Fn() -> TransientPtr<Interface> + Send + Sync> + Send + Sync, { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - use crate::provider::r#async::AsyncFactoryVariant; - if self .di_container .has_binding::<Interface>(BindingOptions::new()) @@ -367,21 +366,21 @@ where ))); } - let factory_impl = ThreadsafeCastableFactory::new(factory_func); + let castable_func = ThreadsafeCastableFunction::new(func); self.di_container.set_binding::<Interface>( BindingOptions::new(), - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::Default, + Box::new(AsyncFunctionProvider::new( + Arc::new(castable_func), + ProvidableFunctionKind::Instant, )), ); Ok(AsyncBindingWhenConfigurator::new(self.di_container)) } - /// Creates a binding of factory type `Interface` to a async factory inside of the - /// associated [`AsyncDIContainer`]. + /// Creates a binding of type `Interface` to a value resolved using the given + /// async function. /// /// # Errors /// Will return Err if the associated [`AsyncDIContainer`] already have a binding @@ -412,7 +411,7 @@ where /// # /// di_container /// .bind::<dyn Foo>() - /// .to_async_default_factory(&|_| { + /// .to_async_dynamic_value(&|_| { /// Box::new(|| { /// Box::pin(async { /// let bar = TransientPtr::new(Bar { @@ -430,24 +429,21 @@ where /// # Ok(()) /// # } /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub fn to_async_default_factory<Return, FactoryFunc>( + pub fn to_async_dynamic_value<Func>( self, - factory_func: &'static FactoryFunc, + func: &'static Func, ) -> Result< AsyncBindingWhenConfigurator<'di_container, Interface>, AsyncBindingBuilderError, > where - Return: 'static + ?Sized, - FactoryFunc: Fn(&AsyncDIContainer) -> BoxFn<(), crate::future::BoxFuture<'static, Return>> - + Send + Func: Fn( + &AsyncDIContainer, + ) -> Box< + dyn Fn() -> BoxFuture<'static, TransientPtr<Interface>> + Send + Sync, + > + Send + Sync, { - use crate::castable_factory::threadsafe::ThreadsafeCastableFactory; - use crate::provider::r#async::AsyncFactoryVariant; - if self .di_container .has_binding::<Interface>(BindingOptions::new()) @@ -458,13 +454,13 @@ where ))); } - let factory_impl = ThreadsafeCastableFactory::new(factory_func); + let castable_func = ThreadsafeCastableFunction::new(func); self.di_container.set_binding::<Interface>( BindingOptions::new(), - Box::new(crate::provider::r#async::AsyncFactoryProvider::new( - crate::ptr::ThreadsafeFactoryPtr::new(factory_impl), - AsyncFactoryVariant::AsyncDefault, + Box::new(AsyncFunctionProvider::new( + Arc::new(castable_func), + ProvidableFunctionKind::AsyncInstant, )), ); @@ -599,8 +595,7 @@ mod tests } #[tokio::test] - #[cfg(feature = "factory")] - async fn can_bind_to_default_factory() + async fn can_bind_to_dynamic_value() { use crate::ptr::TransientPtr; @@ -625,7 +620,7 @@ mod tests ); binding_builder - .to_default_factory(&|_| { + .to_dynamic_value(&|_| { Box::new(|| { let user_manager: TransientPtr<dyn subjects_async::IUserManager> = TransientPtr::new(subjects_async::UserManager::new()); @@ -637,8 +632,7 @@ mod tests } #[tokio::test] - #[cfg(feature = "factory")] - async fn can_bind_to_async_default_factory() + async fn can_bind_to_async_dynamic_value() { use crate::ptr::TransientPtr; use crate::test_utils::async_closure; @@ -664,7 +658,7 @@ mod tests ); binding_builder - .to_async_default_factory(&|_| { + .to_async_dynamic_value(&|_| { async_closure!(|| { let user_manager: TransientPtr<dyn subjects_async::IUserManager> = TransientPtr::new(subjects_async::UserManager::new()); diff --git a/src/di_container/blocking/mod.rs b/src/di_container/blocking.rs index d9efe94..0c464df 100644 --- a/src/di_container/blocking/mod.rs +++ b/src/di_container/blocking.rs @@ -51,14 +51,15 @@ //! ``` use std::any::type_name; +use crate::castable_function::CastableFunction; 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; -use crate::provider::blocking::{IProvider, Providable}; -use crate::ptr::SomePtr; +use crate::provider::blocking::{IProvider, Providable, ProvidableFunctionKind}; +use crate::ptr::{SomePtr, TransientPtr}; use crate::util::use_double; use_double!(crate::dependency_history::DependencyHistory); @@ -284,12 +285,10 @@ impl DIContainer })?, )), #[cfg(feature = "factory")] - Providable::Factory(factory_binding) => { - use crate::castable_factory::CastableFactory; - - let factory = factory_binding + Providable::Function(func_bound, ProvidableFunctionKind::UserCalled) => { + let factory = func_bound .as_any() - .downcast_ref::<CastableFactory<Interface, Self>>() + .downcast_ref::<CastableFunction<Interface, Self>>() .ok_or_else(|| DIContainerError::CastFailed { interface: type_name::<Interface>(), binding_kind: "factory", @@ -297,23 +296,19 @@ impl DIContainer Ok(SomePtr::Factory(factory.call(self).into())) } - #[cfg(feature = "factory")] - Providable::DefaultFactory(factory_binding) => { - use crate::castable_factory::CastableFactory; - use crate::ptr::TransientPtr; - - type DefaultFactoryFn<Interface> = - CastableFactory<dyn Fn() -> TransientPtr<Interface>, DIContainer>; + Providable::Function(func_bound, ProvidableFunctionKind::Instant) => { + type Func<Interface> = + CastableFunction<dyn Fn() -> TransientPtr<Interface>, DIContainer>; - let default_factory = factory_binding + let dynamic_val_func = func_bound .as_any() - .downcast_ref::<DefaultFactoryFn<Interface>>() + .downcast_ref::<Func<Interface>>() .ok_or_else(|| DIContainerError::CastFailed { interface: type_name::<Interface>(), - binding_kind: "default factory", + binding_kind: "dynamic value function", })?; - Ok(SomePtr::Transient(default_factory.call(self)())) + Ok(SomePtr::Transient(dynamic_val_func.call(self)())) } } } @@ -517,7 +512,10 @@ mod tests #[cfg(feature = "factory")] fn can_get_factory() { - use crate::castable_factory::CastableFactory; + use std::rc::Rc; + + use crate::castable_function::CastableFunction; + use crate::provider::blocking::ProvidableFunctionKind; use crate::ptr::FactoryPtr; trait IUserManager @@ -572,9 +570,10 @@ mod tests let mut mock_provider = MockIProvider::new(); mock_provider.expect_provide().returning_st(|_, _| { - Ok(Providable::Factory(FactoryPtr::new(CastableFactory::new( - factory_func, - )))) + Ok(Providable::Function( + Rc::new(CastableFunction::new(factory_func)), + ProvidableFunctionKind::UserCalled, + )) }); di_container @@ -592,8 +591,10 @@ mod tests #[cfg(feature = "factory")] fn can_get_factory_named() { - use crate::castable_factory::CastableFactory; - use crate::ptr::FactoryPtr; + use std::rc::Rc; + + use crate::castable_function::CastableFunction; + use crate::provider::blocking::ProvidableFunctionKind; trait IUserManager { @@ -647,9 +648,10 @@ mod tests let mut mock_provider = MockIProvider::new(); mock_provider.expect_provide().returning_st(|_, _| { - Ok(Providable::Factory(FactoryPtr::new(CastableFactory::new( - factory_func, - )))) + Ok(Providable::Function( + Rc::new(CastableFunction::new(factory_func)), + ProvidableFunctionKind::UserCalled, + )) }); di_container.binding_storage.set::<IUserManagerFactory>( diff --git a/src/di_container/blocking/binding/mod.rs b/src/di_container/blocking/binding.rs index 6a09bff..6a09bff 100644 --- a/src/di_container/blocking/binding/mod.rs +++ b/src/di_container/blocking/binding.rs diff --git a/src/di_container/blocking/binding/builder.rs b/src/di_container/blocking/binding/builder.rs index 9f7f6f9..596a2aa 100644 --- a/src/di_container/blocking/binding/builder.rs +++ b/src/di_container/blocking/binding/builder.rs @@ -1,13 +1,16 @@ //! Binding builder for types inside of a [`DIContainer`]. use std::any::type_name; use std::marker::PhantomData; +use std::rc::Rc; +use crate::castable_function::CastableFunction; use crate::di_container::blocking::binding::scope_configurator::BindingScopeConfigurator; -#[cfg(feature = "factory")] use crate::di_container::blocking::binding::when_configurator::BindingWhenConfigurator; use crate::di_container::BindingOptions; use crate::errors::di_container::BindingBuilderError; use crate::interfaces::injectable::Injectable; +use crate::provider::blocking::{FunctionProvider, ProvidableFunctionKind}; +use crate::ptr::TransientPtr; use crate::util::use_double; use_double!(crate::dependency_history::DependencyHistory); @@ -181,8 +184,6 @@ where Interface: Fn<Args, Output = crate::ptr::TransientPtr<Return>>, Func: Fn(&DIContainer) -> Box<Interface>, { - use crate::castable_factory::CastableFactory; - if self .di_container .has_binding::<Interface>(BindingOptions::new()) @@ -192,21 +193,21 @@ where >())); } - let factory_impl = CastableFactory::new(factory_func); + let factory_impl = CastableFunction::new(factory_func); self.di_container.set_binding::<Interface>( BindingOptions::new(), - Box::new(crate::provider::blocking::FactoryProvider::new( - crate::ptr::FactoryPtr::new(factory_impl), - false, + Box::new(FunctionProvider::new( + Rc::new(factory_impl), + ProvidableFunctionKind::UserCalled, )), ); Ok(BindingWhenConfigurator::new(self.di_container)) } - /// Creates a binding of type `Interface` to a factory that takes no arguments - /// inside of the associated [`DIContainer`]. + /// Creates a binding of type `Interface` to a value resolved using the given + /// function. /// /// # Errors /// Will return Err if the associated [`DIContainer`] already have a binding for @@ -244,33 +245,20 @@ where /// # { /// # let mut di_container = DIContainer::new(); /// # - /// di_container.bind::<dyn IBuffer>().to_default_factory(&|_| { - /// Box::new(|| { - /// let buffer = TransientPtr::new(Buffer::<BUFFER_SIZE>::new()); - /// - /// buffer as TransientPtr<dyn IBuffer> - /// }) + /// di_container.bind::<dyn IBuffer>().to_dynamic_value(&|_| { + /// Box::new(|| TransientPtr::new(Buffer::<BUFFER_SIZE>::new())) /// }); /// # /// # Ok(()) /// # } /// ``` - #[cfg(feature = "factory")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] - pub fn to_default_factory<Return, FactoryFunc>( + pub fn to_dynamic_value<Func>( self, - factory_func: &'static FactoryFunc, + func: &'static Func, ) -> Result<BindingWhenConfigurator<'di_container, Interface>, BindingBuilderError> where - Return: 'static + ?Sized, - FactoryFunc: Fn( - &DIContainer, - ) -> crate::ptr::TransientPtr< - dyn Fn<(), Output = crate::ptr::TransientPtr<Return>>, - >, + Func: Fn(&DIContainer) -> TransientPtr<dyn Fn() -> TransientPtr<Interface>>, { - use crate::castable_factory::CastableFactory; - if self .di_container .has_binding::<Interface>(BindingOptions::new()) @@ -280,13 +268,13 @@ where >())); } - let factory_impl = CastableFactory::new(factory_func); + let castable_func = CastableFunction::new(func); self.di_container.set_binding::<Interface>( BindingOptions::new(), - Box::new(crate::provider::blocking::FactoryProvider::new( - crate::ptr::FactoryPtr::new(factory_impl), - true, + Box::new(FunctionProvider::new( + Rc::new(castable_func), + ProvidableFunctionKind::Instant, )), ); @@ -370,8 +358,7 @@ mod tests } #[test] - #[cfg(feature = "factory")] - fn can_bind_to_default_factory() + fn can_bind_to_dynamic_value() { use crate::ptr::TransientPtr; @@ -395,7 +382,7 @@ mod tests ); binding_builder - .to_default_factory(&|_| { + .to_dynamic_value(&|_| { Box::new(move || { let user_manager: TransientPtr<dyn subjects::IUserManager> = TransientPtr::new(subjects::UserManager::new()); diff --git a/src/errors/mod.rs b/src/errors.rs index 7eb10bd..7eb10bd 100644 --- a/src/errors/mod.rs +++ b/src/errors.rs diff --git a/src/interfaces/mod.rs b/src/interfaces.rs index e7068ad..e7068ad 100644 --- a/src/interfaces/mod.rs +++ b/src/interfaces.rs @@ -110,11 +110,7 @@ pub mod private; mod provider; mod util; -#[cfg(feature = "factory")] -mod castable_factory; - -#[cfg(feature = "factory")] -mod any_factory; +mod castable_function; #[cfg(test)] #[cfg(not(tarpaulin_include))] diff --git a/src/private/mod.rs b/src/private.rs index 9b03ce8..9b03ce8 100644 --- a/src/private/mod.rs +++ b/src/private.rs diff --git a/src/private/cast/mod.rs b/src/private/cast.rs index ddff2a4..ddff2a4 100644 --- a/src/private/cast/mod.rs +++ b/src/private/cast.rs diff --git a/src/provider/mod.rs b/src/provider.rs index 7fb96bb..7fb96bb 100644 --- a/src/provider/mod.rs +++ b/src/provider.rs diff --git a/src/provider/async.rs b/src/provider/async.rs index 3875363..787ef06 100644 --- a/src/provider/async.rs +++ b/src/provider/async.rs @@ -1,7 +1,9 @@ use std::marker::PhantomData; +use std::sync::Arc; use async_trait::async_trait; +use crate::castable_function::threadsafe::AnyThreadsafeCastableFunction; use crate::errors::injectable::InjectableError; use crate::interfaces::async_injectable::AsyncInjectable; use crate::ptr::{ThreadsafeSingletonPtr, TransientPtr}; @@ -14,18 +16,19 @@ pub enum AsyncProvidable<DIContainerT> { Transient(TransientPtr<dyn AsyncInjectable<DIContainerT>>), Singleton(ThreadsafeSingletonPtr<dyn AsyncInjectable<DIContainerT>>), - #[cfg(feature = "factory")] - Factory( - crate::ptr::ThreadsafeFactoryPtr<dyn crate::any_factory::AnyThreadsafeFactory>, - ), - #[cfg(feature = "factory")] - DefaultFactory( - crate::ptr::ThreadsafeFactoryPtr<dyn crate::any_factory::AnyThreadsafeFactory>, + Function( + Arc<dyn crate::castable_function::threadsafe::AnyThreadsafeCastableFunction>, + ProvidableFunctionKind, ), +} + +#[derive(Debug, Clone, Copy)] +pub enum ProvidableFunctionKind +{ #[cfg(feature = "factory")] - AsyncDefaultFactory( - crate::ptr::ThreadsafeFactoryPtr<dyn crate::any_factory::AnyThreadsafeFactory>, - ), + UserCalled, + Instant, + AsyncInstant, } #[async_trait] @@ -170,40 +173,28 @@ where } } -#[cfg(feature = "factory")] -#[derive(Clone, Copy)] -pub enum AsyncFactoryVariant -{ - Normal, - Default, - AsyncDefault, -} - -#[cfg(feature = "factory")] -pub struct AsyncFactoryProvider +pub struct AsyncFunctionProvider { - factory: - crate::ptr::ThreadsafeFactoryPtr<dyn crate::any_factory::AnyThreadsafeFactory>, - variant: AsyncFactoryVariant, + function: Arc<dyn AnyThreadsafeCastableFunction>, + providable_func_kind: ProvidableFunctionKind, } -#[cfg(feature = "factory")] -impl AsyncFactoryProvider +impl AsyncFunctionProvider { pub fn new( - factory: crate::ptr::ThreadsafeFactoryPtr< - dyn crate::any_factory::AnyThreadsafeFactory, - >, - variant: AsyncFactoryVariant, + function: Arc<dyn AnyThreadsafeCastableFunction>, + providable_func_kind: ProvidableFunctionKind, ) -> Self { - Self { factory, variant } + Self { + function, + providable_func_kind, + } } } -#[cfg(feature = "factory")] #[async_trait] -impl<DIContainerT> IAsyncProvider<DIContainerT> for AsyncFactoryProvider +impl<DIContainerT> IAsyncProvider<DIContainerT> for AsyncFunctionProvider where DIContainerT: Send + Sync, { @@ -213,15 +204,10 @@ where _dependency_history: DependencyHistory, ) -> Result<AsyncProvidable<DIContainerT>, InjectableError> { - Ok(match self.variant { - AsyncFactoryVariant::Normal => AsyncProvidable::Factory(self.factory.clone()), - AsyncFactoryVariant::Default => { - AsyncProvidable::DefaultFactory(self.factory.clone()) - } - AsyncFactoryVariant::AsyncDefault => { - AsyncProvidable::AsyncDefaultFactory(self.factory.clone()) - } - }) + Ok(AsyncProvidable::Function( + self.function.clone(), + self.providable_func_kind, + )) } fn do_clone(&self) -> Box<dyn IAsyncProvider<DIContainerT>> @@ -230,14 +216,13 @@ where } } -#[cfg(feature = "factory")] -impl Clone for AsyncFactoryProvider +impl Clone for AsyncFunctionProvider { fn clone(&self) -> Self { Self { - factory: self.factory.clone(), - variant: self.variant, + function: self.function.clone(), + providable_func_kind: self.providable_func_kind, } } } @@ -297,18 +282,18 @@ mod tests } #[tokio::test] - #[cfg(feature = "factory")] - async fn async_factory_provider_works() + async fn function_provider_works() { use std::any::Any; + use std::sync::Arc; - use crate::any_factory::{AnyFactory, AnyThreadsafeFactory}; - use crate::ptr::ThreadsafeFactoryPtr; + use crate::castable_function::threadsafe::AnyThreadsafeCastableFunction; + use crate::castable_function::AnyCastableFunction; #[derive(Debug)] struct FooFactory; - impl AnyFactory for FooFactory + impl AnyCastableFunction for FooFactory { fn as_any(&self) -> &dyn Any { @@ -316,56 +301,27 @@ mod tests } } - impl AnyThreadsafeFactory for FooFactory {} - - let factory_provider = AsyncFactoryProvider::new( - ThreadsafeFactoryPtr::new(FooFactory), - AsyncFactoryVariant::Normal, - ); - - let default_factory_provider = AsyncFactoryProvider::new( - ThreadsafeFactoryPtr::new(FooFactory), - AsyncFactoryVariant::Default, - ); + impl AnyThreadsafeCastableFunction for FooFactory {} - let async_default_factory_provider = AsyncFactoryProvider::new( - ThreadsafeFactoryPtr::new(FooFactory), - AsyncFactoryVariant::AsyncDefault, + let instant_func_provider = AsyncFunctionProvider::new( + Arc::new(FooFactory), + ProvidableFunctionKind::Instant, ); let di_container = MockAsyncDIContainer::new(); assert!( matches!( - factory_provider - .provide(&di_container, MockDependencyHistory::new()) - .await - .unwrap(), - AsyncProvidable::Factory(_) - ), - "The provided type is not a factory" - ); - - assert!( - matches!( - default_factory_provider - .provide(&di_container, MockDependencyHistory::new()) - .await - .unwrap(), - AsyncProvidable::DefaultFactory(_) - ), - "The provided type is not a default factory" - ); - - assert!( - matches!( - async_default_factory_provider + instant_func_provider .provide(&di_container, MockDependencyHistory::new()) .await .unwrap(), - AsyncProvidable::AsyncDefaultFactory(_) + AsyncProvidable::Function(_, ProvidableFunctionKind::Instant) ), - "The provided type is not a async default factory" + concat!( + "The provided type is not a AsyncProvidable::Function of kind ", + "ProvidableFunctionKind::Instant" + ) ); } } diff --git a/src/provider/blocking.rs b/src/provider/blocking.rs index bde3be5..6b22ad0 100644 --- a/src/provider/blocking.rs +++ b/src/provider/blocking.rs @@ -1,5 +1,7 @@ use std::marker::PhantomData; +use std::rc::Rc; +use crate::castable_function::AnyCastableFunction; use crate::errors::injectable::InjectableError; use crate::interfaces::injectable::Injectable; use crate::ptr::{SingletonPtr, TransientPtr}; @@ -12,10 +14,15 @@ pub enum Providable<DIContainerType> { Transient(TransientPtr<dyn Injectable<DIContainerType>>), Singleton(SingletonPtr<dyn Injectable<DIContainerType>>), + Function(Rc<dyn AnyCastableFunction>, ProvidableFunctionKind), +} + +#[derive(Debug, Clone, Copy)] +pub enum ProvidableFunctionKind +{ #[cfg(feature = "factory")] - Factory(crate::ptr::FactoryPtr<dyn crate::any_factory::AnyFactory>), - #[cfg(feature = "factory")] - DefaultFactory(crate::ptr::FactoryPtr<dyn crate::any_factory::AnyFactory>), + UserCalled, + Instant, } #[cfg_attr(test, mockall::automock)] @@ -105,30 +112,27 @@ where } } -#[cfg(feature = "factory")] -pub struct FactoryProvider +pub struct FunctionProvider { - factory: crate::ptr::FactoryPtr<dyn crate::any_factory::AnyFactory>, - is_default_factory: bool, + function: Rc<dyn AnyCastableFunction>, + providable_func_kind: ProvidableFunctionKind, } -#[cfg(feature = "factory")] -impl FactoryProvider +impl FunctionProvider { pub fn new( - factory: crate::ptr::FactoryPtr<dyn crate::any_factory::AnyFactory>, - is_default_factory: bool, + function: Rc<dyn AnyCastableFunction>, + providable_func_kind: ProvidableFunctionKind, ) -> Self { Self { - factory, - is_default_factory, + function, + providable_func_kind, } } } -#[cfg(feature = "factory")] -impl<DIContainerType> IProvider<DIContainerType> for FactoryProvider +impl<DIContainerType> IProvider<DIContainerType> for FunctionProvider { fn provide( &self, @@ -136,11 +140,10 @@ impl<DIContainerType> IProvider<DIContainerType> for FactoryProvider _dependency_history: DependencyHistory, ) -> Result<Providable<DIContainerType>, InjectableError> { - Ok(if self.is_default_factory { - Providable::DefaultFactory(self.factory.clone()) - } else { - Providable::Factory(self.factory.clone()) - }) + Ok(Providable::Function( + self.function.clone(), + self.providable_func_kind, + )) } } @@ -193,18 +196,17 @@ mod tests } #[test] - #[cfg(feature = "factory")] - fn factory_provider_works() + fn function_provider_works() { use std::any::Any; + use std::rc::Rc; - use crate::any_factory::AnyFactory; - use crate::ptr::FactoryPtr; + use crate::castable_function::AnyCastableFunction; #[derive(Debug)] struct FooFactory; - impl AnyFactory for FooFactory + impl AnyCastableFunction for FooFactory { fn as_any(&self) -> &dyn Any { @@ -212,27 +214,21 @@ mod tests } } - let factory_provider = FactoryProvider::new(FactoryPtr::new(FooFactory), false); - let default_factory_provider = - FactoryProvider::new(FactoryPtr::new(FooFactory), true); + let instant_func_provider = + FunctionProvider::new(Rc::new(FooFactory), ProvidableFunctionKind::Instant); let di_container = MockDIContainer::new(); assert!( matches!( - factory_provider.provide(&di_container, MockDependencyHistory::new()), - Ok(Providable::Factory(_)) - ), - "The provided type is not a factory" - ); - - assert!( - matches!( - default_factory_provider + instant_func_provider .provide(&di_container, MockDependencyHistory::new()), - Ok(Providable::DefaultFactory(_)) + Ok(Providable::Function(_, ProvidableFunctionKind::Instant)) ), - "The provided type is not a default factory" + concat!( + "The provided type is not a Providable::Function of kind ", + "ProvidableFunctionKind::Instant" + ) ); } } diff --git a/src/test_utils.rs b/src/test_utils.rs index 491e9b4..176ffa9 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -301,7 +301,7 @@ pub mod mocks } } -#[cfg(all(feature = "async", feature = "factory"))] +#[cfg(all(feature = "async"))] macro_rules! async_closure { (|$($args: ident),*| { $($inner: stmt);* }) => { Box::new(|$($args),*| { @@ -315,5 +315,5 @@ macro_rules! async_closure { }; } -#[cfg(all(feature = "async", feature = "factory"))] +#[cfg(all(feature = "async"))] pub(crate) use async_closure; |