Skip to main content

deorbit_core/resolver/
services.rs

1use crate::builder::ServicesBuilder;
2use crate::builder::{BindingKind, BindingLifetime};
3use crate::either_iter::EitherIter;
4use crate::mbmany::OneOrMany;
5use crate::resolver::Error;
6use crate::resolver::graph;
7use crate::resolver::resolved::Resolved;
8use crate::runtime::ServiceFactory;
9use crate::runtime::TypeMeta;
10use crate::runtime::{ErasedArc, ErasedUnsizer};
11use std::collections::HashMap;
12use std::iter;
13
14/// A collection of services.
15#[derive(Debug)]
16pub struct Services {
17    services: HashMap<TypeMeta, ImmutableBinding>,
18}
19
20#[derive(Debug)]
21enum ImmutableBinding {
22    Type {
23        binding: ImmutableTypeBinding,
24    },
25    Alias {
26        impls: OneOrMany<(ErasedUnsizer, ImmutableTypeBinding)>,
27    },
28}
29
30impl ImmutableBinding {
31    pub fn unwrap_type(&self) -> &ImmutableTypeBinding {
32        match self {
33            ImmutableBinding::Type { binding } => binding,
34            ImmutableBinding::Alias { .. } => {
35                panic!("Called unwrap_type on an Alias binding")
36            }
37        }
38    }
39}
40
41#[derive(Debug, Clone)]
42enum ImmutableTypeBinding {
43    Singleton(ErasedArc),
44    Transient(ServiceFactory),
45}
46
47impl ImmutableTypeBinding {
48    fn from(value: BindingLifetime, services: &Services) -> Result<Self, Error> {
49        let binding = match value {
50            BindingLifetime::Singleton(x) => Self::Singleton(x.to_instance(services)?),
51            BindingLifetime::Transient(x) => Self::Transient(x),
52        };
53
54        Ok(binding)
55    }
56}
57
58impl Services {
59    /// Attempts to make an instance of Services from a ServiceBuilder instance.
60    pub fn from_builder(builder: ServicesBuilder) -> Result<Self, Error> {
61        let bindings = builder.to_vec();
62
63        let bindings = graph::merge_aliases(bindings);
64        let bindings = graph::resolve_order(bindings)?;
65
66        // Bindings that shouldn't be exposed under their types
67        // will be removed after construction
68        let unbind: Vec<_> = bindings
69            .iter()
70            .filter_map(|x| match x.kind {
71                BindingKind::Type { bind_self, .. } if !bind_self => Some(x.ty),
72                _ => None,
73            })
74            .collect();
75
76        let mut services = Self {
77            services: HashMap::new(),
78        };
79
80        for binding in bindings {
81            let ty = binding.ty;
82
83            let binding = match binding.kind {
84                BindingKind::Type { lifetime, .. } => ImmutableBinding::Type {
85                    binding: ImmutableTypeBinding::from(lifetime, &services)?,
86                },
87                BindingKind::Alias { impls } => {
88                    ImmutableBinding::Alias {
89                        impls: impls
90                            .iter()
91                            .map(|(meta, unsizer)| {
92                                // Bindings are sorted, so it's guaranteed that all
93                                // underlying types are already presented in the map
94                                let binding = services.services.get(meta).unwrap();
95
96                                (unsizer.clone(), binding.unwrap_type().clone())
97                            })
98                            .collect(),
99                    }
100                }
101            };
102
103            services.services.insert(ty, binding);
104        }
105
106        // Removing unexposed bindings as they're
107        // not needed for resolution anymore
108        for ty in unbind {
109            services.services.remove(&ty);
110        }
111
112        Ok(services)
113    }
114}
115
116impl Services {
117    /// Returns a lazy iterator over all members of type T.
118    /// If T is concrete, the iter will always contain a single element.
119    pub fn resolve_all<T>(&self) -> Option<impl DoubleEndedIterator<Item = Resolved<T>>>
120    where
121        T: ?Sized + Send + Sync + 'static,
122    {
123        let type_meta = TypeMeta::of::<T>();
124
125        self.services.get(&type_meta).map(|x| match x {
126            ImmutableBinding::Type { binding } => {
127                let iter = iter::once(binding).map(|binding| {
128                    self.get_instance(binding)
129                        .coerce::<T>()
130                        .expect("Failed to coerce. This is a bug!")
131                });
132
133                EitherIter::Left(iter)
134            }
135            ImmutableBinding::Alias { impls } => {
136                let iter = impls.into_iter().map(|(unsizer, binding)| {
137                    let arc = self.get_instance(binding);
138
139                    unsizer
140                        .unsize::<T>(arc)
141                        .expect("Failed to unsize. This is a bug!")
142                });
143
144                EitherIter::Right(iter)
145            }
146        })
147    }
148
149    /// Returns the last binding of type T. For concrete T, there is always a single instance.
150    pub fn resolve<T>(&self) -> Option<Resolved<T>>
151    where
152        T: ?Sized + Send + Sync + 'static,
153    {
154        self.resolve_all().map(|mut x| x.next_back().unwrap())
155    }
156
157    fn get_instance(&self, binding: &ImmutableTypeBinding) -> ErasedArc {
158        match binding {
159            ImmutableTypeBinding::Singleton(arc) => arc.clone(),
160            // Transient is designed to panic because dependencies are validated beforehand,
161            // so if an error has occurred after validation it's not a dependency resolution issue anymore
162            ImmutableTypeBinding::Transient(factory) => factory
163                .produce(self)
164                .expect("Failed while trying to instantiate Transient"),
165        }
166    }
167}