springtime_di/component.rs
1//! One of the basic blocks of dependency injection is a [Component]. Components are injectable
2//! objects, which themselves can contain dependencies to other components.
3//!
4//! ## Registering concrete components
5//!
6//! Any type that wants to be managed by the DI system needs to implement `Component`. For
7//! convenience, the trait can be automatically derived with all infrastructures if the `derive`
8//! feature is enabled:
9//!
10//! ```
11//! use springtime_di::component::Component;
12//! use springtime_di::instance_provider::ComponentInstancePtr;
13//! use springtime_di::{Component, component_alias, injectable};
14//!
15//! #[injectable]
16//! trait TestTrait {}
17//!
18//! #[derive(Component)]
19//! struct TestDependency;
20//!
21//! #[component_alias]
22//! impl TestTrait for TestDependency {}
23//!
24//! #[derive(Component)]
25//! #[component(names = ["dep2"])]
26//! struct TestComponent {
27//! // concrete type dependency
28//! dependency_1: ComponentInstancePtr<TestDependency>,
29//! // primary dyn Trait dependency - note Send + Sync when using the "threadsafe" feature
30//! dependency_2: ComponentInstancePtr<dyn TestTrait + Send + Sync>,
31//! // optional dependency - don't fail when not present
32//! optional_dependency: Option<ComponentInstancePtr<TestDependency>>,
33//! // all registered dependencies of a given type
34//! all_dependencies: Vec<ComponentInstancePtr<dyn TestTrait + Sync + Send>>,
35//! #[component(default)]
36//! default: i8,
37//! #[component(default = "dummy_expr")]
38//! default_expr: i8,
39//! }
40//!
41//! fn dummy_expr() -> i8 {
42//! -1
43//! }
44//! ```
45//!
46//! Please see the examples for more usage information.
47//!
48//! ### Supported `#[component]` struct configuration
49//!
50//! * `names = ["name"]` - use given name list as the component names, instead of the auto-generated
51//! one
52//! * `condition = "expr"` - call `expr()` and evaluate if given component should be registered; see
53//! [crate::component_registry::conditional]
54//! * `priority = number` - if a condition is present, use the given numerical priority to establish
55//! the order of registration in relation to other components with a condition (i8; higher is first;
56//! default is 0)
57//! * `constructor = "expr"` - call `expr(dependencies...)` to construct the component, instead of
58//! using standard struct construction; parameters must be in the same order as fields in the struct
59//! while non-injected fields can be ignored with the `#[component(ignore)]` attribute
60//! * `constructor_parameters = "params"` - additional injectable parameters for the above
61//! constructor; the "params" string consists of comma separated definitions in format:
62//! `(Type | Type/name | Option<Type> | Option<Type>/name | Vec<Type>)`, which means (in order):
63//! primary instance of `Type`, `name`d instance of `Type`, optional primary instance of `Type`,
64//! optional `name`d instance of `Type`, all instances of `Type`
65//! * `scope = "name"` - use the [scope](crate::scope) named `name` or
66//! [SINGLETON](crate::scope::SINGLETON) as default
67//!
68//! ### Supported `#[component]` field configuration
69//!
70//! * `default` - use `Default::default()` initialization
71//! * `default = "expr"` - call `expr()` for initialization
72//! * `name = "name"` - inject instance named as `name`
73//! * `ignore` - ignore the field when using custom constructor
74//!
75//! ## Registering component aliases
76//!
77//! Component aliases are different types, which can refer to a concrete component type. Usually
78//! they are simply `dyn Traits`, which makes it possible to inject an abstract `dyn Trait` type
79//! instead of a concrete component type. Each injectable trait should be marked as such, which can
80//! be done with the `#[injectable]` helper attribute.
81//!
82//! To automatically register a component alias, use the `#[component_alias]` attribute on a trait
83//! implementation:
84//!
85//! ```
86//! use springtime_di::{Component, component_alias, injectable};
87//!
88//! #[derive(Component)]
89//! struct SomeComponent;
90//!
91//! #[injectable]
92//! trait SomeTrait {
93//! }
94//!
95//! #[component_alias]
96//! impl SomeTrait for SomeComponent {
97//! }
98//! ```
99//!
100//! The above example shows how it's possible to inject both `ComponentInstancePtr<SomeComponent>`
101//! and `ComponentInstancePtr<dyn SomeTrait>`.
102//!
103//! ### Supported `#[component_alias]` arguments
104//!
105//! * `primary` - mark the concrete component, for which we're implementing the trait, as selected
106//! (primary) when requesting a single instance of `ComponentInstancePtr<dyn Trait>` and multiple
107//! components are available
108//! * `condition = "expr"` - call `expr()` and evaluate if given component should be registered; see
109//! [crate::component_registry::conditional]
110//! * `priority = number` - if a condition is present, use the given numerical priority to establish
111//! the order of registration in relation to other components with a condition (i8; higher
112//! is first; default is 0)
113//! * `scope = "name"` - use the [scope](crate::scope) named `name` to override the concrete
114//! component scope
115
116#[cfg(feature = "async")]
117use crate::future::BoxFuture;
118use crate::instance_provider::ComponentInstanceProviderError;
119use crate::instance_provider::{
120 ComponentInstanceAnyPtr, ComponentInstanceProvider, ComponentInstancePtr,
121};
122
123/// Base trait for components for dependency injection.
124///
125/// Components might depend on other components, which form the basis for dependency injection. To
126/// make the system work, your component instances must be wrapped in a [ComponentInstancePtr].
127/// Please see the module-level documentation for more information.
128pub trait Component: ComponentDowncast<Self> + Sized {
129 #[cfg(not(feature = "async"))]
130 /// Creates an instance of this component using dependencies from given [ComponentInstanceProvider].
131 fn create(
132 instance_provider: &mut dyn ComponentInstanceProvider,
133 ) -> Result<Self, ComponentInstanceProviderError>;
134
135 #[cfg(feature = "async")]
136 /// Creates an instance of this component using dependencies from given [ComponentInstanceProvider].
137 fn create(
138 instance_provider: &mut (dyn ComponentInstanceProvider + Sync + Send),
139 ) -> BoxFuture<'_, Result<Self, ComponentInstanceProviderError>>;
140}
141
142/// Helper trait for traits implemented by components, thus allowing injection of components based
143/// on `dyn Trait` types. The type `C` refers to a concrete component type. Typically automatically
144/// derived when using the `#[component_alias]` attribute.
145pub trait ComponentDowncast<C: Component>: Injectable {
146 fn downcast(
147 source: ComponentInstanceAnyPtr,
148 ) -> Result<ComponentInstancePtr<Self>, ComponentInstanceAnyPtr>;
149}
150
151/// Marker trait for injectable types - components and aliases.
152pub trait Injectable: 'static {}