1use crate::collection::{Registration, Source};
2use crate::container::{Container, Erased, Slots};
3use crate::key::Key;
4use crate::scope::ScopeState;
5use crate::sync::ConstructionLock;
6use crate::{BoxError, Lifetime, ResolveError};
7use std::cell::RefCell;
8use std::fmt;
9use std::ptr;
10use std::sync::Arc;
11
12pub struct Resolver<'a> {
21 container: &'a Container,
22 scope: Option<&'a ScopeState>,
23 parent: Option<&'a Resolver<'a>>,
24 service: Option<&'a Registration>,
25}
26
27impl fmt::Debug for Resolver<'_> {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f.debug_struct("Resolver")
30 .field("constructing", &self.path())
31 .finish_non_exhaustive()
32 }
33}
34
35impl<'a> Resolver<'a> {
36 pub(crate) fn root(container: &'a Container) -> Self {
37 Self {
38 container,
39 scope: None,
40 parent: None,
41 service: None,
42 }
43 }
44
45 pub(crate) fn scoped(container: &'a Container, scope: &'a ScopeState) -> Self {
46 Self {
47 container,
48 scope: Some(scope),
49 parent: None,
50 service: None,
51 }
52 }
53
54 pub fn resolve<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, ResolveError> {
59 let key = Key::of::<T>();
60 let Some(registration) = self.container.registration(key) else {
61 return Err(ResolveError::NotRegistered {
62 path: self.path_to(key),
63 });
64 };
65
66 let instance = self.instance(registration)?;
67 self.cast(registration, instance)
68 }
69
70 pub fn resolve_all<T: ?Sized + Send + Sync + 'static>(
73 &self,
74 ) -> Result<Vec<Arc<T>>, ResolveError> {
75 let registrations = self.container.registrations_of(Key::of::<T>());
76 let mut all = Vec::with_capacity(registrations.len());
77 for registration in registrations {
78 let instance = self.instance(registration)?;
79 all.push(self.cast(registration, instance)?);
80 }
81 Ok(all)
82 }
83
84 pub fn construction_error(&self, source: impl Into<BoxError>) -> ResolveError {
86 ResolveError::Construction {
87 path: self.path(),
88 source: source.into(),
89 }
90 }
91
92 pub(crate) fn failure(&self, error: BoxError) -> ResolveError {
95 match error.downcast::<ResolveError>() {
96 Ok(error) => *error,
97 Err(error) => self.construction_error(error),
98 }
99 }
100
101 fn instance(&self, registration: &Registration) -> Result<Erased, ResolveError> {
102 match registration.lifetime {
103 Lifetime::Singleton => self.singleton(registration),
104 Lifetime::Scoped => self.scoped_instance(registration),
105 Lifetime::Transient => self.construct(registration, self.scope),
106 }
107 }
108
109 fn cast<T: ?Sized + 'static>(
110 &self,
111 registration: &Registration,
112 instance: Erased,
113 ) -> Result<Arc<T>, ResolveError> {
114 registration
115 .cast
116 .downcast_ref::<fn(Erased) -> Option<Arc<T>>>()
117 .and_then(|cast| cast(instance))
118 .ok_or_else(|| ResolveError::NotRegistered {
119 path: self.path_to(registration.key),
120 })
121 }
122
123 fn singleton(&self, registration: &Registration) -> Result<Erased, ResolveError> {
124 let container = self.container;
125 self.cached(
126 registration,
127 &container.singletons,
128 &container.construction,
129 None,
130 )
131 }
132
133 fn scoped_instance(&self, registration: &Registration) -> Result<Erased, ResolveError> {
134 let Some(scope) = self.scope else {
135 let mut path = self.path();
138 path.push(registration.implementation);
139 return Err(ResolveError::ScopedFromRoot { path });
140 };
141 self.cached(
142 registration,
143 scope.slots(self.container),
144 &scope.construction,
145 Some(scope),
146 )
147 }
148
149 fn cached(
152 &self,
153 registration: &Registration,
154 slots: &Slots,
155 lock: &ConstructionLock,
156 scope: Option<&ScopeState>,
157 ) -> Result<Erased, ResolveError> {
158 if let Some(instance) = slots.get(registration.slot) {
159 return Ok(instance);
160 }
161
162 let _guard = lock.lock();
163 if let Some(instance) = slots.get(registration.slot) {
164 return Ok(instance);
165 }
166 let instance = self.construct(registration, scope)?;
167 slots.fill(registration.slot, Arc::clone(&instance));
168 Ok(instance)
169 }
170
171 fn construct(
172 &self,
173 registration: &'a Registration,
174 scope: Option<&'a ScopeState>,
175 ) -> Result<Erased, ResolveError> {
176 let _constructing =
177 Constructing::enter(registration).map_err(|path| ResolveError::Cycle { path })?;
178 let frame = Resolver {
179 container: self.container,
180 scope,
181 parent: Some(self),
182 service: Some(registration),
183 };
184 let result = match ®istration.source {
185 Source::Construct(construct) => construct(&frame),
186 Source::Instance(instance) => Ok(Arc::clone(instance)),
187 };
188
189 #[cfg(feature = "logging")]
190 match &result {
191 Ok(_) => tracing::debug!(
192 service = registration.implementation,
193 lifetime = ?registration.lifetime,
194 "constructed service"
195 ),
196 Err(error) => tracing::debug!(
197 service = registration.implementation,
198 lifetime = ?registration.lifetime,
199 %error,
200 "service construction failed"
201 ),
202 }
203
204 result
205 }
206
207 fn path(&self) -> Vec<&'static str> {
209 let mut path = Vec::new();
210 let mut frame = Some(self);
211 while let Some(current) = frame {
212 if let Some(service) = current.service {
213 path.push(service.implementation);
214 }
215 frame = current.parent;
216 }
217 path.reverse();
218 path
219 }
220
221 fn path_to(&self, key: Key) -> Vec<&'static str> {
222 let mut path = self.path();
223 path.push(key.name);
224 path
225 }
226}
227
228thread_local! {
229 static CONSTRUCTING: RefCell<Vec<(*const Registration, &'static str)>> =
235 const { RefCell::new(Vec::new()) };
236}
237
238struct Constructing;
240
241impl Constructing {
242 fn enter(registration: &Registration) -> Result<Self, Vec<&'static str>> {
245 let this: *const Registration = registration;
246 CONSTRUCTING.with_borrow_mut(|stack| {
247 if let Some(start) = stack.iter().position(|&(entry, _)| ptr::eq(entry, this)) {
248 let mut path: Vec<_> = stack[start..].iter().map(|&(_, name)| name).collect();
249 path.push(registration.implementation);
250 return Err(path);
251 }
252 stack.push((this, registration.implementation));
253 Ok(Constructing)
254 })
255 }
256}
257
258impl Drop for Constructing {
259 fn drop(&mut self) {
260 CONSTRUCTING.with_borrow_mut(|stack| {
261 stack.pop();
262 });
263 }
264}