1use crate::{
2 validate, ServiceCardinality, ServiceDescriptor, ServiceLifetime, ServiceProvider, Type,
3 ValidationError,
4};
5use std::any::Any;
6use std::collections::HashMap;
7use std::fmt::{Formatter, Result as FormatResult, Write};
8use std::iter::{DoubleEndedIterator, ExactSizeIterator};
9use std::ops::Index;
10use std::slice::{Iter, IterMut};
11use std::vec::IntoIter;
12
13#[cfg(feature = "fmt")]
14use colored::Colorize;
15
16#[cfg(feature = "fmt")]
17use std::fmt::Display;
18
19#[derive(Default)]
21pub struct ServiceCollection {
22 items: Vec<ServiceDescriptor>,
23}
24
25impl ServiceCollection {
26 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn is_empty(&self) -> bool {
33 self.items.is_empty()
34 }
35
36 pub fn len(&self) -> usize {
38 self.items.len()
39 }
40
41 pub fn clear(&mut self) {
43 self.items.clear()
44 }
45
46 pub fn remove(&mut self, index: usize) -> ServiceDescriptor {
56 self.items.remove(index)
57 }
58
59 pub fn add<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
65 self.items.push(descriptor.into());
66 self
67 }
68
69 pub fn try_add<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
75 let new_item = descriptor.into();
76 let service_type = new_item.service_type();
77
78 for item in &self.items {
79 if item.service_type() == service_type {
80 return self;
81 }
82 }
83
84 self.items.push(new_item);
85 self
86 }
87
88 pub fn try_add_to_all<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
95 let new_item = descriptor.into();
96 let service_type = new_item.service_type();
97 let implementation_type = new_item.implementation_type();
98
99 if service_type == implementation_type {
100 return self;
101 }
102
103 for item in &self.items {
104 if item.service_type() == service_type
105 && item.implementation_type() == implementation_type
106 {
107 return self;
108 }
109 }
110
111 self.items.push(new_item);
112 self
113 }
114
115 pub fn try_add_all(
122 &mut self,
123 descriptors: impl IntoIterator<Item = ServiceDescriptor>,
124 ) -> &mut Self {
125 for descriptor in descriptors {
126 self.try_add_to_all(descriptor);
127 }
128 self
129 }
130
131 pub fn replace<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
137 let new_item = descriptor.into();
138 let service_type = new_item.service_type();
139
140 for i in 0..self.items.len() {
141 if self.items[i].service_type() == service_type {
142 self.items.remove(i);
143 break;
144 }
145 }
146
147 self.items.push(new_item);
148 self
149 }
150
151 pub fn try_replace<T: Into<ServiceDescriptor>>(&mut self, descriptor: T) -> &mut Self {
157 self.try_add(descriptor)
158 }
159
160 pub fn remove_all<T: Any + ?Sized>(&mut self) -> &mut Self {
162 let service_type = Type::of::<T>();
163
164 for i in (0..self.items.len()).rev() {
165 if self.items[i].service_type() == service_type {
166 self.items.remove(i);
167 }
168 }
169
170 self
171 }
172
173 pub fn build_provider(&self) -> Result<ServiceProvider, ValidationError> {
175 if let Err(error) = validate(self) {
176 return Err(error);
177 }
178
179 let mut services = HashMap::with_capacity(self.items.len());
180
181 for item in &self.items {
182 let key = item.service_type().clone();
183 let descriptors = services.entry(key).or_insert_with(Vec::new);
184
185 descriptors.push(item.clone_with(false));
189 }
190
191 for values in services.values_mut() {
192 values.shrink_to_fit();
193 }
194
195 services.shrink_to_fit();
196 Ok(ServiceProvider::new(services))
197 }
198
199 pub fn iter(
201 &self,
202 ) -> impl Iterator<Item = &ServiceDescriptor> + ExactSizeIterator + DoubleEndedIterator {
203 self.items.iter()
204 }
205}
206
207impl<'a> IntoIterator for &'a ServiceCollection {
208 type Item = &'a ServiceDescriptor;
209 type IntoIter = Iter<'a, ServiceDescriptor>;
210
211 fn into_iter(self) -> Self::IntoIter {
212 self.items.iter()
213 }
214}
215
216impl<'a> IntoIterator for &'a mut ServiceCollection {
217 type Item = &'a mut ServiceDescriptor;
218 type IntoIter = IterMut<'a, ServiceDescriptor>;
219
220 fn into_iter(self) -> Self::IntoIter {
221 self.items.iter_mut()
222 }
223}
224
225impl IntoIterator for ServiceCollection {
226 type Item = ServiceDescriptor;
227 type IntoIter = IntoIter<Self::Item>;
228
229 fn into_iter(self) -> Self::IntoIter {
230 self.items.into_iter()
231 }
232}
233
234impl Index<usize> for ServiceCollection {
235 type Output = ServiceDescriptor;
236
237 fn index(&self, index: usize) -> &Self::Output {
238 &self.items[index]
239 }
240}
241
242impl std::fmt::Debug for ServiceCollection {
243 fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
244 print(self, TextRenderer::default(), f)
245 }
246}
247
248#[cfg(feature = "fmt")]
249impl Display for ServiceCollection {
250 fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
251 print(self, TerminalRenderer::default(), f)
252 }
253}
254
255trait Renderer {
256 fn write(&mut self, ch: char, f: &mut Formatter<'_>) -> FormatResult {
257 f.write_char(ch)
258 }
259
260 fn write_str<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
261 f.write_str(text.as_ref())
262 }
263
264 fn service<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
265 f.write_str(text.as_ref())
266 }
267
268 fn implementation<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
269 f.write_str(text.as_ref())
270 }
271
272 fn keyword<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
273 f.write_str(text.as_ref())
274 }
275
276 fn info<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
277 f.write_str(text.as_ref())
278 }
279
280 fn warn<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
281 f.write_str(text.as_ref())
282 }
283
284 fn error<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
285 f.write_str(text.as_ref())
286 }
287
288 fn accent<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
289 f.write_str(text.as_ref())
290 }
291}
292
293#[derive(Default)]
294struct TextRenderer;
295
296impl Renderer for TextRenderer {}
297
298#[cfg(feature = "fmt")]
299#[derive(Default)]
300struct TerminalRenderer;
301
302#[cfg(feature = "fmt")]
303impl Renderer for TerminalRenderer {
304 fn write(&mut self, ch: char, f: &mut Formatter<'_>) -> FormatResult {
305 f.write_char(ch)
306 }
307
308 fn write_str<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
309 f.write_str(text.as_ref())
310 }
311
312 fn keyword<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
313 text.as_ref().truecolor(75, 154, 214).fmt(f)
314 }
315
316 fn service<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
317 text.as_ref().truecolor(158, 211, 163).fmt(f)
318 }
319
320 fn implementation<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
321 text.as_ref().truecolor(78, 201, 176).fmt(f)
322 }
323
324 fn info<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
325 text.as_ref().truecolor(118, 118, 118).fmt(f)
326 }
327
328 fn warn<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
329 text.as_ref().truecolor(220, 220, 170).fmt(f)
330 }
331
332 fn error<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
333 text.as_ref().truecolor(231, 72, 86).fmt(f)
334 }
335
336 fn accent<T: AsRef<str>>(&mut self, text: T, f: &mut Formatter<'_>) -> FormatResult {
337 text.as_ref().truecolor(218, 112, 179).fmt(f)
338 }
339}
340
341enum PrintItem<'a> {
342 One(&'a ServiceDescriptor),
343 Many((&'a Type, &'a str, &'a Vec<&'a ServiceDescriptor>)),
344 Warning((&'a Type, &'a str)),
345 Error((&'a Type, &'a str)),
346}
347
348struct PrintContext<'a> {
349 scope: ServiceLifetime,
350 visited: Vec<&'a ServiceDescriptor>,
351 lookup: &'a HashMap<&'a Type, Vec<&'a ServiceDescriptor>>,
352}
353
354impl<'a> PrintContext<'a> {
355 fn new(lookup: &'a HashMap<&'a Type, Vec<&'a ServiceDescriptor>>) -> Self {
356 Self {
357 scope: ServiceLifetime::Transient,
358 visited: Vec::new(),
359 lookup,
360 }
361 }
362
363 fn reset(&mut self, descriptor: &'a ServiceDescriptor) {
364 self.scope = descriptor.lifetime();
365 self.visited.clear();
366 self.visited.push(descriptor);
367 }
368
369 fn lookup(&self, key: &Type) -> Option<&'a Vec<&'a ServiceDescriptor>> {
370 self.lookup.get(key)
371 }
372
373 fn enter(&mut self, descriptor: &'a ServiceDescriptor) {
374 if self.scope != ServiceLifetime::Singleton
375 && descriptor.lifetime() == ServiceLifetime::Singleton
376 {
377 self.scope = ServiceLifetime::Singleton;
378 }
379
380 self.visited.push(descriptor);
381 }
382
383 fn exit(&mut self) {
384 self.visited.pop();
385
386 for item in self.visited.iter().rev() {
387 self.scope = item.lifetime();
388
389 if self.scope == ServiceLifetime::Singleton {
390 return;
391 }
392 }
393
394 self.scope = self
395 .visited
396 .last()
397 .map_or(ServiceLifetime::Transient, |s| s.lifetime());
398 }
399
400 fn is_circular_ref(&self, descriptor: &ServiceDescriptor) -> bool {
401 for item in self.visited.iter().rev() {
402 if item.service_type() == descriptor.service_type() {
403 return true;
404 }
405 }
406
407 false
408 }
409
410 fn is_invalid_lifetime(&self, descriptor: &ServiceDescriptor) -> bool {
411 self.scope == ServiceLifetime::Singleton && descriptor.lifetime() == ServiceLifetime::Scoped
412 }
413}
414
415fn print<R: Renderer>(
416 services: &ServiceCollection,
417 mut renderer: R,
418 f: &mut Formatter<'_>,
419) -> FormatResult {
420 let count = services.items.len();
421
422 if count == 0 {
423 return Ok(());
424 }
425
426 let last = count - 1;
427 let mut branches = Vec::<char>::new();
428 let mut lookup = HashMap::with_capacity(count);
429
430 for item in &services.items {
431 let key = item.service_type();
432 let descriptors = lookup.entry(key).or_insert_with(Vec::new);
433 descriptors.push(item);
434 }
435
436 let mut context = PrintContext::new(&lookup);
437
438 branches.push('│');
439 branches.push(' ');
440
441 for (index, descriptor) in services.items.iter().enumerate() {
442 if index == last {
443 renderer.write('└', f)?;
444 branches[0] = ' ';
445 } else if index == 0 {
446 renderer.write('┌', f)?;
447 } else {
448 renderer.write('├', f)?;
449 }
450
451 renderer.write(' ', f)?;
452 context.reset(descriptor);
453
454 print_item(
455 PrintItem::One(descriptor),
456 ServiceCardinality::ExactlyOne,
457 &mut context,
458 0,
459 &mut branches,
460 f,
461 &mut renderer,
462 )?;
463
464 if index != last {
465 renderer.write_str("│\n", f)?;
466 }
467 }
468
469 Ok(())
470}
471
472fn print_item<R: Renderer>(
473 item: PrintItem,
474 cardinality: ServiceCardinality,
475 context: &mut PrintContext,
476 depth: usize,
477 branches: &mut Vec<char>,
478 formatter: &mut Formatter,
479 renderer: &mut R,
480) -> FormatResult {
481 match item {
482 PrintItem::One(sd) => {
483 append_service(sd.service_type(), cardinality, renderer, formatter)?;
484
485 if context.is_invalid_lifetime(sd) {
486 renderer.error(
487 format!(
488 "⧗ {} [{:?}]",
489 sd.implementation_type().name(),
490 sd.lifetime()
491 ),
492 formatter,
493 )?;
494 } else {
495 append_implementation(sd, renderer, formatter)?;
496 }
497 }
498 PrintItem::Many((ty, impl_count, _)) => {
499 append_service(ty, cardinality, renderer, formatter)?;
500 renderer.write_str(impl_count, formatter)?;
501 }
502 PrintItem::Warning((sd, msg)) => {
503 append_service(sd, cardinality, renderer, formatter)?;
504 renderer.warn(msg, formatter)?;
505 }
506 PrintItem::Error((sd, msg)) => {
507 append_service(sd, cardinality, renderer, formatter)?;
508 renderer.error(msg, formatter)?;
509 }
510 }
511
512 renderer.write('\n', formatter)?;
513
514 match item {
515 PrintItem::One(child) => {
516 traverse_dependencies(child, context, depth, branches, formatter, renderer)
517 }
518 PrintItem::Many((_, _, children)) => {
519 traverse_services(children, context, depth, branches, formatter, renderer)
520 }
521 _ => Ok(()),
522 }
523}
524
525fn append_service<R: Renderer>(
526 ty: &Type,
527 cardinality: ServiceCardinality,
528 renderer: &mut R,
529 f: &mut Formatter,
530) -> FormatResult {
531 let (type_, key) = Type::deconstruct(ty);
532
533 if type_.starts_with("dyn") {
534 renderer.keyword("dyn", f)?;
535 renderer.write(' ', f)?;
536 renderer.service(&type_[(type_.char_indices().nth(4).unwrap().0)..], f)?;
537 } else {
538 renderer.implementation(type_, f)?;
539 }
540
541 if cardinality == ServiceCardinality::ZeroOrMore {
542 renderer.accent("*", f)?;
543 } else if cardinality == ServiceCardinality::ZeroOrOne {
544 renderer.accent("?", f)?;
545 }
546
547 if let Some(name) = key {
548 renderer.write(' ', f)?;
549 renderer.info("[⚿ ", f)?;
550 renderer.info(name, f)?;
551 renderer.info("]", f)?;
552 }
553
554 renderer.write_str(" → ", f)
555}
556
557fn append_implementation<R: Renderer>(
558 item: &ServiceDescriptor,
559 renderer: &mut R,
560 f: &mut Formatter,
561) -> FormatResult {
562 renderer.implementation(item.implementation_type().name(), f)?;
563 renderer.write(' ', f)?;
564
565 match item.lifetime() {
566 ServiceLifetime::Scoped => renderer.info("[Scoped]", f),
567 ServiceLifetime::Singleton => renderer.info("[Singleton]", f),
568 ServiceLifetime::Transient => renderer.info("[Transient]", f),
569 }
570}
571
572fn indent<R: Renderer>(
573 branches: &mut Vec<char>,
574 formatter: &mut Formatter,
575 renderer: &mut R,
576 last: bool,
577) -> FormatResult {
578 for i in 0..branches.len() {
579 renderer.write(branches[i], formatter)?;
580 }
581
582 if last {
583 renderer.write('└', formatter)?;
584 } else {
585 renderer.write('├', formatter)?;
586 }
587
588 renderer.write(' ', formatter)?;
589
590 if last {
591 branches.push(' ');
592 } else {
593 branches.push('│');
594 }
595
596 branches.push(' ');
597 Ok(())
598}
599
600fn unindent(branches: &mut Vec<char>) {
601 branches.pop();
602 branches.pop();
603}
604
605fn traverse_dependencies<R: Renderer>(
606 descriptor: &ServiceDescriptor,
607 context: &mut PrintContext,
608 depth: usize,
609 branches: &mut Vec<char>,
610 formatter: &mut Formatter,
611 renderer: &mut R,
612) -> FormatResult {
613 for (index, dependency) in descriptor.dependencies().iter().enumerate() {
614 let type_ = dependency.injected_type();
615 let cardinality = dependency.cardinality();
616 let last = index == descriptor.dependencies().len() - 1;
617
618 indent(branches, formatter, renderer, last)?;
619
620 if let Some(children) = context.lookup(type_) {
621 if cardinality == ServiceCardinality::ZeroOrMore {
622 print_item(
623 PrintItem::Many((type_, &format!("Count: {}", children.len()), children)),
624 cardinality,
625 context,
626 depth + 1,
627 branches,
628 formatter,
629 renderer,
630 )?;
631 } else {
632 for child in children {
633 let msg;
634 let item = if context.is_circular_ref(child) {
635 msg = format!("♺ {}", child.service_type().name());
636 PrintItem::Error((child.service_type(), &msg))
637 } else {
638 PrintItem::One(child)
639 };
640
641 context.enter(child);
642 print_item(
643 item,
644 cardinality,
645 context,
646 depth + 1,
647 branches,
648 formatter,
649 renderer,
650 )?;
651 context.exit();
652 }
653 }
654 } else {
655 let item = match cardinality {
656 ServiceCardinality::ExactlyOne => PrintItem::Error((type_, "‼ Missing")),
657 ServiceCardinality::ZeroOrOne => PrintItem::Warning((type_, "▲ Missing")),
658 ServiceCardinality::ZeroOrMore => PrintItem::Warning((type_, "▲ Count: 0")),
659 };
660
661 print_item(
662 item,
663 cardinality,
664 context,
665 depth + 1,
666 branches,
667 formatter,
668 renderer,
669 )?;
670 }
671
672 unindent(branches);
673 }
674
675 Ok(())
676}
677
678fn traverse_services<R: Renderer>(
679 descriptors: &Vec<&ServiceDescriptor>,
680 context: &mut PrintContext,
681 depth: usize,
682 branches: &mut Vec<char>,
683 formatter: &mut Formatter,
684 renderer: &mut R,
685) -> FormatResult {
686 for (index, descriptor) in descriptors.iter().enumerate() {
687 let last = index == descriptors.len() - 1;
688
689 indent(branches, formatter, renderer, last)?;
690 print_item(
691 PrintItem::One(descriptor),
692 ServiceCardinality::ExactlyOne,
693 context,
694 depth + 1,
695 branches,
696 formatter,
697 renderer,
698 )?;
699 unindent(branches);
700 }
701
702 Ok(())
703}
704
705#[cfg(test)]
706mod tests {
707
708 use super::*;
709 use crate::{test::*, *};
710 use std::fs::remove_file;
711 use std::path::{Path, PathBuf};
712
713 #[test]
714 fn is_empty_should_return_true_when_empty() {
715 let collection = ServiceCollection::default();
717
718 let empty = collection.is_empty();
720
721 assert!(empty);
723 }
724
725 #[test]
726 fn length_should_return_zero_when_empty() {
727 let collection = ServiceCollection::default();
729
730 let length = collection.len();
732
733 assert_eq!(length, 0);
735 }
736
737 #[test]
738 fn is_empty_should_return_false_when_not_empty() {
739 let descriptor =
741 existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
742 let mut collection = ServiceCollection::new();
743
744 collection.add(descriptor);
745
746 let not_empty = !collection.is_empty();
748
749 assert!(not_empty);
751 }
752
753 #[test]
754 fn length_should_return_count_when_not_empty() {
755 let descriptor =
757 existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
758 let mut collection = ServiceCollection::new();
759
760 collection.add(descriptor);
761
762 let length = collection.len();
764
765 assert_eq!(length, 1);
767 }
768
769 #[test]
770 fn clear_should_remove_all_elements() {
771 let descriptor =
773 existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
774 let mut collection = ServiceCollection::new();
775
776 collection.add(descriptor);
777
778 collection.clear();
780
781 assert!(collection.is_empty());
783 }
784
785 #[test]
786 fn try_add_should_do_nothing_when_service_is_registered() {
787 let mut collection = ServiceCollection::new();
789
790 collection.add(
791 singleton::<dyn TestService, TestServiceImpl>()
792 .from(|_| Ref::new(TestServiceImpl::default())),
793 );
794
795 collection.try_add(
797 singleton::<dyn TestService, TestServiceImpl>()
798 .from(|_| Ref::new(TestServiceImpl::default())),
799 );
800
801 assert_eq!(collection.len(), 1);
803 }
804
805 #[test]
806 fn try_add_to_all_should_add_descriptor_when_implementation_is_unregistered() {
807 let mut collection = ServiceCollection::new();
809
810 collection.add(existing::<dyn TestService, TestServiceImpl>(Box::new(
811 TestServiceImpl::default(),
812 )));
813
814 collection.try_add_to_all(
815 singleton::<dyn OtherTestService, OtherTestServiceImpl>().from(|sp| {
816 Ref::new(OtherTestServiceImpl::new(
817 sp.get_required::<dyn TestService>(),
818 ))
819 }),
820 );
821
822 let count = collection.len();
824
825 assert_eq!(count, 2);
827 }
828
829 #[test]
830 fn try_add_to_all_should_not_add_descriptor_when_implementation_is_registered() {
831 let mut collection = ServiceCollection::new();
833
834 collection.add(existing::<dyn TestService, TestServiceImpl>(Box::new(
835 TestServiceImpl::default(),
836 )));
837
838 collection.try_add_to_all(
839 transient::<dyn TestService, TestServiceImpl>()
840 .from(|_| Ref::new(TestServiceImpl::default())),
841 );
842
843 let count = collection.len();
845
846 assert_eq!(count, 1);
848 }
849
850 #[test]
851 fn try_add_all_should_only_add_descriptors_for_unregistered_implementations() {
852 let descriptors = vec![
854 existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default())),
855 transient::<dyn TestService, TestServiceImpl>()
856 .from(|_| Ref::new(TestServiceImpl::default())),
857 ];
858 let mut collection = ServiceCollection::new();
859
860 collection.try_add_all(descriptors.into_iter());
861
862 let count = collection.len();
864
865 assert_eq!(count, 1);
867 }
868
869 #[test]
870 fn replace_should_replace_first_registered_service() {
871 let mut collection = ServiceCollection::new();
873
874 collection
875 .add(
876 singleton::<dyn TestService, TestServiceImpl>()
877 .from(|_| Ref::new(TestServiceImpl::default())),
878 )
879 .add(
880 singleton::<dyn TestService, TestServiceImpl>()
881 .from(|_| Ref::new(TestServiceImpl::default())),
882 );
883
884 collection.replace(
886 singleton::<dyn TestService, TestServiceImpl>()
887 .from(|_| Ref::new(TestServiceImpl::default())),
888 );
889
890 assert_eq!(collection.len(), 2);
892 }
893
894 #[test]
895 fn remove_all_should_remove_registered_services() {
896 let mut collection = ServiceCollection::new();
898
899 collection
900 .add(
901 singleton::<dyn TestService, TestServiceImpl>()
902 .from(|_| Ref::new(TestServiceImpl::default())),
903 )
904 .add(
905 singleton::<dyn TestService, TestServiceImpl>()
906 .from(|_| Ref::new(TestServiceImpl::default())),
907 );
908
909 collection.remove_all::<dyn TestService>();
911
912 assert!(collection.is_empty());
914 }
915
916 #[test]
917 fn try_replace_should_do_nothing_when_service_is_registered() {
918 let mut collection = ServiceCollection::new();
920
921 collection.add(
922 singleton::<dyn TestService, TestServiceImpl>()
923 .from(|_| Ref::new(TestServiceImpl { value: 1 })),
924 );
925
926 collection.try_replace(
928 singleton::<dyn TestService, TestServiceImpl>()
929 .from(|_| Ref::new(TestServiceImpl { value: 2 })),
930 );
931
932 let value = collection
934 .build_provider()
935 .unwrap()
936 .get_required::<dyn TestService>()
937 .value();
938 assert_eq!(value, 1);
939 }
940
941 #[test]
942 fn remove_should_remove_element_at_index() {
943 let descriptor =
945 existing::<dyn TestService, TestServiceImpl>(Box::new(TestServiceImpl::default()));
946 let mut collection = ServiceCollection::new();
947
948 collection.add(descriptor);
949
950 let _ = collection.remove(0);
952
953 assert!(collection.is_empty());
955 }
956
957 #[test]
958 fn service_collection_should_drop_existing_as_service() {
959 let file = new_temp_file("drop1");
961
962 {
964 let mut services = ServiceCollection::new();
965 services.add(existing_as_self(Droppable::new(file.clone())));
966 }
967
968 let dropped = !file.exists();
970 remove_file(&file).ok();
971 assert!(dropped);
972 }
973
974 #[test]
975 fn service_collection_should_not_drop_service_if_never_instantiated() {
976 let file = new_temp_file("drop4");
978 let mut services = ServiceCollection::new();
979
980 {
982 services
983 .add(existing::<Path, PathBuf>(file.clone().into_boxed_path()))
984 .add(singleton_as_self().from(|sp| {
985 Ref::new(Droppable::new(sp.get_required::<Path>().to_path_buf()))
986 }));
987 }
988
989 let not_dropped = file.exists();
991 remove_file(&file).ok();
992 assert!(not_dropped);
993 }
994}