1use async_trait::async_trait;
4
5use crate::container::DIContainer;
6use crate::globals::INSTANCE;
7use crate::types::DI;
8
9#[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
12pub trait DITarget: 'static {}
13#[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
14pub trait DITarget: Send + Sync + 'static {}
15
16#[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
17impl<T: 'static> DITarget for T {}
18#[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
19impl<T: Send + Sync + 'static> DITarget for T {}
20
21pub trait DIPortal {
23 fn di_on(container: &DIContainer) -> DI<Self>
25 where
26 Self: Sized + DITarget,
27 {
28 container.get_or_init(|| Self::create_for_di(container))
29 }
30
31 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
33 fn di() -> DI<Self>
34 where
35 Self: Sized + DITarget,
36 {
37 Self::di_on(&INSTANCE)
38 }
39 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
40 fn di() -> DI<Self>
41 where
42 Self: Sized + DITarget,
43 {
44 Self::di_on(INSTANCE.with(|i| i.clone()).as_ref())
45 }
46
47 fn create_for_di(container: &DIContainer) -> Self;
49}
50
51#[cfg_attr(all(target_arch = "wasm32", not(feature = "multi-thread")), async_trait(?Send))]
53#[cfg_attr(
54 any(not(target_arch = "wasm32"), feature = "multi-thread"),
55 async_trait
56)]
57pub trait AsyncDIPortal {
58 async fn di_on(container: &DIContainer) -> DI<Self>
60 where
61 Self: Sized + DITarget,
62 {
63 container
64 .get_or_init_async(|| Self::create_for_di(container))
65 .await
66 }
67
68 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
70 async fn di() -> DI<Self>
71 where
72 Self: Sized + DITarget,
73 {
74 Self::di_on(&INSTANCE).await
75 }
76 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
77 async fn di() -> DI<Self>
78 where
79 Self: Sized + DITarget,
80 {
81 Self::di_on(INSTANCE.with(|i| i.clone()).as_ref()).await
82 }
83
84 async fn create_for_di(container: &DIContainer) -> Self;
86}
87
88pub trait DIProvider {
90 type Output: ?Sized;
92
93 fn di_on(container: &DIContainer) -> DI<Self::Output>;
95
96 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
98 fn di() -> DI<Self::Output> {
99 Self::di_on(&INSTANCE)
100 }
101 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
102 fn di() -> DI<Self::Output> {
103 Self::di_on(INSTANCE.with(|i| i.clone()).as_ref())
104 }
105}
106
107#[cfg_attr(all(target_arch = "wasm32", not(feature = "multi-thread")), async_trait(?Send))]
109#[cfg_attr(
110 any(not(target_arch = "wasm32"), feature = "multi-thread"),
111 async_trait
112)]
113pub trait AsyncDIProvider {
114 type Output: ?Sized;
116
117 async fn di_on(container: &DIContainer) -> DI<Self::Output>;
119
120 #[cfg(any(not(target_arch = "wasm32"), feature = "multi-thread"))]
122 async fn di() -> DI<Self::Output> {
123 Self::di_on(&INSTANCE).await
124 }
125 #[cfg(all(target_arch = "wasm32", not(feature = "multi-thread")))]
126 async fn di() -> DI<Self::Output> {
127 Self::di_on(INSTANCE.with(|i| i.clone()).as_ref()).await
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 trait FooI {}
136
137 mod sync_test {
138 use super::*;
139
140 struct Hoge;
141 impl DIPortal for Hoge {
142 fn create_for_di(_container: &DIContainer) -> Self {
143 Hoge {}
144 }
145 }
146 impl FooI for Hoge {}
147
148 struct FooIProvider;
149 impl DIProvider for FooIProvider {
150 type Output = dyn FooI;
151 fn di_on(container: &DIContainer) -> DI<Self::Output> {
152 Hoge::di_on(container)
153 }
154 }
155
156 #[test]
157 #[allow(non_snake_case)]
158 fn test_same_instance_for_DIPortal() {
159 let c = DIContainer::new();
160 let hoge1 = Hoge::di_on(&c).as_ref() as *const _;
161 let hoge2 = Hoge::di_on(&c).as_ref() as *const _;
162 assert!(std::ptr::eq(hoge1, hoge2));
163 }
164
165 #[test]
166 #[allow(non_snake_case)]
167 fn test_same_instance_for_DIProvider() {
168 let c = DIContainer::new();
169 let foo1 = FooIProvider::di_on(&c).as_ref() as *const _;
170 let foo2 = FooIProvider::di_on(&c).as_ref() as *const _;
171 assert!(std::ptr::eq(foo1, foo2));
172 }
173 }
174
175 mod async_test {
176 use super::*;
177
178 struct AsyncHoge;
179 #[async_trait]
180 impl AsyncDIPortal for AsyncHoge {
181 async fn create_for_di(_container: &DIContainer) -> Self {
182 AsyncHoge {}
183 }
184 }
185 impl FooI for AsyncHoge {}
186
187 struct AsyncFooIProvider;
188 #[async_trait]
189 impl AsyncDIProvider for AsyncFooIProvider {
190 type Output = dyn FooI;
191 async fn di_on(container: &DIContainer) -> DI<Self::Output> {
192 AsyncHoge::di_on(container).await
193 }
194 }
195
196 #[tokio::test]
197 #[allow(non_snake_case)]
198 async fn test_same_instance_for_AsyncDIPortal() {
199 let c = DIContainer::new();
200 let hoge1 = AsyncHoge::di_on(&c).await.as_ref() as *const _;
201 let hoge2 = AsyncHoge::di_on(&c).await.as_ref() as *const _;
202 println!("check !!! {:?} {:?}", hoge1, hoge2);
203 assert!(std::ptr::eq(hoge1, hoge2));
204 }
205
206 #[tokio::test]
207 #[allow(non_snake_case)]
208 async fn test_same_instance_for_AsyncDIProvider() {
209 let c = DIContainer::new();
210 let foo1 = AsyncFooIProvider::di_on(&c).await.as_ref() as *const _;
211 let foo2 = AsyncFooIProvider::di_on(&c).await.as_ref() as *const _;
212 println!("check !!! {:?} {:?}", foo1, foo2);
213 assert!(std::ptr::eq(foo1, foo2));
214 }
215 }
216}