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