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