1use super::{AnyProvider, ModuleRef, ProviderToken};
2use crate::{BootError, BoxFuture, Result};
3use std::fmt;
4use std::future::Future;
5use std::sync::Arc;
6
7type ProviderFactory = dyn Fn(&ModuleRef) -> Result<Arc<AnyProvider>> + Send + Sync;
8type AsyncProviderFactory =
9 dyn Fn(ModuleRef) -> BoxFuture<'static, Result<Arc<AnyProvider>>> + Send + Sync;
10type ProviderModuleInitHook = dyn Fn(Arc<AnyProvider>, &ModuleRef) -> Result<()> + Send + Sync;
11type ProviderApplicationHook =
12 dyn Fn(Arc<AnyProvider>, ModuleRef) -> BoxFuture<'static, Result<()>> + Send + Sync;
13
14pub trait ProviderOnModuleInit: Send + Sync + 'static {
16 fn on_module_init(&self, _module_ref: &ModuleRef) -> Result<()> {
17 Ok(())
18 }
19}
20
21pub trait ProviderOnApplicationBootstrap: Send + Sync + 'static {
23 fn on_application_bootstrap(&self, _module_ref: ModuleRef) -> BoxFuture<'static, Result<()>> {
24 Box::pin(async { Ok(()) })
25 }
26}
27
28pub trait ProviderOnApplicationShutdown: Send + Sync + 'static {
30 fn on_application_shutdown(&self, _module_ref: ModuleRef) -> BoxFuture<'static, Result<()>> {
31 Box::pin(async { Ok(()) })
32 }
33}
34
35pub trait FromModuleRef: Sized + Send + Sync + 'static {
37 fn from_module_ref(module_ref: &ModuleRef) -> Result<Self>;
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum ProviderScope {
43 Singleton,
44 Request,
45 Transient,
46}
47
48#[derive(Clone)]
50pub struct ProviderDefinition {
51 token: ProviderToken,
52 factory: ProviderFactoryKind,
53 scope: ProviderScope,
54 lifecycle: ProviderLifecycleHooks,
55 alias_target: Option<ProviderToken>,
56}
57
58#[derive(Clone)]
59enum ProviderFactoryKind {
60 Sync(Arc<ProviderFactory>),
61 Async(Arc<AsyncProviderFactory>),
62}
63
64#[derive(Clone, Default)]
65pub(super) struct ProviderLifecycleHooks {
66 on_module_init: Option<Arc<ProviderModuleInitHook>>,
67 on_application_bootstrap: Option<Arc<ProviderApplicationHook>>,
68 on_application_shutdown: Option<Arc<ProviderApplicationHook>>,
69}
70
71impl ProviderLifecycleHooks {
72 pub(super) fn has_hooks(&self) -> bool {
73 self.on_module_init.is_some()
74 || self.on_application_bootstrap.is_some()
75 || self.on_application_shutdown.is_some()
76 }
77
78 pub(super) fn on_module_init(&self) -> Option<&Arc<ProviderModuleInitHook>> {
79 self.on_module_init.as_ref()
80 }
81
82 pub(super) fn on_application_bootstrap(&self) -> Option<&Arc<ProviderApplicationHook>> {
83 self.on_application_bootstrap.as_ref()
84 }
85
86 pub(super) fn on_application_shutdown(&self) -> Option<&Arc<ProviderApplicationHook>> {
87 self.on_application_shutdown.as_ref()
88 }
89}
90
91impl fmt::Debug for ProviderDefinition {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.debug_struct("ProviderDefinition")
94 .field("token", &self.token)
95 .field("scope", &self.scope)
96 .field("async", &self.factory.is_async())
97 .field("alias_target", &self.alias_target)
98 .finish_non_exhaustive()
99 }
100}
101
102impl ProviderFactoryKind {
103 fn is_async(&self) -> bool {
104 matches!(self, Self::Async(_))
105 }
106}
107
108impl ProviderDefinition {
109 pub fn singleton<T>(value: T) -> Self
110 where
111 T: Send + Sync + 'static,
112 {
113 Self::from_arc(Arc::new(value))
114 }
115
116 pub fn named_singleton<T>(token: impl Into<String>, value: T) -> Self
117 where
118 T: Send + Sync + 'static,
119 {
120 Self::named_from_arc(token, Arc::new(value))
121 }
122
123 pub fn from_arc<T>(value: Arc<T>) -> Self
124 where
125 T: Send + Sync + 'static,
126 {
127 let token = ProviderToken::of::<T>();
128 Self::named_from_arc(token.as_str(), value)
129 }
130
131 pub fn named_from_arc<T>(token: impl Into<String>, value: Arc<T>) -> Self
132 where
133 T: Send + Sync + 'static,
134 {
135 let token = ProviderToken::named(token);
136 let factory_value = Arc::clone(&value);
137 Self {
138 token,
139 factory: ProviderFactoryKind::Sync(Arc::new(move |_| {
140 Ok(Arc::clone(&factory_value) as Arc<AnyProvider>)
141 })),
142 scope: ProviderScope::Singleton,
143 lifecycle: ProviderLifecycleHooks::default(),
144 alias_target: None,
145 }
146 }
147
148 pub fn factory<T, F>(factory: F) -> Self
149 where
150 T: Send + Sync + 'static,
151 F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
152 {
153 Self::named_factory(ProviderToken::of::<T>().as_str(), factory)
154 }
155
156 pub fn factory_arc<T, F>(factory: F) -> Self
157 where
158 T: Send + Sync + 'static,
159 F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
160 {
161 Self::named_factory_arc(ProviderToken::of::<T>().as_str(), factory)
162 }
163
164 pub fn named_factory<T, F>(token: impl Into<String>, factory: F) -> Self
165 where
166 T: Send + Sync + 'static,
167 F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
168 {
169 Self {
170 token: ProviderToken::named(token),
171 factory: ProviderFactoryKind::Sync(Arc::new(move |module_ref| {
172 Ok(Arc::new(factory(module_ref)?) as Arc<AnyProvider>)
173 })),
174 scope: ProviderScope::Singleton,
175 lifecycle: ProviderLifecycleHooks::default(),
176 alias_target: None,
177 }
178 }
179
180 pub fn named_factory_arc<T, F>(token: impl Into<String>, factory: F) -> Self
181 where
182 T: Send + Sync + 'static,
183 F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
184 {
185 Self {
186 token: ProviderToken::named(token),
187 factory: ProviderFactoryKind::Sync(Arc::new(move |module_ref| {
188 Ok(factory(module_ref)? as Arc<AnyProvider>)
189 })),
190 scope: ProviderScope::Singleton,
191 lifecycle: ProviderLifecycleHooks::default(),
192 alias_target: None,
193 }
194 }
195
196 pub fn async_factory<T, F, Fut>(factory: F) -> Self
197 where
198 T: Send + Sync + 'static,
199 F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
200 Fut: Future<Output = Result<T>> + Send + 'static,
201 {
202 Self::named_async_factory(ProviderToken::of::<T>().as_str(), factory)
203 }
204
205 pub fn async_factory_arc<T, F, Fut>(factory: F) -> Self
206 where
207 T: Send + Sync + 'static,
208 F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
209 Fut: Future<Output = Result<Arc<T>>> + Send + 'static,
210 {
211 Self::named_async_factory_arc(ProviderToken::of::<T>().as_str(), factory)
212 }
213
214 pub fn named_async_factory<T, F, Fut>(token: impl Into<String>, factory: F) -> Self
215 where
216 T: Send + Sync + 'static,
217 F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
218 Fut: Future<Output = Result<T>> + Send + 'static,
219 {
220 Self {
221 token: ProviderToken::named(token),
222 factory: ProviderFactoryKind::Async(Arc::new(move |module_ref| {
223 let future = factory(module_ref);
224 Box::pin(async move { Ok(Arc::new(future.await?) as Arc<AnyProvider>) })
225 })),
226 scope: ProviderScope::Singleton,
227 lifecycle: ProviderLifecycleHooks::default(),
228 alias_target: None,
229 }
230 }
231
232 pub fn named_async_factory_arc<T, F, Fut>(token: impl Into<String>, factory: F) -> Self
233 where
234 T: Send + Sync + 'static,
235 F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
236 Fut: Future<Output = Result<Arc<T>>> + Send + 'static,
237 {
238 Self {
239 token: ProviderToken::named(token),
240 factory: ProviderFactoryKind::Async(Arc::new(move |module_ref| {
241 let future = factory(module_ref);
242 Box::pin(async move { Ok(future.await? as Arc<AnyProvider>) })
243 })),
244 scope: ProviderScope::Singleton,
245 lifecycle: ProviderLifecycleHooks::default(),
246 alias_target: None,
247 }
248 }
249
250 pub fn injectable<T>() -> Self
251 where
252 T: FromModuleRef,
253 {
254 Self::factory::<T, _>(T::from_module_ref)
255 }
256
257 pub fn named_injectable<T>(token: impl Into<String>) -> Self
258 where
259 T: FromModuleRef,
260 {
261 Self::named_factory::<T, _>(token, T::from_module_ref)
262 }
263
264 pub fn alias<T>(target: ProviderToken) -> Self
265 where
266 T: Send + Sync + 'static,
267 {
268 Self::named_alias(ProviderToken::of::<T>().as_str(), target)
269 }
270
271 pub fn named_alias(token: impl Into<String>, target: ProviderToken) -> Self {
272 Self {
273 token: ProviderToken::named(token),
274 factory: ProviderFactoryKind::Sync(Arc::new(|_| {
275 Err(BootError::Internal(
276 "provider aliases must be resolved through ModuleRef".to_string(),
277 ))
278 })),
279 scope: ProviderScope::Singleton,
280 lifecycle: ProviderLifecycleHooks::default(),
281 alias_target: Some(target),
282 }
283 }
284
285 pub fn transient<T, F>(factory: F) -> Self
286 where
287 T: Send + Sync + 'static,
288 F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
289 {
290 Self::factory::<T, _>(factory).with_scope(ProviderScope::Transient)
291 }
292
293 pub fn transient_arc<T, F>(factory: F) -> Self
294 where
295 T: Send + Sync + 'static,
296 F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
297 {
298 Self::factory_arc::<T, _>(factory).with_scope(ProviderScope::Transient)
299 }
300
301 pub fn named_transient<T, F>(token: impl Into<String>, factory: F) -> Self
302 where
303 T: Send + Sync + 'static,
304 F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
305 {
306 Self::named_factory::<T, _>(token, factory).with_scope(ProviderScope::Transient)
307 }
308
309 pub fn named_transient_arc<T, F>(token: impl Into<String>, factory: F) -> Self
310 where
311 T: Send + Sync + 'static,
312 F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
313 {
314 Self::named_factory_arc::<T, _>(token, factory).with_scope(ProviderScope::Transient)
315 }
316
317 pub fn transient_injectable<T>() -> Self
318 where
319 T: FromModuleRef,
320 {
321 Self::injectable::<T>().with_scope(ProviderScope::Transient)
322 }
323
324 pub fn named_transient_injectable<T>(token: impl Into<String>) -> Self
325 where
326 T: FromModuleRef,
327 {
328 Self::named_injectable::<T>(token).with_scope(ProviderScope::Transient)
329 }
330
331 pub fn request_scoped<T, F>(factory: F) -> Self
332 where
333 T: Send + Sync + 'static,
334 F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
335 {
336 Self::factory::<T, _>(factory).with_scope(ProviderScope::Request)
337 }
338
339 pub fn request_scoped_arc<T, F>(factory: F) -> Self
340 where
341 T: Send + Sync + 'static,
342 F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
343 {
344 Self::factory_arc::<T, _>(factory).with_scope(ProviderScope::Request)
345 }
346
347 pub fn named_request_scoped<T, F>(token: impl Into<String>, factory: F) -> Self
348 where
349 T: Send + Sync + 'static,
350 F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
351 {
352 Self::named_factory::<T, _>(token, factory).with_scope(ProviderScope::Request)
353 }
354
355 pub fn named_request_scoped_arc<T, F>(token: impl Into<String>, factory: F) -> Self
356 where
357 T: Send + Sync + 'static,
358 F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
359 {
360 Self::named_factory_arc::<T, _>(token, factory).with_scope(ProviderScope::Request)
361 }
362
363 pub fn request_scoped_injectable<T>() -> Self
364 where
365 T: FromModuleRef,
366 {
367 Self::injectable::<T>().with_scope(ProviderScope::Request)
368 }
369
370 pub fn named_request_scoped_injectable<T>(token: impl Into<String>) -> Self
371 where
372 T: FromModuleRef,
373 {
374 Self::named_injectable::<T>(token).with_scope(ProviderScope::Request)
375 }
376
377 pub fn with_scope(mut self, scope: ProviderScope) -> Self {
378 self.scope = scope;
379 self
380 }
381
382 pub fn with_on_module_init<T>(mut self) -> Self
383 where
384 T: ProviderOnModuleInit,
385 {
386 self.lifecycle.on_module_init = Some(Arc::new(|provider, module_ref| {
387 let provider = downcast_lifecycle_provider::<T>(provider)?;
388 provider.on_module_init(module_ref)
389 }));
390 self
391 }
392
393 pub fn with_on_application_bootstrap<T>(mut self) -> Self
394 where
395 T: ProviderOnApplicationBootstrap,
396 {
397 self.lifecycle.on_application_bootstrap =
398 Some(Arc::new(
399 |provider, module_ref| match downcast_lifecycle_provider::<T>(provider) {
400 Ok(provider) => provider.on_application_bootstrap(module_ref),
401 Err(error) => Box::pin(async move { Err(error) }),
402 },
403 ));
404 self
405 }
406
407 pub fn with_on_application_shutdown<T>(mut self) -> Self
408 where
409 T: ProviderOnApplicationShutdown,
410 {
411 self.lifecycle.on_application_shutdown =
412 Some(Arc::new(
413 |provider, module_ref| match downcast_lifecycle_provider::<T>(provider) {
414 Ok(provider) => provider.on_application_shutdown(module_ref),
415 Err(error) => Box::pin(async move { Err(error) }),
416 },
417 ));
418 self
419 }
420
421 pub fn token(&self) -> &ProviderToken {
422 &self.token
423 }
424
425 pub fn scope(&self) -> ProviderScope {
426 self.scope
427 }
428
429 pub(super) fn is_alias(&self) -> bool {
430 self.alias_target.is_some()
431 }
432
433 pub(super) fn is_async_factory(&self) -> bool {
434 self.factory.is_async()
435 }
436
437 pub(super) fn alias_target(&self) -> Option<&ProviderToken> {
438 self.alias_target.as_ref()
439 }
440
441 pub(super) fn lifecycle(&self) -> &ProviderLifecycleHooks {
442 &self.lifecycle
443 }
444
445 pub(super) fn build(&self, module_ref: &ModuleRef) -> Result<Arc<AnyProvider>> {
446 match &self.factory {
447 ProviderFactoryKind::Sync(factory) => factory(module_ref),
448 ProviderFactoryKind::Async(_) => Err(BootError::Internal(format!(
449 "async provider factory requires async application build: {}",
450 self.token
451 ))),
452 }
453 }
454
455 pub(super) async fn build_async(&self, module_ref: ModuleRef) -> Result<Arc<AnyProvider>> {
456 match &self.factory {
457 ProviderFactoryKind::Sync(factory) => factory(&module_ref),
458 ProviderFactoryKind::Async(factory) => factory(module_ref).await,
459 }
460 }
461}
462
463fn downcast_lifecycle_provider<T>(provider: Arc<AnyProvider>) -> Result<Arc<T>>
464where
465 T: Send + Sync + 'static,
466{
467 Arc::downcast::<T>(provider)
468 .map_err(|_| BootError::ProviderTypeMismatch(std::any::type_name::<T>().to_string()))
469}