1use crate::{fmt, validate, Ref, ServiceDescriptor, ServiceDescriptorBuilder, ServiceProvider, Type, ValidationError};
2use std::any::Any;
3use std::collections::HashMap;
4use std::fmt::{Formatter, Result as FormatResult};
5use std::iter::{DoubleEndedIterator, ExactSizeIterator};
6use std::ops::Index;
7use std::slice::{Iter, IterMut};
8use std::vec::IntoIter;
9
10macro_rules! decorate {
11 (($($traits:tt)+), ($($bounds:tt)+)) => {
12 pub fn decorate<TSvc: ?Sized + $($traits)+, TImpl>(
64 &mut self,
65 activate: impl Fn(&ServiceProvider, Ref<TSvc>) -> Ref<TSvc> + $($bounds)+,
66 ) -> &mut Self {
67 let service_type = Type::of::<TSvc>();
68
69 for item in self.items.iter_mut().rev() {
70 if item.service_type() != service_type {
71 continue;
72 }
73
74 let impl_type = Type::of::<TImpl>();
75
76 if item.implementation_type() == impl_type {
77 return self;
78 }
79
80 let original = item.clone();
81 let builder = ServiceDescriptorBuilder::<TSvc, TImpl>::new(original.lifetime(), impl_type);
82
83 *item = builder.from(move |sp| {
84 let decorated = original.get(sp).downcast_ref::<Ref<TSvc>>().unwrap().clone();
85 activate(sp, decorated)
86 });
87
88 break;
89 }
90
91 self
92 }
93
94 pub fn decorate_all<TSvc: ?Sized + $($traits)+, TImpl>(
177 &mut self,
178 activate: impl Fn(&ServiceProvider, Ref<TSvc>) -> Ref<TSvc> + $($bounds)+,
179 ) -> &mut Self {
180 let service_type = Type::of::<TSvc>();
181 let func = Ref::new(activate);
182
183 for item in self.items.iter_mut() {
184 let impl_type = Type::of::<TImpl>();
185
186 if item.service_type() != service_type || item.implementation_type() == impl_type {
187 continue;
188 }
189
190 let original = item.clone();
191 let activate = func.clone();
192 let builder = ServiceDescriptorBuilder::<TSvc, TImpl>::new(original.lifetime(), impl_type);
193
194 *item = builder.from(move |sp| {
195 let decorated = original.get(sp).downcast_ref::<Ref<TSvc>>().unwrap().clone();
196 (activate)(sp, decorated)
197 });
198 }
199
200 self
201 }
202 };
203}
204
205#[derive(Default)]
207pub struct ServiceCollection {
208 items: Vec<ServiceDescriptor>,
209}
210
211impl ServiceCollection {
212 #[inline]
214 pub fn new() -> Self {
215 Self::default()
216 }
217
218 #[inline]
220 pub fn is_empty(&self) -> bool {
221 self.items.is_empty()
222 }
223
224 #[inline]
226 pub fn len(&self) -> usize {
227 self.items.len()
228 }
229
230 #[inline]
232 pub fn clear(&mut self) {
233 self.items.clear()
234 }
235
236 #[inline]
246 pub fn remove(&mut self, index: usize) -> ServiceDescriptor {
247 self.items.remove(index)
248 }
249
250 pub fn add<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
256 self.items.push(descriptor.into());
257 self
258 }
259
260 pub fn try_add<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
266 let new_item = descriptor.into();
267 let service_type = new_item.service_type();
268
269 for item in &self.items {
270 if item.service_type() == service_type {
271 return self;
272 }
273 }
274
275 self.items.push(new_item);
276 self
277 }
278
279 pub fn try_add_to_all<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
286 let new_item = descriptor.into();
287 let service_type = new_item.service_type();
288 let implementation_type = new_item.implementation_type();
289
290 if service_type == implementation_type {
291 return self;
292 }
293
294 for item in &self.items {
295 if item.service_type() == service_type && item.implementation_type() == implementation_type {
296 return self;
297 }
298 }
299
300 self.items.push(new_item);
301 self
302 }
303
304 pub fn try_add_all(&mut self, descriptors: impl IntoIterator<Item = ServiceDescriptor>) -> &mut Self {
311 for descriptor in descriptors {
312 self.try_add_to_all(descriptor);
313 }
314 self
315 }
316
317 pub fn replace<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
323 let new_item = descriptor.into();
324 let service_type = new_item.service_type();
325
326 for i in 0..self.items.len() {
327 if self.items[i].service_type() == service_type {
328 self.items.remove(i);
329 break;
330 }
331 }
332
333 self.items.push(new_item);
334 self
335 }
336
337 #[inline]
343 pub fn try_replace<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
344 self.try_add(descriptor)
345 }
346
347 pub fn remove_all<T: Any + ?Sized>(&mut self) -> &mut Self {
349 let service_type = Type::of::<T>();
350
351 for i in (0..self.items.len()).rev() {
352 if self.items[i].service_type() == service_type {
353 self.items.remove(i);
354 }
355 }
356
357 self
358 }
359
360 pub fn build_provider(&self) -> Result<ServiceProvider, ValidationError> {
362 validate(self)?;
363
364 let mut services = HashMap::with_capacity(self.items.len());
365
366 for item in &self.items {
367 let key = item.service_type().clone();
368 let descriptors = services.entry(key).or_insert_with(Vec::new);
369
370 descriptors.push(item.clone_with(false));
374 }
375
376 for values in services.values_mut() {
377 values.shrink_to_fit();
378 }
379
380 services.shrink_to_fit();
381 Ok(ServiceProvider::new(services))
382 }
383
384 #[inline]
386 pub fn iter(&self) -> impl ExactSizeIterator<Item = &ServiceDescriptor> + DoubleEndedIterator {
387 self.items.iter()
388 }
389
390 cfg_if::cfg_if! {
391 if #[cfg(feature = "async")] {
392 decorate!((Any + Send + Sync), (Send + Sync + 'static));
393 } else {
394 decorate!((Any), ('static));
395 }
396 }
397}
398
399impl<'a> IntoIterator for &'a ServiceCollection {
400 type Item = &'a ServiceDescriptor;
401 type IntoIter = Iter<'a, ServiceDescriptor>;
402
403 fn into_iter(self) -> Self::IntoIter {
404 self.items.iter()
405 }
406}
407
408impl<'a> IntoIterator for &'a mut ServiceCollection {
409 type Item = &'a mut ServiceDescriptor;
410 type IntoIter = IterMut<'a, ServiceDescriptor>;
411
412 fn into_iter(self) -> Self::IntoIter {
413 self.items.iter_mut()
414 }
415}
416
417impl IntoIterator for ServiceCollection {
418 type Item = ServiceDescriptor;
419 type IntoIter = IntoIter<Self::Item>;
420
421 fn into_iter(self) -> Self::IntoIter {
422 self.items.into_iter()
423 }
424}
425
426impl Index<usize> for ServiceCollection {
427 type Output = ServiceDescriptor;
428
429 fn index(&self, index: usize) -> &Self::Output {
430 &self.items[index]
431 }
432}
433
434impl std::fmt::Debug for ServiceCollection {
435 fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
436 fmt::write(self, fmt::text::Renderer, f)
437 }
438}
439
440impl std::fmt::Display for ServiceCollection {
441 fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
442 cfg_if::cfg_if! {
443 if #[cfg(feature = "fmt")] {
444 if f.alternate() {
445 return fmt::write(self, fmt::terminal::Renderer, f);
446 }
447 }
448 }
449
450 fmt::write(self, fmt::text::Renderer, f)
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457 use crate::{existing, existing_as_self, singleton, singleton_as_self, test::*, transient};
458 use std::fs::remove_file;
459 use std::path::{Path, PathBuf};
460
461 #[test]
462 fn is_empty_should_return_true_when_empty() {
463 let collection = ServiceCollection::default();
465
466 let empty = collection.is_empty();
468
469 assert!(empty);
471 }
472
473 #[test]
474 fn length_should_return_zero_when_empty() {
475 let collection = ServiceCollection::default();
477
478 let length = collection.len();
480
481 assert_eq!(length, 0);
483 }
484
485 #[test]
486 fn is_empty_should_return_false_when_not_empty() {
487 let descriptor = existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
489 let mut collection = ServiceCollection::new();
490
491 collection.add(descriptor);
492
493 let not_empty = !collection.is_empty();
495
496 assert!(not_empty);
498 }
499
500 #[test]
501 fn length_should_return_count_when_not_empty() {
502 let descriptor = existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
504 let mut collection = ServiceCollection::new();
505
506 collection.add(descriptor);
507
508 let length = collection.len();
510
511 assert_eq!(length, 1);
513 }
514
515 #[test]
516 fn clear_should_remove_all_elements() {
517 let descriptor = existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
519 let mut collection = ServiceCollection::new();
520
521 collection.add(descriptor);
522
523 collection.clear();
525
526 assert!(collection.is_empty());
528 }
529
530 #[test]
531 fn try_add_should_do_nothing_when_service_is_registered() {
532 let mut collection = ServiceCollection::new();
534
535 collection.add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())));
536
537 collection
539 .try_add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())));
540
541 assert_eq!(collection.len(), 1);
543 }
544
545 #[test]
546 fn try_add_to_all_should_add_descriptor_when_implementation_is_unregistered() {
547 let mut collection = ServiceCollection::new();
549
550 collection.add(existing::<dyn TestService, TestServiceImpl>(Box::new(
551 TestServiceImpl::default(),
552 )));
553
554 collection.try_add_to_all(
555 singleton::<dyn OtherTestService, OtherTestServiceImpl>()
556 .from(|sp| Ref::new(OtherTestServiceImpl::new(sp.get_required::<dyn TestService>()))),
557 );
558
559 let count = collection.len();
561
562 assert_eq!(count, 2);
564 }
565
566 #[test]
567 fn try_add_to_all_should_not_add_descriptor_when_implementation_is_registered() {
568 let mut collection = ServiceCollection::new();
570
571 collection.add(existing::<dyn TestService, TestServiceImpl>(Box::new(
572 TestServiceImpl::default(),
573 )));
574
575 collection.try_add_to_all(
576 transient::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())),
577 );
578
579 let count = collection.len();
581
582 assert_eq!(count, 1);
584 }
585
586 #[test]
587 fn try_add_all_should_only_add_descriptors_for_unregistered_implementations() {
588 let descriptors = vec![
590 existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default())),
591 transient::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())),
592 ];
593 let mut collection = ServiceCollection::new();
594
595 collection.try_add_all(descriptors.into_iter());
596
597 let count = collection.len();
599
600 assert_eq!(count, 1);
602 }
603
604 #[test]
605 fn replace_should_replace_first_registered_service() {
606 let mut collection = ServiceCollection::new();
608
609 collection
610 .add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())))
611 .add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())));
612
613 collection
615 .replace(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())));
616
617 assert_eq!(collection.len(), 2);
619 }
620
621 #[test]
622 fn remove_all_should_remove_registered_services() {
623 let mut collection = ServiceCollection::new();
625
626 collection
627 .add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())))
628 .add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl::default())));
629
630 collection.remove_all::<dyn TestService>();
632
633 assert!(collection.is_empty());
635 }
636
637 #[test]
638 fn try_replace_should_do_nothing_when_service_is_registered() {
639 let mut collection = ServiceCollection::new();
641
642 collection
643 .add(singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl { value: 1 })));
644
645 collection.try_replace(
647 singleton::<dyn TestService, TestServiceImpl>().from(|_| Ref::new(TestServiceImpl { value: 2 })),
648 );
649
650 let value = collection
652 .build_provider()
653 .unwrap()
654 .get_required::<dyn TestService>()
655 .value();
656 assert_eq!(value, 1);
657 }
658
659 #[test]
660 fn remove_should_remove_element_at_index() {
661 let descriptor = existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
663 let mut collection = ServiceCollection::new();
664
665 collection.add(descriptor);
666
667 let _ = collection.remove(0);
669
670 assert!(collection.is_empty());
672 }
673
674 #[test]
675 fn service_collection_should_drop_existing_as_service() {
676 let file = new_temp_file("drop1");
678
679 {
681 let mut services = ServiceCollection::new();
682 services.add(existing_as_self(Droppable::new(file.clone())));
683 }
684
685 let dropped = !file.exists();
687 remove_file(&file).ok();
688 assert!(dropped);
689 }
690
691 #[test]
692 fn service_collection_should_not_drop_service_if_never_instantiated() {
693 let file = new_temp_file("drop4");
695 let mut services = ServiceCollection::new();
696
697 {
699 services
700 .add(existing::<Path, PathBuf>(file.clone().into_boxed_path()))
701 .add(singleton_as_self().from(|sp| Ref::new(Droppable::new(sp.get_required::<Path>().to_path_buf()))));
702 }
703
704 let not_dropped = file.exists();
706 remove_file(&file).ok();
707 assert!(not_dropped);
708 }
709}