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
use super::*;
impl<T: ?Sized + 'static> Provider<T> {
/// Applies resource limits to this provider.
pub fn with_limits(mut self, limits: Limits) -> Self {
self.limits = limits;
self.limiter = Limiter::from_limits(limits);
self
}
pub(crate) fn acquire_creation_permit(
&self,
type_name: &str,
) -> Result<Option<CreationPermit>, Error> {
if let Some(limiter) = &self.limiter {
return Limiter::try_acquire(limiter, type_name).map(Some);
}
Ok(None)
}
#[cfg(feature = "async-factory")]
pub(crate) async fn acquire_creation_permit_async(
&self,
type_name: &str,
) -> Result<Option<CreationPermit>, Error> {
if let Some(limiter) = &self.limiter {
#[cfg(all(feature = "thread-safe", feature = "resource-limit-async"))]
{
return Limiter::try_acquire_async(limiter, type_name)
.await
.map(Some);
}
#[cfg(not(all(feature = "thread-safe", feature = "resource-limit-async")))]
{
return Limiter::try_acquire(limiter, type_name).map(Some);
}
}
Ok(None)
}
/// Declares that this provider depends on a single service `D`.
///
/// This hint is used by graph tooling (`dependency_graph`, `validate_graph`)
/// and does not change runtime resolution behavior.
pub fn with_dependency<D>(mut self) -> Self
where
D: ?Sized + 'static,
{
self.dependency_hints.push(DependencyHint::one::<D>());
self
}
/// Declares that this provider depends on a named service `D`.
///
/// This hint is used by graph tooling (`dependency_graph`, `validate_graph`)
/// and does not change runtime resolution behavior.
pub fn with_named_dependency<D>(mut self, name: impl Into<String>) -> Self
where
D: ?Sized + 'static,
{
self.dependency_hints
.push(DependencyHint::named::<D>(name.into()));
self
}
/// Declares that this provider depends on all set bindings of service `D`.
///
/// This hint is used by graph tooling (`dependency_graph`, `validate_graph`)
/// and does not change runtime resolution behavior.
pub fn with_set_dependency<D>(mut self) -> Self
where
D: ?Sized + 'static,
{
self.dependency_hints.push(DependencyHint::all::<D>());
self
}
/// Wraps resolved instances with a decorator (e.g. logging, caching).
///
/// The decorator receives the base instance and returns a wrapped instance.
/// Order is deterministic: base factory runs first, then decorator.
///
/// For multiple decorators, chain: `provider.with_decorator(d1).with_decorator(d2)`.
#[cfg(not(feature = "thread-safe"))]
pub fn with_decorator<F>(self, decorator: F) -> Self
where
F: Fn(Shared<T>) -> Shared<T> + 'static,
{
let Self {
scope,
factory,
#[cfg(feature = "async-factory")]
async_factory,
limits,
dependency_hints,
limiter,
} = self;
Self {
scope,
factory: Box::new(move |inj| {
let instance = factory(inj);
Instance::new(decorator(instance.value()))
}),
#[cfg(feature = "async-factory")]
async_factory,
limits,
dependency_hints,
limiter,
}
}
/// Wraps resolved instances with a decorator (thread-safe).
#[cfg(feature = "thread-safe")]
pub fn with_decorator<F>(self, decorator: F) -> Self
where
F: Fn(Shared<T>) -> Shared<T> + Send + Sync + 'static,
{
let Self {
scope,
factory,
#[cfg(feature = "async-factory")]
async_factory,
limits,
dependency_hints,
limiter,
} = self;
Self {
scope,
factory: Box::new(move |inj| {
let instance = factory(inj);
Instance::new(decorator(instance.value()))
}),
#[cfg(feature = "async-factory")]
async_factory,
limits,
dependency_hints,
limiter,
}
}
}