1use std::{
2 any::{Any, TypeId},
3 collections::HashMap,
4 fmt,
5 sync::Arc,
6};
7use thiserror::Error;
8
9use crate::{RegistrationOwner, ServiceRegistration};
10
11#[derive(Clone)]
14pub struct Shared<T: ?Sized + Send + Sync + 'static> {
15 inner: Arc<T>,
16}
17
18impl<T: ?Sized + Send + Sync + 'static> Shared<T> {
19 pub const fn new(inner: Arc<T>) -> Self {
20 Self { inner }
21 }
22
23 pub fn inner(&self) -> Arc<T> {
24 Arc::clone(&self.inner)
25 }
26}
27
28impl<T: ?Sized + Send + Sync + 'static> std::fmt::Debug for Shared<T> {
29 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 formatter
31 .debug_struct("Shared")
32 .field("service", &std::any::type_name::<T>())
33 .finish_non_exhaustive()
34 }
35}
36
37#[derive(Default)]
38pub struct ServiceCollection {
39 services: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
40 registrations: HashMap<TypeId, (ServiceRegistration, usize)>,
41 next_installation_index: usize,
42}
43
44impl std::fmt::Debug for ServiceCollection {
45 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 formatter
47 .debug_struct("ServiceCollection")
48 .field("service_count", &self.services.len())
49 .field("registration_count", &self.registrations.len())
50 .field("next_installation_index", &self.next_installation_index)
51 .finish()
52 }
53}
54
55impl ServiceCollection {
56 pub fn insert<T>(&mut self, value: Arc<T>) -> Result<(), ServiceError>
57 where
58 T: Any + Send + Sync,
59 {
60 self.insert_owned(value, RegistrationOwner::application())
61 }
62
63 pub(crate) fn insert_owned<T>(
64 &mut self,
65 value: Arc<T>,
66 attempted_owner: RegistrationOwner,
67 ) -> Result<(), ServiceError>
68 where
69 T: Any + Send + Sync,
70 {
71 let type_id = TypeId::of::<T>();
72 let rust_type = std::any::type_name::<T>();
73 if let Some((first, _)) = self.registrations.get(&type_id) {
74 return Err(ServiceError::Duplicate(DuplicateServiceRegistration {
75 rust_type,
76 first_owner: first.owner.clone(),
77 attempted_owner,
78 }));
79 }
80 self.services.insert(type_id, value);
81 self.registrations.insert(
82 type_id,
83 (
84 ServiceRegistration {
85 rust_type,
86 owner: attempted_owner,
87 },
88 self.next_installation_index,
89 ),
90 );
91 self.next_installation_index += 1;
92 Ok(())
93 }
94
95 pub fn insert_shared<T>(&mut self, value: Arc<T>) -> Result<(), ServiceError>
96 where
97 T: ?Sized + Send + Sync + 'static,
98 {
99 self.insert_shared_owned(value, RegistrationOwner::application())
100 }
101
102 pub(crate) fn insert_shared_owned<T>(
103 &mut self,
104 value: Arc<T>,
105 owner: RegistrationOwner,
106 ) -> Result<(), ServiceError>
107 where
108 T: ?Sized + Send + Sync + 'static,
109 {
110 self.insert_owned(Arc::new(Shared::new(value)), owner)
111 }
112
113 pub fn contains<T>(&self) -> bool
114 where
115 T: Any + Send + Sync,
116 {
117 self.services.contains_key(&TypeId::of::<T>())
118 }
119
120 pub fn contains_shared<T>(&self) -> bool
121 where
122 T: ?Sized + Send + Sync + 'static,
123 {
124 self.contains::<Shared<T>>()
125 }
126
127 pub fn get<T>(&self) -> Result<Arc<T>, ServiceError>
128 where
129 T: Any + Send + Sync,
130 {
131 get_service(&self.services)
132 }
133
134 pub fn get_optional<T>(&self) -> Result<Option<Arc<T>>, ServiceError>
135 where
136 T: Any + Send + Sync,
137 {
138 get_optional_service(&self.services)
139 }
140
141 pub fn get_shared<T>(&self) -> Result<Arc<T>, ServiceError>
142 where
143 T: ?Sized + Send + Sync + 'static,
144 {
145 self.get::<Shared<T>>().map(|service| service.inner())
146 }
147
148 pub fn get_optional_shared<T>(&self) -> Result<Option<Arc<T>>, ServiceError>
149 where
150 T: ?Sized + Send + Sync + 'static,
151 {
152 self.get_optional::<Shared<T>>()
153 .map(|service| service.map(|value| value.inner()))
154 }
155
156 pub fn freeze(self) -> FrozenServices {
157 let mut registrations = self.registrations.into_values().collect::<Vec<_>>();
158 registrations.sort_by(|(left, left_index), (right, right_index)| {
159 left.rust_type
160 .cmp(right.rust_type)
161 .then_with(|| left_index.cmp(right_index))
162 });
163 let registrations = registrations
164 .into_iter()
165 .map(|(registration, _)| registration)
166 .collect();
167 FrozenServices {
168 services: self.services,
169 registrations,
170 }
171 }
172}
173
174pub struct ServiceRegistrar<'a> {
179 pub(crate) services: &'a mut ServiceCollection,
180 pub(crate) owner: RegistrationOwner,
181}
182
183impl fmt::Debug for ServiceRegistrar<'_> {
184 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
185 formatter
186 .debug_struct("ServiceRegistrar")
187 .field("owner", &self.owner)
188 .finish_non_exhaustive()
189 }
190}
191
192impl ServiceRegistrar<'_> {
193 pub fn insert<T>(&mut self, value: Arc<T>) -> Result<(), ServiceError>
194 where
195 T: Any + Send + Sync,
196 {
197 self.services.insert_owned(value, self.owner.clone())
198 }
199
200 pub fn insert_shared<T>(&mut self, value: Arc<T>) -> Result<(), ServiceError>
201 where
202 T: ?Sized + Send + Sync + 'static,
203 {
204 self.services.insert_shared_owned(value, self.owner.clone())
205 }
206
207 pub fn contains<T>(&self) -> bool
208 where
209 T: Any + Send + Sync,
210 {
211 self.services.contains::<T>()
212 }
213
214 pub fn contains_shared<T>(&self) -> bool
215 where
216 T: ?Sized + Send + Sync + 'static,
217 {
218 self.services.contains_shared::<T>()
219 }
220
221 pub fn get<T>(&self) -> Result<Arc<T>, ServiceError>
222 where
223 T: Any + Send + Sync,
224 {
225 self.services.get::<T>()
226 }
227
228 pub fn get_optional<T>(&self) -> Result<Option<Arc<T>>, ServiceError>
229 where
230 T: Any + Send + Sync,
231 {
232 self.services.get_optional::<T>()
233 }
234
235 pub fn get_shared<T>(&self) -> Result<Arc<T>, ServiceError>
236 where
237 T: ?Sized + Send + Sync + 'static,
238 {
239 self.services.get_shared::<T>()
240 }
241
242 pub fn get_optional_shared<T>(&self) -> Result<Option<Arc<T>>, ServiceError>
243 where
244 T: ?Sized + Send + Sync + 'static,
245 {
246 self.services.get_optional_shared::<T>()
247 }
248}
249
250#[derive(Clone, Default)]
251pub struct FrozenServices {
252 services: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
253 registrations: Vec<ServiceRegistration>,
254}
255
256impl std::fmt::Debug for FrozenServices {
257 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 formatter
259 .debug_struct("FrozenServices")
260 .field("service_count", &self.services.len())
261 .field("registration_count", &self.registrations.len())
262 .finish()
263 }
264}
265
266impl FrozenServices {
267 pub fn registrations(&self) -> &[ServiceRegistration] {
269 &self.registrations
270 }
271
272 pub fn get<T>(&self) -> Result<Arc<T>, ServiceError>
273 where
274 T: Any + Send + Sync,
275 {
276 get_service(&self.services)
277 }
278
279 pub fn get_optional<T>(&self) -> Result<Option<Arc<T>>, ServiceError>
280 where
281 T: Any + Send + Sync,
282 {
283 get_optional_service(&self.services)
284 }
285
286 pub fn get_shared<T>(&self) -> Result<Arc<T>, ServiceError>
287 where
288 T: ?Sized + Send + Sync + 'static,
289 {
290 self.get::<Shared<T>>().map(|service| service.inner())
291 }
292
293 pub fn get_optional_shared<T>(&self) -> Result<Option<Arc<T>>, ServiceError>
294 where
295 T: ?Sized + Send + Sync + 'static,
296 {
297 self.get_optional::<Shared<T>>()
298 .map(|service| service.map(|value| value.inner()))
299 }
300}
301
302fn get_service<T>(
303 services: &HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
304) -> Result<Arc<T>, ServiceError>
305where
306 T: Any + Send + Sync,
307{
308 services
309 .get(&TypeId::of::<T>())
310 .cloned()
311 .ok_or_else(|| ServiceError::Missing(std::any::type_name::<T>()))?
312 .downcast::<T>()
313 .map_err(|_| ServiceError::TypeMismatch(std::any::type_name::<T>()))
314}
315
316fn get_optional_service<T>(
317 services: &HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
318) -> Result<Option<Arc<T>>, ServiceError>
319where
320 T: Any + Send + Sync,
321{
322 services
323 .get(&TypeId::of::<T>())
324 .cloned()
325 .map(|value| {
326 value
327 .downcast::<T>()
328 .map_err(|_| ServiceError::TypeMismatch(std::any::type_name::<T>()))
329 })
330 .transpose()
331}
332
333#[derive(Debug, Clone, PartialEq, Eq)]
334pub struct DuplicateServiceRegistration {
335 pub rust_type: &'static str,
336 pub first_owner: RegistrationOwner,
337 pub attempted_owner: RegistrationOwner,
338}
339
340impl fmt::Display for DuplicateServiceRegistration {
341 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
342 write!(
343 formatter,
344 "{} (first owner: {}, attempted owner: {})",
345 self.rust_type, self.first_owner, self.attempted_owner
346 )
347 }
348}
349
350#[derive(Debug, Error, Clone, PartialEq, Eq)]
351pub enum ServiceError {
352 #[error("service is already registered: {0}")]
353 Duplicate(DuplicateServiceRegistration),
354 #[error("service is not registered: {0}")]
355 Missing(&'static str),
356 #[error("service has an unexpected concrete type: {0}")]
357 TypeMismatch(&'static str),
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363
364 trait Greeting: Send + Sync {
365 fn text(&self) -> &'static str;
366 }
367
368 #[derive(Debug)]
369 struct Hello;
370 impl Greeting for Hello {
371 fn text(&self) -> &'static str {
372 "hello"
373 }
374 }
375
376 #[test]
377 fn typed_services_are_frozen_and_retrieved_without_string_keys() {
378 let mut services = ServiceCollection::default();
379 services.insert(Arc::new(String::from("hello"))).unwrap();
380 let frozen = services.freeze();
381 assert_eq!(&*frozen.get::<String>().unwrap(), "hello");
382 }
383
384 #[test]
385 fn trait_object_services_are_registered_without_double_arc_call_sites() {
386 let mut services = ServiceCollection::default();
387 services
388 .insert_shared::<dyn Greeting>(Arc::new(Hello))
389 .unwrap();
390 assert_eq!(
391 services.get_shared::<dyn Greeting>().unwrap().text(),
392 "hello"
393 );
394 }
395
396 #[test]
397 fn optional_service_lookup_distinguishes_absence_from_type_errors() {
398 let services = ServiceCollection::default();
399 assert!(services.get_optional::<String>().unwrap().is_none());
400 assert!(
401 services
402 .get_optional_shared::<dyn Greeting>()
403 .unwrap()
404 .is_none()
405 );
406
407 let frozen = services.freeze();
408 assert!(frozen.get_optional::<String>().unwrap().is_none());
409 assert!(
410 frozen
411 .get_optional_shared::<dyn Greeting>()
412 .unwrap()
413 .is_none()
414 );
415 }
416
417 #[test]
418 fn duplicate_service_types_are_rejected() {
419 let mut services = ServiceCollection::default();
420 services.insert(Arc::new(1_u64)).unwrap();
421 let Err(ServiceError::Duplicate(duplicate)) = services.insert(Arc::new(2_u64)) else {
422 panic!("duplicate must fail");
423 };
424 assert_eq!(duplicate.rust_type, std::any::type_name::<u64>());
425 assert!(duplicate.first_owner.is_application());
426 assert!(duplicate.attempted_owner.is_application());
427 assert_eq!(
428 duplicate.to_string(),
429 "u64 (first owner: application, attempted owner: application)"
430 );
431 }
432}