portaldi_core/
container.rs1use crate::{traits::DITarget, types::DI};
4use std::{any::Any, collections::HashMap, future::Future};
5
6#[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
7use std::cell::RefCell;
8#[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
9use std::sync::RwLock;
10
11#[derive(Debug)]
13pub struct DIContainer {
14 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
16 components: RefCell<HashMap<String, DI<dyn Any>>>,
17 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
18 components: RwLock<HashMap<String, DI<dyn Any + Send + Sync>>>,
19}
20
21impl Default for DIContainer {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl DIContainer {
28 pub fn new() -> DIContainer {
30 DIContainer {
31 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
32 components: RefCell::new(HashMap::new()),
33 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
34 components: RwLock::new(HashMap::new()),
35 }
36 }
37
38 pub fn get<T: DITarget>(&self) -> Option<DI<T>> {
40 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
41 let comps = self.components.borrow();
42 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
43 let comps = self.components.read().unwrap();
44 comps
45 .get(std::any::type_name::<T>())
46 .map(|c| c.clone().downcast::<T>().unwrap())
47 }
48
49 pub fn put_if_absent<T: DITarget>(&self, c: &DI<T>) -> DI<T> {
51 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
52 let mut components = self.components.borrow_mut();
53 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
54 let mut components = self.components.write().unwrap();
55 let key = std::any::type_name::<T>();
56 let value = components
57 .get(key)
58 .map(|c| c.clone().downcast::<T>().unwrap());
59 if let Some(c) = value {
60 c
61 } else {
62 components.insert(key.into(), c.clone());
63 c.clone()
64 }
65 }
66
67 pub fn get_or_init<T, F>(&self, init: F) -> DI<T>
70 where
71 T: DITarget,
72 F: Fn() -> T,
73 {
74 if let Some(c) = self.get::<T>() {
75 c
76 } else {
77 let c = DI::new(init());
78 self.put_if_absent(&c)
79 }
80 }
81
82 pub async fn get_or_init_async<T, F, Fut>(&self, init: F) -> DI<T>
85 where
86 T: DITarget,
87 F: Fn() -> Fut,
88 Fut: Future<Output = T>,
89 {
90 if let Some(c) = self.get::<T>() {
91 c
92 } else {
93 let v = init().await;
94 let c = DI::new(v);
95 self.put_if_absent(&c)
96 }
97 }
98}