1use crate::container::{ConstructFn, Container, Erased};
2use crate::graph::Graph;
3use crate::key::Key;
4use crate::{
5 BoxError, BuildError, BuildIssue, CastFrom, Dependency, Lifetime, Resolver, Service,
6 ServiceProvider,
7};
8use std::any::{Any, type_name};
9use std::fmt;
10use std::sync::Arc;
11
12#[derive(Debug, Default)]
49pub struct ServiceCollection {
50 registrations: Vec<Registration>,
51 validation: Validation,
52}
53
54#[derive(Debug, Default)]
56struct Validation {
57 dependencies: bool,
58 scopes: bool,
59}
60
61pub(crate) struct Registration {
62 pub(crate) key: Key,
63 pub(crate) implementation: &'static str,
66 pub(crate) lifetime: Lifetime,
67 pub(crate) source: Source,
68 pub(crate) dependencies: Option<fn() -> Vec<Dependency>>,
70 pub(crate) cast: Box<dyn Any + Send + Sync>,
72 pub(crate) slot: usize,
74}
75
76impl fmt::Debug for Registration {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 f.debug_struct("Registration")
79 .field("service", &self.key.name)
80 .field("implementation", &self.implementation)
81 .field("lifetime", &self.lifetime)
82 .finish_non_exhaustive()
83 }
84}
85
86pub(crate) enum Source {
87 Construct(ConstructFn),
88 Instance(Erased),
89}
90
91impl ServiceCollection {
92 pub fn new() -> Self {
94 Self::default()
95 }
96
97 pub fn add_singleton<T: Service>(&mut self) -> &mut Self {
99 self.add::<T>(Lifetime::Singleton)
100 }
101
102 pub fn add_scoped<T: Service>(&mut self) -> &mut Self {
104 self.add::<T>(Lifetime::Scoped)
105 }
106
107 pub fn add_transient<T: Service>(&mut self) -> &mut Self {
109 self.add::<T>(Lifetime::Transient)
110 }
111
112 pub fn add_singleton_as<I, T>(&mut self) -> &mut Self
118 where
119 I: ?Sized + CastFrom<T> + Send + Sync + 'static,
120 T: Service,
121 {
122 self.add_service::<I, T>(Lifetime::Singleton, trait_cast::<I, T>())
123 }
124
125 pub fn add_scoped_as<I, T>(&mut self) -> &mut Self
127 where
128 I: ?Sized + CastFrom<T> + Send + Sync + 'static,
129 T: Service,
130 {
131 self.add_service::<I, T>(Lifetime::Scoped, trait_cast::<I, T>())
132 }
133
134 pub fn add_transient_as<I, T>(&mut self) -> &mut Self
137 where
138 I: ?Sized + CastFrom<T> + Send + Sync + 'static,
139 T: Service,
140 {
141 self.add_service::<I, T>(Lifetime::Transient, trait_cast::<I, T>())
142 }
143
144 pub fn contains<T: ?Sized + 'static>(&self) -> bool {
149 let key = Key::of::<T>();
150 self.registrations
151 .iter()
152 .any(|registration| registration.key == key)
153 }
154
155 pub fn try_add_singleton<T: Service>(&mut self) -> &mut Self {
158 if self.contains::<T>() {
159 return self;
160 }
161 self.add_singleton::<T>()
162 }
163
164 pub fn try_add_scoped<T: Service>(&mut self) -> &mut Self {
167 if self.contains::<T>() {
168 return self;
169 }
170 self.add_scoped::<T>()
171 }
172
173 pub fn try_add_transient<T: Service>(&mut self) -> &mut Self {
176 if self.contains::<T>() {
177 return self;
178 }
179 self.add_transient::<T>()
180 }
181
182 pub fn try_add_singleton_as<I, T>(&mut self) -> &mut Self
185 where
186 I: ?Sized + CastFrom<T> + Send + Sync + 'static,
187 T: Service,
188 {
189 if self.contains::<I>() {
190 return self;
191 }
192 self.add_singleton_as::<I, T>()
193 }
194
195 pub fn try_add_scoped_as<I, T>(&mut self) -> &mut Self
198 where
199 I: ?Sized + CastFrom<T> + Send + Sync + 'static,
200 T: Service,
201 {
202 if self.contains::<I>() {
203 return self;
204 }
205 self.add_scoped_as::<I, T>()
206 }
207
208 pub fn try_add_transient_as<I, T>(&mut self) -> &mut Self
211 where
212 I: ?Sized + CastFrom<T> + Send + Sync + 'static,
213 T: Service,
214 {
215 if self.contains::<I>() {
216 return self;
217 }
218 self.add_transient_as::<I, T>()
219 }
220
221 pub fn add_singleton_with<T, F>(&mut self, factory: F) -> &mut Self
229 where
230 T: Send + Sync + 'static,
231 F: Fn(&Resolver<'_>) -> Result<T, BoxError> + Send + Sync + 'static,
232 {
233 self.add_factory(Lifetime::Singleton, factory)
234 }
235
236 pub fn add_scoped_with<T, F>(&mut self, factory: F) -> &mut Self
238 where
239 T: Send + Sync + 'static,
240 F: Fn(&Resolver<'_>) -> Result<T, BoxError> + Send + Sync + 'static,
241 {
242 self.add_factory(Lifetime::Scoped, factory)
243 }
244
245 pub fn add_transient_with<T, F>(&mut self, factory: F) -> &mut Self
247 where
248 T: Send + Sync + 'static,
249 F: Fn(&Resolver<'_>) -> Result<T, BoxError> + Send + Sync + 'static,
250 {
251 self.add_factory(Lifetime::Transient, factory)
252 }
253
254 pub fn add_singleton_instance<T: Send + Sync + 'static>(&mut self, instance: T) -> &mut Self {
256 self.push_unchecked::<T>(Lifetime::Singleton, Source::Instance(Arc::new(instance)))
257 }
258
259 pub fn add_singleton_as_with<I, F>(&mut self, factory: F) -> &mut Self
267 where
268 I: ?Sized + Send + Sync + 'static,
269 F: Fn(&Resolver<'_>) -> Result<Arc<I>, BoxError> + Send + Sync + 'static,
270 {
271 self.add_factory_as(Lifetime::Singleton, factory)
272 }
273
274 pub fn add_scoped_as_with<I, F>(&mut self, factory: F) -> &mut Self
277 where
278 I: ?Sized + Send + Sync + 'static,
279 F: Fn(&Resolver<'_>) -> Result<Arc<I>, BoxError> + Send + Sync + 'static,
280 {
281 self.add_factory_as(Lifetime::Scoped, factory)
282 }
283
284 pub fn add_transient_as_with<I, F>(&mut self, factory: F) -> &mut Self
290 where
291 I: ?Sized + Send + Sync + 'static,
292 F: Fn(&Resolver<'_>) -> Result<Arc<I>, BoxError> + Send + Sync + 'static,
293 {
294 self.add_factory_as(Lifetime::Transient, factory)
295 }
296
297 pub fn add_singleton_instance_as<I>(&mut self, instance: Arc<I>) -> &mut Self
299 where
300 I: ?Sized + Send + Sync + 'static,
301 {
302 self.push_trait_object::<I>(Lifetime::Singleton, Source::Instance(Arc::new(instance)))
303 }
304
305 pub fn validate_dependencies(&mut self) -> &mut Self {
312 self.validation.dependencies = true;
313 self
314 }
315
316 pub fn validate_scopes(&mut self) -> &mut Self {
323 self.validation.scopes = true;
324 self
325 }
326
327 pub fn build(self) -> Result<ServiceProvider, BuildError> {
332 let graph = Graph::new(&self.registrations);
333 let mut issues: Vec<BuildIssue> = graph
334 .cycles()
335 .into_iter()
336 .map(|path| BuildIssue::Cycle { path })
337 .collect();
338 if self.validation.dependencies {
339 issues.extend(
340 graph
341 .missing()
342 .into_iter()
343 .map(|path| BuildIssue::MissingDependency { path }),
344 );
345 }
346 if self.validation.scopes {
347 issues.extend(
348 graph
349 .captive()
350 .into_iter()
351 .map(|path| BuildIssue::CaptiveDependency { path }),
352 );
353 }
354 if !issues.is_empty() {
355 return Err(BuildError::new(issues));
356 }
357 Ok(ServiceProvider::new(Container::new(self.registrations)))
358 }
359
360 fn add<T: Service>(&mut self, lifetime: Lifetime) -> &mut Self {
361 self.add_service::<T, T>(lifetime, concrete_cast::<T>())
362 }
363
364 fn add_service<I: ?Sized + 'static, T: Service>(
365 &mut self,
366 lifetime: Lifetime,
367 cast: Cast,
368 ) -> &mut Self {
369 let construct: ConstructFn =
370 Arc::new(|resolver| T::construct(resolver).map(|service| Arc::new(service) as Erased));
371 self.push(Registration {
372 key: Key::of::<I>(),
373 implementation: type_name::<T>(),
374 lifetime,
375 source: Source::Construct(construct),
376 dependencies: Some(T::dependencies),
377 cast,
378 slot: 0,
379 })
380 }
381
382 fn add_factory<T, F>(&mut self, lifetime: Lifetime, factory: F) -> &mut Self
383 where
384 T: Send + Sync + 'static,
385 F: Fn(&Resolver<'_>) -> Result<T, BoxError> + Send + Sync + 'static,
386 {
387 self.push_unchecked::<T>(lifetime, Source::Construct(factory_construct(factory)))
388 }
389
390 fn push_unchecked<T: Send + Sync + 'static>(
392 &mut self,
393 lifetime: Lifetime,
394 source: Source,
395 ) -> &mut Self {
396 let key = Key::of::<T>();
397 self.push(Registration {
398 key,
399 implementation: key.name,
400 lifetime,
401 source,
402 dependencies: None,
403 cast: concrete_cast::<T>(),
404 slot: 0,
405 })
406 }
407
408 fn add_factory_as<I, F>(&mut self, lifetime: Lifetime, factory: F) -> &mut Self
409 where
410 I: ?Sized + Send + Sync + 'static,
411 F: Fn(&Resolver<'_>) -> Result<Arc<I>, BoxError> + Send + Sync + 'static,
412 {
413 self.push_trait_object::<I>(lifetime, Source::Construct(factory_construct(factory)))
414 }
415
416 fn push_trait_object<I>(&mut self, lifetime: Lifetime, source: Source) -> &mut Self
419 where
420 I: ?Sized + Send + Sync + 'static,
421 {
422 let key = Key::of::<I>();
423 let cast: fn(Erased) -> Option<Arc<I>> = |instance| {
424 instance
425 .downcast::<Arc<I>>()
426 .ok()
427 .map(|arc| Arc::clone(arc.as_ref()))
428 };
429 self.push(Registration {
430 key,
431 implementation: key.name,
432 lifetime,
433 source,
434 dependencies: None,
435 cast: Box::new(cast),
436 slot: 0,
437 })
438 }
439
440 fn push(&mut self, registration: Registration) -> &mut Self {
441 self.registrations.push(registration);
442 self
443 }
444}
445
446fn factory_construct<T, F>(factory: F) -> ConstructFn
449where
450 T: Send + Sync + 'static,
451 F: Fn(&Resolver<'_>) -> Result<T, BoxError> + Send + Sync + 'static,
452{
453 Arc::new(move |resolver| match factory(resolver) {
454 Ok(service) => Ok(Arc::new(service) as Erased),
455 Err(error) => Err(resolver.failure(error)),
456 })
457}
458
459type Cast = Box<dyn Any + Send + Sync>;
461
462fn trait_cast<I, T>() -> Cast
463where
464 I: ?Sized + CastFrom<T> + 'static,
465 T: Send + Sync + 'static,
466{
467 let cast: fn(Erased) -> Option<Arc<I>> = |instance| instance.downcast::<T>().ok().map(I::cast);
468 Box::new(cast)
469}
470
471fn concrete_cast<T: Send + Sync + 'static>() -> Cast {
472 let cast: fn(Erased) -> Option<Arc<T>> = |instance| instance.downcast().ok();
473 Box::new(cast)
474}