1use crate::entry::{AsyncServiceFactory, ServiceDescriptor, ServiceFactory, ServiceLifetime};
2use crate::registration::ServiceRegistration;
3use std::any::{Any, TypeId};
4use std::future::Future;
5use std::pin::Pin;
6use std::sync::Arc;
7
8pub struct ServiceCollection {
9 descriptors: Vec<ServiceDescriptor>,
10}
11
12impl ServiceCollection {
13 pub fn new() -> Self {
14 Self {
15 descriptors: Vec::new(),
16 }
17 }
18
19 pub fn singleton<T: ?Sized + Send + Sync + 'static>(
20 mut self,
21 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
22 ) -> Self {
23 self.push(ServiceLifetime::Singleton, None, f);
24 self
25 }
26
27 pub fn transient<T: ?Sized + Send + Sync + 'static>(
28 mut self,
29 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
30 ) -> Self {
31 self.push(ServiceLifetime::Transient, None, f);
32 self
33 }
34
35 pub fn scoped<T: ?Sized + Send + Sync + 'static>(
36 mut self,
37 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
38 ) -> Self {
39 self.push(ServiceLifetime::Scoped, None, f);
40 self
41 }
42
43 pub fn keyed_singleton<T: ?Sized + Send + Sync + 'static>(
48 mut self,
49 k: impl Into<String>,
50 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
51 ) -> Self {
52 self.push(ServiceLifetime::Singleton, Some(k.into()), f);
53 self
54 }
55
56 pub fn keyed_transient<T: ?Sized + Send + Sync + 'static>(
58 mut self,
59 k: impl Into<String>,
60 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
61 ) -> Self {
62 self.push(ServiceLifetime::Transient, Some(k.into()), f);
63 self
64 }
65
66 pub fn keyed_scoped<T: ?Sized + Send + Sync + 'static>(
68 mut self,
69 k: impl Into<String>,
70 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
71 ) -> Self {
72 self.push(ServiceLifetime::Scoped, Some(k.into()), f);
73 self
74 }
75
76 pub fn async_singleton<T: ?Sized + Send + Sync + 'static>(
78 mut self,
79 f: impl Fn(
80 Arc<crate::provider::ServiceProvider>,
81 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
82 + Send
83 + Sync
84 + 'static,
85 ) -> Self {
86 self.push_async(ServiceLifetime::Singleton, None, f);
87 self
88 }
89
90 pub fn async_transient<T: ?Sized + Send + Sync + 'static>(
92 mut self,
93 f: impl Fn(
94 Arc<crate::provider::ServiceProvider>,
95 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
96 + Send
97 + Sync
98 + 'static,
99 ) -> Self {
100 self.push_async(ServiceLifetime::Transient, None, f);
101 self
102 }
103
104 pub fn async_scoped<T: ?Sized + Send + Sync + 'static>(
106 mut self,
107 f: impl Fn(
108 Arc<crate::provider::ServiceProvider>,
109 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
110 + Send
111 + Sync
112 + 'static,
113 ) -> Self {
114 self.push_async(ServiceLifetime::Scoped, None, f);
115 self
116 }
117
118 pub fn async_keyed_singleton<T: ?Sized + Send + Sync + 'static>(
120 mut self,
121 k: impl Into<String>,
122 f: impl Fn(
123 Arc<crate::provider::ServiceProvider>,
124 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
125 + Send
126 + Sync
127 + 'static,
128 ) -> Self {
129 self.push_async(ServiceLifetime::Singleton, Some(k.into()), f);
130 self
131 }
132
133 pub fn async_keyed_transient<T: ?Sized + Send + Sync + 'static>(
135 mut self,
136 k: impl Into<String>,
137 f: impl Fn(
138 Arc<crate::provider::ServiceProvider>,
139 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
140 + Send
141 + Sync
142 + 'static,
143 ) -> Self {
144 self.push_async(ServiceLifetime::Transient, Some(k.into()), f);
145 self
146 }
147
148 pub fn async_keyed_scoped<T: ?Sized + Send + Sync + 'static>(
150 mut self,
151 k: impl Into<String>,
152 f: impl Fn(
153 Arc<crate::provider::ServiceProvider>,
154 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
155 + Send
156 + Sync
157 + 'static,
158 ) -> Self {
159 self.push_async(ServiceLifetime::Scoped, Some(k.into()), f);
160 self
161 }
162
163 pub fn try_add<T: ?Sized + Send + Sync + 'static>(
164 self,
165 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
166 ) -> Self {
167 self.try_add_with_lifetime(ServiceLifetime::Singleton, f)
168 }
169
170 pub fn try_add_singleton<T: ?Sized + Send + Sync + 'static>(
172 self,
173 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
174 ) -> Self {
175 self.try_add_with_lifetime(ServiceLifetime::Singleton, f)
176 }
177
178 pub fn try_add_scoped<T: ?Sized + Send + Sync + 'static>(
180 self,
181 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
182 ) -> Self {
183 self.try_add_with_lifetime(ServiceLifetime::Scoped, f)
184 }
185
186 pub fn try_add_transient<T: ?Sized + Send + Sync + 'static>(
188 self,
189 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
190 ) -> Self {
191 self.try_add_with_lifetime(ServiceLifetime::Transient, f)
192 }
193
194 fn try_add_with_lifetime<T: ?Sized + Send + Sync + 'static>(
195 mut self,
196 lt: ServiceLifetime,
197 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
198 ) -> Self {
199 let tid = TypeId::of::<T>();
200 if self
201 .descriptors
202 .iter()
203 .any(|d| d.type_id == tid && d.key.is_none())
204 {
205 return self;
206 }
207 self.push(lt, None, f);
208 self
209 }
210
211 pub fn add<T: ?Sized + Send + Sync + 'static>(
212 mut self,
213 lt: ServiceLifetime,
214 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
215 ) -> Self {
216 self.push(lt, None, f);
217 self
218 }
219
220 pub fn instance<T: Send + Sync + 'static>(mut self, v: Arc<T>) -> Self {
221 let ff: ServiceFactory = Arc::new(move |_| Arc::new(v.clone()));
222 self.descriptors.push(ServiceDescriptor {
223 type_id: TypeId::of::<T>(),
224 type_name: std::any::type_name::<T>(),
225 key: None,
226 factory: ff,
227 async_factory: None,
228 lifetime: ServiceLifetime::Singleton,
229 });
230 self
231 }
232
233 pub fn singleton_value<T: Send + Sync + 'static>(self, v: T) -> Self {
234 self.instance(Arc::new(v))
235 }
236
237 pub fn build(self) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
238 self.build_with(crate::provider::ServiceProviderOptions::default())
239 }
240
241 pub fn build_with(
248 self,
249 options: crate::provider::ServiceProviderOptions,
250 ) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
251 crate::provider::ServiceProvider::new_with(self.into_store(), options)
252 }
253
254 pub async fn build_async(
266 self,
267 ) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
268 self.build_async_with(crate::provider::ServiceProviderOptions::default())
269 .await
270 }
271
272 pub async fn build_async_with(
274 self,
275 options: crate::provider::ServiceProviderOptions,
276 ) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
277 crate::provider::ServiceProvider::new_async_with(self.into_store(), options).await
278 }
279
280 fn into_store(self) -> crate::entry::ServiceStore {
285 let mut s = crate::entry::ServiceStore::new();
286 for (n, d) in self.descriptors.into_iter().enumerate() {
287 let e = crate::entry::ServiceEntry {
288 cache_key: n,
289 key: d.key,
290 type_name: d.type_name,
291 factory: d.factory,
292 async_factory: d.async_factory,
293 lifetime: d.lifetime,
294 };
295 s.entry(d.type_id).or_default().push(e);
296 }
297 s
298 }
299
300 #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
303 pub fn from_injected() -> Self {
304 let mut descriptors = Vec::new();
305 for reg in inventory::iter::<ServiceRegistration> {
306 let factory: ServiceFactory = Arc::new(move |r| (reg.factory)(r));
307 descriptors.push(ServiceDescriptor {
308 type_id: reg.type_id,
309 type_name: (reg.type_name_fn)(),
310 key: None,
311 factory,
312 async_factory: None,
313 lifetime: reg.lifetime,
314 });
315 }
316 Self { descriptors }
317 }
318
319 fn push<T: ?Sized + Send + Sync + 'static>(
321 &mut self,
322 lt: ServiceLifetime,
323 key: Option<String>,
324 f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
325 ) {
326 let sf: ServiceFactory = Arc::new(move |r| {
327 let val: Arc<T> = (f)(r);
328 Arc::new(val) as Arc<dyn Any + Send + Sync>
329 });
330 self.descriptors.push(ServiceDescriptor {
331 type_id: TypeId::of::<T>(),
332 type_name: std::any::type_name::<T>(),
333 key,
334 factory: sf,
335 async_factory: None,
336 lifetime: lt,
337 });
338 }
339
340 fn push_async<T: ?Sized + Send + Sync + 'static>(
342 &mut self,
343 lt: ServiceLifetime,
344 key: Option<String>,
345 f: impl Fn(
346 Arc<crate::provider::ServiceProvider>,
347 ) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
348 + Send
349 + Sync
350 + 'static,
351 ) {
352 let af: AsyncServiceFactory = Arc::new(move |sp: Arc<crate::provider::ServiceProvider>| {
353 let fut = (f)(sp);
354 Box::pin(async move {
355 let val: Arc<T> = fut.await;
356 Arc::new(val) as Arc<dyn Any + Send + Sync>
357 }) as Pin<Box<dyn Future<Output = Arc<dyn Any + Send + Sync>> + Send>>
358 });
359 let type_name = std::any::type_name::<T>();
362 let sf: ServiceFactory = Arc::new(move |_| {
363 std::panic::panic_any(crate::error::RdiError::AsyncServiceRequiresBuildAsync {
364 service: type_name.to_string(),
365 })
366 });
367 self.descriptors.push(ServiceDescriptor {
368 type_id: TypeId::of::<T>(),
369 type_name: std::any::type_name::<T>(),
370 key,
371 factory: sf,
372 async_factory: Some(af),
373 lifetime: lt,
374 });
375 }
376}
377impl Default for ServiceCollection {
378 fn default() -> Self {
379 Self::new()
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386 #[derive(Debug, PartialEq)]
387 struct G {
388 n: String,
389 }
390 #[derive(Debug, PartialEq)]
391 struct C {
392 v: i32,
393 }
394 #[test]
395 fn empty() {
396 let p = ServiceCollection::new().build().unwrap();
397 assert!(p.get_optional::<G>().is_none());
398 }
399 #[test]
400 fn singleton() {
401 let p = ServiceCollection::new()
402 .singleton(|_| Arc::new(G { n: "Hi".into() }))
403 .build()
404 .unwrap();
405 assert_eq!(p.get::<G>().unwrap().n, "Hi");
406 }
407 #[test]
408 fn singleton_caches() {
409 use std::sync::atomic::{AtomicUsize, Ordering};
410 static CNT: AtomicUsize = AtomicUsize::new(0);
411 let p = ServiceCollection::new()
412 .singleton(|_| {
413 CNT.fetch_add(1, Ordering::SeqCst);
414 Arc::new(C { v: 42 })
415 })
416 .build()
417 .unwrap();
418 let _ = p.get::<C>();
419 let _ = p.get::<C>();
420 assert_eq!(CNT.load(Ordering::SeqCst), 1);
421 }
422 #[test]
423 fn transient_not_cached() {
424 use std::sync::atomic::{AtomicUsize, Ordering};
425 static CNT: AtomicUsize = AtomicUsize::new(0);
426 let p = ServiceCollection::new()
427 .transient(|_| {
428 CNT.fetch_add(1, Ordering::SeqCst);
429 Arc::new(C { v: 1 })
430 })
431 .build()
432 .unwrap();
433 let _ = p.get::<C>();
434 let _ = p.get::<C>();
435 assert_eq!(CNT.load(Ordering::SeqCst), 2);
436 }
437 #[test]
438 fn instance() {
439 let g = Arc::new(G { n: "Inst".into() });
440 let p = ServiceCollection::new()
441 .instance(g.clone())
442 .build()
443 .unwrap();
444 assert!(Arc::ptr_eq(&g, &p.get::<G>().unwrap()));
445 }
446 #[test]
447 fn keyed_svc() {
448 let p = ServiceCollection::new()
449 .keyed_singleton("a", |_| Arc::new(G { n: "A".into() }))
450 .keyed_singleton("b", |_| Arc::new(G { n: "B".into() }))
451 .build()
452 .unwrap();
453 assert_eq!(p.get_keyed::<G>("a").unwrap().n, "A");
454 assert_eq!(p.get_keyed::<G>("b").unwrap().n, "B");
455 }
456 #[test]
457 fn get_all() {
458 let p = ServiceCollection::new()
459 .keyed_singleton("x", |_| Arc::new(C { v: 1 }))
460 .keyed_singleton("y", |_| Arc::new(C { v: 2 }))
461 .build()
462 .unwrap();
463 assert!(
464 p.get_all::<C>().is_empty(),
465 "get_all excludes keyed registrations (MEDI GetServices)"
466 );
467 let keyed: Vec<i32> = p.get_all_keyed::<C>().iter().map(|c| c.v).collect();
468 assert_eq!(keyed, vec![1, 2]);
469 }
470 #[test]
471 fn try_add_skips() {
472 let p = ServiceCollection::new()
473 .singleton(|_| Arc::new(G { n: "First".into() }))
474 .try_add(|_| Arc::new(G { n: "Second".into() }))
475 .build()
476 .unwrap();
477 assert_eq!(p.get::<G>().unwrap().n, "First");
478 }
479}