Skip to main content

hosting_di/
container.rs

1use crate::collection::{Registration, Source};
2use crate::key::{Key, KeyMap};
3use crate::scope::Scope;
4use crate::sync::ConstructionLock;
5use crate::{Lifetime, ResolveError, Resolver};
6use std::any::Any;
7use std::fmt;
8use std::sync::atomic::{AtomicUsize, Ordering};
9use std::sync::{Arc, OnceLock};
10
11pub(crate) type Erased = Arc<dyn Any + Send + Sync>;
12
13pub(crate) type ConstructFn =
14    Arc<dyn Fn(&Resolver<'_>) -> Result<Erased, ResolveError> + Send + Sync>;
15
16/// Registrations frozen at build, plus singleton storage.
17pub(crate) struct Container {
18    registrations: Box<[Registration]>,
19    /// Every registration of a service, in registration order.
20    lookup: KeyMap<Box<[usize]>>,
21    pub(crate) scoped_count: usize,
22    pub(crate) singletons: Slots,
23    pub(crate) construction: ConstructionLock,
24}
25
26impl Container {
27    pub(crate) fn new(mut registrations: Vec<Registration>) -> Self {
28        // Every registration is reachable through `resolve_all`, so each gets
29        // its own storage, including ones a later registration overrides.
30        let (mut singletons, mut scoped) = (0, 0);
31        for registration in &mut registrations {
32            let count = match registration.lifetime {
33                Lifetime::Singleton => &mut singletons,
34                Lifetime::Scoped => &mut scoped,
35                Lifetime::Transient => continue,
36            };
37            registration.slot = *count;
38            *count += 1;
39        }
40
41        let container = Self {
42            lookup: index_by_key(&registrations),
43            registrations: registrations.into_boxed_slice(),
44            scoped_count: scoped,
45            singletons: Slots::new(singletons),
46            construction: ConstructionLock::default(),
47        };
48        for registration in &container.registrations {
49            if let Source::Instance(instance) = &registration.source {
50                container
51                    .singletons
52                    .fill(registration.slot, Arc::clone(instance));
53            }
54        }
55        container
56    }
57
58    /// The registration a single resolution uses: the last one.
59    pub(crate) fn registration(&self, key: Key) -> Option<&Registration> {
60        let &index = self.lookup.get(&key)?.last()?;
61        self.registrations.get(index)
62    }
63
64    pub(crate) fn registrations_of(
65        &self,
66        key: Key,
67    ) -> impl DoubleEndedIterator<Item = &Registration> + ExactSizeIterator {
68        self.lookup
69            .get(&key)
70            .map_or(&[][..], |indices| &indices[..])
71            .iter()
72            .map(|&index| &self.registrations[index])
73    }
74}
75
76/// Registration indices grouped by service, each group in registration order.
77pub(crate) fn index_by_key(registrations: &[Registration]) -> KeyMap<Box<[usize]>> {
78    let mut grouped: KeyMap<Vec<usize>> = KeyMap::default();
79    for (index, registration) in registrations.iter().enumerate() {
80        grouped.entry(registration.key).or_default().push(index);
81    }
82    grouped
83        .into_iter()
84        .map(|(key, indices)| (key, indices.into_boxed_slice()))
85        .collect()
86}
87
88/// Cached instances owned by the container or by a scope.
89///
90/// Filled slots form a list from the newest instance back to the oldest,
91/// threaded through the slots themselves, so the store stays one allocation
92/// and is released in reverse creation order without sorting.
93pub(crate) struct Slots {
94    slots: Box<[Slot]>,
95    newest: AtomicUsize,
96}
97
98struct Slot {
99    value: OnceLock<Erased>,
100    previous: AtomicUsize,
101}
102
103const NONE: usize = usize::MAX;
104
105impl Slots {
106    pub(crate) fn new(len: usize) -> Self {
107        Self {
108            slots: (0..len)
109                .map(|_| Slot {
110                    value: OnceLock::new(),
111                    previous: AtomicUsize::new(NONE),
112                })
113                .collect(),
114            newest: AtomicUsize::new(NONE),
115        }
116    }
117
118    pub(crate) fn get(&self, index: usize) -> Option<Erased> {
119        self.slots
120            .get(index)
121            .and_then(|slot| slot.value.get())
122            .map(Arc::clone)
123    }
124
125    /// Stores a new instance. Callers hold the owner's construction lock, so
126    /// the list is only ever extended by one thread at a time.
127    pub(crate) fn fill(&self, index: usize, instance: Erased) {
128        if let Some(slot) = self.slots.get(index) {
129            if slot.value.set(instance).is_ok() {
130                let previous = self.newest.swap(index, Ordering::Relaxed);
131                slot.previous.store(previous, Ordering::Relaxed);
132            }
133        }
134    }
135
136    fn release(&mut self) {
137        let mut next = self.newest.swap(NONE, Ordering::Relaxed);
138        while let Some(slot) = self.slots.get_mut(next) {
139            next = *slot.previous.get_mut();
140            drop(slot.value.take());
141        }
142    }
143}
144
145impl Drop for Slots {
146    fn drop(&mut self) {
147        self.release();
148    }
149}
150
151impl Drop for Container {
152    fn drop(&mut self) {
153        self.singletons.release();
154        // Registered instances were created at build, before anything else, so
155        // they are released last, latest registration first.
156        let registrations = std::mem::take(&mut self.registrations).into_vec();
157        registrations.into_iter().rev().for_each(drop);
158    }
159}
160
161/// The root of a built container. Cheap to clone.
162#[derive(Clone)]
163pub struct ServiceProvider {
164    container: Arc<Container>,
165}
166
167impl ServiceProvider {
168    pub(crate) fn new(container: Container) -> Self {
169        Self {
170            container: Arc::new(container),
171        }
172    }
173
174    /// Resolves a singleton or transient service.
175    ///
176    /// When `T` is registered more than once, the last registration wins; use
177    /// [`resolve_all`](Self::resolve_all) for every one.
178    pub fn resolve<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, ResolveError> {
179        Resolver::root(&self.container).resolve()
180    }
181
182    /// Resolves every registration of `T`, in registration order.
183    pub fn resolve_all<T: ?Sized + Send + Sync + 'static>(
184        &self,
185    ) -> Result<Vec<Arc<T>>, ResolveError> {
186        Resolver::root(&self.container).resolve_all()
187    }
188
189    /// Creates a scope for resolving scoped services.
190    pub fn create_scope(&self) -> Scope {
191        Scope::new(Arc::clone(&self.container))
192    }
193}
194
195impl fmt::Debug for ServiceProvider {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        f.debug_struct("ServiceProvider")
198            .field("registrations", &self.container.registrations)
199            .finish_non_exhaustive()
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206    use crate::{Dependency, Service, ServiceCollection};
207
208    struct Leaf;
209
210    impl Service for Leaf {
211        fn dependencies() -> Vec<Dependency> {
212            Vec::new()
213        }
214
215        fn construct(_: &Resolver<'_>) -> Result<Self, ResolveError> {
216            Ok(Leaf)
217        }
218    }
219
220    struct Config;
221
222    #[test]
223    fn every_registration_gets_storage() {
224        let mut services = ServiceCollection::new();
225        services
226            .add_scoped::<Leaf>()
227            .add_scoped::<Leaf>()
228            .add_singleton_instance(Config)
229            .add_singleton_with(|_| Ok(Config));
230        let provider = services.build().unwrap();
231        let container = &provider.container;
232
233        assert_eq!(container.scoped_count, 2);
234        assert_eq!(container.singletons.slots.len(), 2);
235        assert_eq!(container.singletons.newest.load(Ordering::Relaxed), 0);
236    }
237}