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 {}