Skip to main content

a3s_boot/provider/
definition.rs

1use super::{AnyProvider, ModuleRef, ProviderToken};
2use crate::pipeline::ProviderEnhancerMarker;
3use crate::{
4    BootError, BoxFuture, ExceptionFilter, Guard, Interceptor, Pipe, Result,
5    TransportExceptionFilter, TransportGuard, TransportInterceptor, TransportPipe,
6    WebSocketExceptionFilter, WebSocketGuard, WebSocketInterceptor, WebSocketPipe,
7};
8use std::fmt;
9use std::future::Future;
10use std::sync::Arc;
11
12type ProviderFactory = dyn Fn(&ModuleRef) -> Result<Arc<AnyProvider>> + Send + Sync;
13type AsyncProviderFactory =
14    dyn Fn(ModuleRef) -> BoxFuture<'static, Result<Arc<AnyProvider>>> + Send + Sync;
15type ProviderModuleInitHook = dyn Fn(Arc<AnyProvider>, &ModuleRef) -> Result<()> + Send + Sync;
16type ProviderApplicationHook =
17    dyn Fn(Arc<AnyProvider>, ModuleRef) -> BoxFuture<'static, Result<()>> + Send + Sync;
18type ProviderShutdownHook = dyn Fn(Arc<AnyProvider>, ModuleRef, Option<String>) -> BoxFuture<'static, Result<()>>
19    + Send
20    + Sync;
21
22/// Lifecycle hook for singleton providers that need synchronous module init work.
23pub trait ProviderOnModuleInit: Send + Sync + 'static {
24    fn on_module_init(&self, _module_ref: &ModuleRef) -> Result<()> {
25        Ok(())
26    }
27}
28
29/// Lifecycle hook for singleton providers that need async startup work.
30pub trait ProviderOnApplicationBootstrap: Send + Sync + 'static {
31    fn on_application_bootstrap(&self, _module_ref: ModuleRef) -> BoxFuture<'static, Result<()>> {
32        Box::pin(async { Ok(()) })
33    }
34}
35
36/// Lifecycle hook for singleton providers that need async teardown before shutdown starts.
37pub trait ProviderOnModuleDestroy: Send + Sync + 'static {
38    fn on_module_destroy(
39        &self,
40        _module_ref: ModuleRef,
41        _signal: Option<String>,
42    ) -> BoxFuture<'static, Result<()>> {
43        Box::pin(async { Ok(()) })
44    }
45}
46
47/// Lifecycle hook for singleton providers that need async work before listeners close.
48pub trait ProviderBeforeApplicationShutdown: Send + Sync + 'static {
49    fn before_application_shutdown(
50        &self,
51        _module_ref: ModuleRef,
52        _signal: Option<String>,
53    ) -> BoxFuture<'static, Result<()>> {
54        Box::pin(async { Ok(()) })
55    }
56}
57
58/// Lifecycle hook for singleton providers that need async shutdown cleanup.
59pub trait ProviderOnApplicationShutdown: Send + Sync + 'static {
60    fn on_application_shutdown(&self, _module_ref: ModuleRef) -> BoxFuture<'static, Result<()>> {
61        Box::pin(async { Ok(()) })
62    }
63
64    fn on_application_shutdown_with_signal(
65        &self,
66        module_ref: ModuleRef,
67        _signal: Option<String>,
68    ) -> BoxFuture<'static, Result<()>> {
69        self.on_application_shutdown(module_ref)
70    }
71}
72
73/// Builds an injectable value from the module provider graph.
74pub trait FromModuleRef: Sized + Send + Sync + 'static {
75    fn from_module_ref(module_ref: &ModuleRef) -> Result<Self>;
76
77    /// Dependencies captured while constructing this provider.
78    ///
79    /// `#[injectable]` implements this automatically. Manual implementations
80    /// can return `None` when the dependency graph is opaque.
81    fn provider_dependencies() -> Option<Vec<ProviderDependency>> {
82        None
83    }
84}
85
86/// Lifetime strategy for provider resolution.
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum ProviderScope {
89    Singleton,
90    Request,
91    Transient,
92}
93
94/// One provider dependency used to calculate contextual scope propagation.
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct ProviderDependency {
97    token: ProviderToken,
98    optional: bool,
99    lazy: bool,
100}
101
102impl ProviderDependency {
103    /// Declare a required typed dependency.
104    pub fn typed<T>() -> Self
105    where
106        T: Send + Sync + 'static,
107    {
108        Self::named(ProviderToken::of::<T>().as_str())
109    }
110
111    /// Declare a required named dependency.
112    pub fn named(token: impl Into<String>) -> Self {
113        Self {
114            token: ProviderToken::named(token),
115            optional: false,
116            lazy: false,
117        }
118    }
119
120    /// Mark this dependency as optional when its token is not visible.
121    pub fn optional(mut self) -> Self {
122        self.optional = true;
123        self
124    }
125
126    /// Mark this as a lazy handle that does not participate in scope bubbling.
127    pub fn lazy(mut self) -> Self {
128        self.lazy = true;
129        self
130    }
131
132    pub fn token(&self) -> &ProviderToken {
133        &self.token
134    }
135
136    pub fn is_optional(&self) -> bool {
137        self.optional
138    }
139
140    pub fn is_lazy(&self) -> bool {
141        self.lazy
142    }
143}
144
145/// A provider registration, similar to a Nest provider entry.
146#[derive(Clone)]
147pub struct ProviderDefinition {
148    token: ProviderToken,
149    factory: ProviderFactoryKind,
150    scope: ProviderScope,
151    lifecycle: ProviderLifecycleHooks,
152    alias_target: Option<ProviderToken>,
153    dependencies: Option<Arc<[ProviderDependency]>>,
154    enhancers: Arc<[ProviderEnhancerMarker]>,
155}
156
157#[derive(Clone)]
158enum ProviderFactoryKind {
159    Sync(Arc<ProviderFactory>),
160    Async(Arc<AsyncProviderFactory>),
161}
162
163#[derive(Clone, Default)]
164pub(super) struct ProviderLifecycleHooks {
165    on_module_init: Option<Arc<ProviderModuleInitHook>>,
166    on_application_bootstrap: Option<Arc<ProviderApplicationHook>>,
167    on_module_destroy: Option<Arc<ProviderShutdownHook>>,
168    before_application_shutdown: Option<Arc<ProviderShutdownHook>>,
169    on_application_shutdown: Option<Arc<ProviderShutdownHook>>,
170}
171
172impl ProviderLifecycleHooks {
173    pub(super) fn has_hooks(&self) -> bool {
174        self.on_module_init.is_some()
175            || self.on_application_bootstrap.is_some()
176            || self.on_module_destroy.is_some()
177            || self.before_application_shutdown.is_some()
178            || self.on_application_shutdown.is_some()
179    }
180
181    pub(super) fn on_module_init(&self) -> Option<&Arc<ProviderModuleInitHook>> {
182        self.on_module_init.as_ref()
183    }
184
185    pub(super) fn on_application_bootstrap(&self) -> Option<&Arc<ProviderApplicationHook>> {
186        self.on_application_bootstrap.as_ref()
187    }
188
189    pub(super) fn on_module_destroy(&self) -> Option<&Arc<ProviderShutdownHook>> {
190        self.on_module_destroy.as_ref()
191    }
192
193    pub(super) fn before_application_shutdown(&self) -> Option<&Arc<ProviderShutdownHook>> {
194        self.before_application_shutdown.as_ref()
195    }
196
197    pub(super) fn on_application_shutdown(&self) -> Option<&Arc<ProviderShutdownHook>> {
198        self.on_application_shutdown.as_ref()
199    }
200}
201
202impl fmt::Debug for ProviderDefinition {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        f.debug_struct("ProviderDefinition")
205            .field("token", &self.token)
206            .field("scope", &self.scope)
207            .field("async", &self.factory.is_async())
208            .field("alias_target", &self.alias_target)
209            .field("enhancers", &self.enhancers.len())
210            .field(
211                "dependencies",
212                &self
213                    .dependencies
214                    .as_ref()
215                    .map(|dependencies| dependencies.len()),
216            )
217            .finish_non_exhaustive()
218    }
219}
220
221impl ProviderFactoryKind {
222    fn is_async(&self) -> bool {
223        matches!(self, Self::Async(_))
224    }
225}
226
227impl ProviderDefinition {
228    pub fn singleton<T>(value: T) -> Self
229    where
230        T: Send + Sync + 'static,
231    {
232        Self::from_arc(Arc::new(value))
233    }
234
235    pub fn named_singleton<T>(token: impl Into<String>, value: T) -> Self
236    where
237        T: Send + Sync + 'static,
238    {
239        Self::named_from_arc(token, Arc::new(value))
240    }
241
242    pub fn from_arc<T>(value: Arc<T>) -> Self
243    where
244        T: Send + Sync + 'static,
245    {
246        let token = ProviderToken::of::<T>();
247        Self::named_from_arc(token.as_str(), value)
248    }
249
250    pub fn named_from_arc<T>(token: impl Into<String>, value: Arc<T>) -> Self
251    where
252        T: Send + Sync + 'static,
253    {
254        let token = ProviderToken::named(token);
255        let factory_value = Arc::clone(&value);
256        Self {
257            token,
258            factory: ProviderFactoryKind::Sync(Arc::new(move |_| {
259                Ok(Arc::clone(&factory_value) as Arc<AnyProvider>)
260            })),
261            scope: ProviderScope::Singleton,
262            lifecycle: ProviderLifecycleHooks::default(),
263            alias_target: None,
264            dependencies: Some(Arc::from([])),
265            enhancers: Arc::from([]),
266        }
267    }
268
269    pub fn factory<T, F>(factory: F) -> Self
270    where
271        T: Send + Sync + 'static,
272        F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
273    {
274        Self::named_factory(ProviderToken::of::<T>().as_str(), factory)
275    }
276
277    pub fn factory_arc<T, F>(factory: F) -> Self
278    where
279        T: Send + Sync + 'static,
280        F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
281    {
282        Self::named_factory_arc(ProviderToken::of::<T>().as_str(), factory)
283    }
284
285    pub fn named_factory<T, F>(token: impl Into<String>, factory: F) -> Self
286    where
287        T: Send + Sync + 'static,
288        F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
289    {
290        Self {
291            token: ProviderToken::named(token),
292            factory: ProviderFactoryKind::Sync(Arc::new(move |module_ref| {
293                Ok(Arc::new(factory(module_ref)?) as Arc<AnyProvider>)
294            })),
295            scope: ProviderScope::Singleton,
296            lifecycle: ProviderLifecycleHooks::default(),
297            alias_target: None,
298            dependencies: None,
299            enhancers: Arc::from([]),
300        }
301    }
302
303    pub fn named_factory_arc<T, F>(token: impl Into<String>, factory: F) -> Self
304    where
305        T: Send + Sync + 'static,
306        F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
307    {
308        Self {
309            token: ProviderToken::named(token),
310            factory: ProviderFactoryKind::Sync(Arc::new(move |module_ref| {
311                Ok(factory(module_ref)? as Arc<AnyProvider>)
312            })),
313            scope: ProviderScope::Singleton,
314            lifecycle: ProviderLifecycleHooks::default(),
315            alias_target: None,
316            dependencies: None,
317            enhancers: Arc::from([]),
318        }
319    }
320
321    pub fn async_factory<T, F, Fut>(factory: F) -> Self
322    where
323        T: Send + Sync + 'static,
324        F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
325        Fut: Future<Output = Result<T>> + Send + 'static,
326    {
327        Self::named_async_factory(ProviderToken::of::<T>().as_str(), factory)
328    }
329
330    pub fn async_factory_arc<T, F, Fut>(factory: F) -> Self
331    where
332        T: Send + Sync + 'static,
333        F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
334        Fut: Future<Output = Result<Arc<T>>> + Send + 'static,
335    {
336        Self::named_async_factory_arc(ProviderToken::of::<T>().as_str(), factory)
337    }
338
339    pub fn named_async_factory<T, F, Fut>(token: impl Into<String>, factory: F) -> Self
340    where
341        T: Send + Sync + 'static,
342        F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
343        Fut: Future<Output = Result<T>> + Send + 'static,
344    {
345        Self {
346            token: ProviderToken::named(token),
347            factory: ProviderFactoryKind::Async(Arc::new(move |module_ref| {
348                let future = factory(module_ref);
349                Box::pin(async move { Ok(Arc::new(future.await?) as Arc<AnyProvider>) })
350            })),
351            scope: ProviderScope::Singleton,
352            lifecycle: ProviderLifecycleHooks::default(),
353            alias_target: None,
354            dependencies: None,
355            enhancers: Arc::from([]),
356        }
357    }
358
359    pub fn named_async_factory_arc<T, F, Fut>(token: impl Into<String>, factory: F) -> Self
360    where
361        T: Send + Sync + 'static,
362        F: Fn(ModuleRef) -> Fut + Send + Sync + 'static,
363        Fut: Future<Output = Result<Arc<T>>> + Send + 'static,
364    {
365        Self {
366            token: ProviderToken::named(token),
367            factory: ProviderFactoryKind::Async(Arc::new(move |module_ref| {
368                let future = factory(module_ref);
369                Box::pin(async move { Ok(future.await? as Arc<AnyProvider>) })
370            })),
371            scope: ProviderScope::Singleton,
372            lifecycle: ProviderLifecycleHooks::default(),
373            alias_target: None,
374            dependencies: None,
375            enhancers: Arc::from([]),
376        }
377    }
378
379    pub fn injectable<T>() -> Self
380    where
381        T: FromModuleRef,
382    {
383        let definition = Self::factory::<T, _>(T::from_module_ref);
384        match T::provider_dependencies() {
385            Some(dependencies) => definition.with_dependencies(dependencies),
386            None => definition,
387        }
388    }
389
390    pub fn named_injectable<T>(token: impl Into<String>) -> Self
391    where
392        T: FromModuleRef,
393    {
394        let definition = Self::named_factory::<T, _>(token, T::from_module_ref);
395        match T::provider_dependencies() {
396            Some(dependencies) => definition.with_dependencies(dependencies),
397            None => definition,
398        }
399    }
400
401    pub fn alias<T>(target: ProviderToken) -> Self
402    where
403        T: Send + Sync + 'static,
404    {
405        Self::named_alias(ProviderToken::of::<T>().as_str(), target)
406    }
407
408    pub fn named_alias(token: impl Into<String>, target: ProviderToken) -> Self {
409        Self {
410            token: ProviderToken::named(token),
411            factory: ProviderFactoryKind::Sync(Arc::new(|_| {
412                Err(BootError::Internal(
413                    "provider aliases must be resolved through ModuleRef".to_string(),
414                ))
415            })),
416            scope: ProviderScope::Singleton,
417            lifecycle: ProviderLifecycleHooks::default(),
418            alias_target: Some(target.clone()),
419            dependencies: Some(Arc::from([ProviderDependency {
420                token: target,
421                optional: false,
422                lazy: false,
423            }])),
424            enhancers: Arc::from([]),
425        }
426    }
427
428    pub fn transient<T, F>(factory: F) -> Self
429    where
430        T: Send + Sync + 'static,
431        F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
432    {
433        Self::factory::<T, _>(factory).with_scope(ProviderScope::Transient)
434    }
435
436    pub fn transient_arc<T, F>(factory: F) -> Self
437    where
438        T: Send + Sync + 'static,
439        F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
440    {
441        Self::factory_arc::<T, _>(factory).with_scope(ProviderScope::Transient)
442    }
443
444    pub fn named_transient<T, F>(token: impl Into<String>, factory: F) -> Self
445    where
446        T: Send + Sync + 'static,
447        F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
448    {
449        Self::named_factory::<T, _>(token, factory).with_scope(ProviderScope::Transient)
450    }
451
452    pub fn named_transient_arc<T, F>(token: impl Into<String>, factory: F) -> Self
453    where
454        T: Send + Sync + 'static,
455        F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
456    {
457        Self::named_factory_arc::<T, _>(token, factory).with_scope(ProviderScope::Transient)
458    }
459
460    pub fn transient_injectable<T>() -> Self
461    where
462        T: FromModuleRef,
463    {
464        Self::injectable::<T>().with_scope(ProviderScope::Transient)
465    }
466
467    pub fn named_transient_injectable<T>(token: impl Into<String>) -> Self
468    where
469        T: FromModuleRef,
470    {
471        Self::named_injectable::<T>(token).with_scope(ProviderScope::Transient)
472    }
473
474    pub fn request_scoped<T, F>(factory: F) -> Self
475    where
476        T: Send + Sync + 'static,
477        F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
478    {
479        Self::factory::<T, _>(factory).with_scope(ProviderScope::Request)
480    }
481
482    pub fn request_scoped_arc<T, F>(factory: F) -> Self
483    where
484        T: Send + Sync + 'static,
485        F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
486    {
487        Self::factory_arc::<T, _>(factory).with_scope(ProviderScope::Request)
488    }
489
490    pub fn named_request_scoped<T, F>(token: impl Into<String>, factory: F) -> Self
491    where
492        T: Send + Sync + 'static,
493        F: Fn(&ModuleRef) -> Result<T> + Send + Sync + 'static,
494    {
495        Self::named_factory::<T, _>(token, factory).with_scope(ProviderScope::Request)
496    }
497
498    pub fn named_request_scoped_arc<T, F>(token: impl Into<String>, factory: F) -> Self
499    where
500        T: Send + Sync + 'static,
501        F: Fn(&ModuleRef) -> Result<Arc<T>> + Send + Sync + 'static,
502    {
503        Self::named_factory_arc::<T, _>(token, factory).with_scope(ProviderScope::Request)
504    }
505
506    pub fn request_scoped_injectable<T>() -> Self
507    where
508        T: FromModuleRef,
509    {
510        Self::injectable::<T>().with_scope(ProviderScope::Request)
511    }
512
513    pub fn named_request_scoped_injectable<T>(token: impl Into<String>) -> Self
514    where
515        T: FromModuleRef,
516    {
517        Self::named_injectable::<T>(token).with_scope(ProviderScope::Request)
518    }
519
520    /// Register an injectable provider as an application-wide HTTP guard.
521    pub fn app_guard<T>() -> Self
522    where
523        T: FromModuleRef + Guard,
524    {
525        Self::injectable::<T>().with_app_guard::<T>()
526    }
527
528    /// Register an injectable provider as an application-wide HTTP pipe.
529    pub fn app_pipe<T>() -> Self
530    where
531        T: FromModuleRef + Pipe,
532    {
533        Self::injectable::<T>().with_app_pipe::<T>()
534    }
535
536    /// Register an injectable provider as an application-wide HTTP interceptor.
537    pub fn app_interceptor<T>() -> Self
538    where
539        T: FromModuleRef + Interceptor,
540    {
541        Self::injectable::<T>().with_app_interceptor::<T>()
542    }
543
544    /// Register an injectable provider as an application-wide HTTP exception filter.
545    pub fn app_filter<T>() -> Self
546    where
547        T: FromModuleRef + ExceptionFilter,
548    {
549        Self::injectable::<T>().with_app_filter::<T>()
550    }
551
552    /// Register an injectable provider as an application-wide WebSocket guard.
553    pub fn app_websocket_guard<T>() -> Self
554    where
555        T: FromModuleRef + WebSocketGuard,
556    {
557        Self::injectable::<T>().with_app_websocket_guard::<T>()
558    }
559
560    /// Register an injectable provider as an application-wide WebSocket pipe.
561    pub fn app_websocket_pipe<T>() -> Self
562    where
563        T: FromModuleRef + WebSocketPipe,
564    {
565        Self::injectable::<T>().with_app_websocket_pipe::<T>()
566    }
567
568    /// Register an injectable provider as an application-wide WebSocket interceptor.
569    pub fn app_websocket_interceptor<T>() -> Self
570    where
571        T: FromModuleRef + WebSocketInterceptor,
572    {
573        Self::injectable::<T>().with_app_websocket_interceptor::<T>()
574    }
575
576    /// Register an injectable provider as an application-wide WebSocket exception filter.
577    pub fn app_websocket_filter<T>() -> Self
578    where
579        T: FromModuleRef + WebSocketExceptionFilter,
580    {
581        Self::injectable::<T>().with_app_websocket_filter::<T>()
582    }
583
584    /// Register an injectable provider as an application-wide transport guard.
585    pub fn app_transport_guard<T>() -> Self
586    where
587        T: FromModuleRef + TransportGuard,
588    {
589        Self::injectable::<T>().with_app_transport_guard::<T>()
590    }
591
592    /// Register an injectable provider as an application-wide transport pipe.
593    pub fn app_transport_pipe<T>() -> Self
594    where
595        T: FromModuleRef + TransportPipe,
596    {
597        Self::injectable::<T>().with_app_transport_pipe::<T>()
598    }
599
600    /// Register an injectable provider as an application-wide transport interceptor.
601    pub fn app_transport_interceptor<T>() -> Self
602    where
603        T: FromModuleRef + TransportInterceptor,
604    {
605        Self::injectable::<T>().with_app_transport_interceptor::<T>()
606    }
607
608    /// Register an injectable provider as an application-wide transport exception filter.
609    pub fn app_transport_filter<T>() -> Self
610    where
611        T: FromModuleRef + TransportExceptionFilter,
612    {
613        Self::injectable::<T>().with_app_transport_filter::<T>()
614    }
615
616    /// Mark this provider as an application-wide HTTP guard.
617    pub fn with_app_guard<T>(self) -> Self
618    where
619        T: Guard,
620    {
621        let token = self.token.clone();
622        self.with_enhancer(ProviderEnhancerMarker::guard::<T>(token))
623    }
624
625    /// Mark this provider as an application-wide HTTP pipe.
626    pub fn with_app_pipe<T>(self) -> Self
627    where
628        T: Pipe,
629    {
630        let token = self.token.clone();
631        self.with_enhancer(ProviderEnhancerMarker::pipe::<T>(token))
632    }
633
634    /// Mark this provider as an application-wide HTTP interceptor.
635    pub fn with_app_interceptor<T>(self) -> Self
636    where
637        T: Interceptor,
638    {
639        let token = self.token.clone();
640        self.with_enhancer(ProviderEnhancerMarker::interceptor::<T>(token))
641    }
642
643    /// Mark this provider as an application-wide HTTP exception filter.
644    pub fn with_app_filter<T>(self) -> Self
645    where
646        T: ExceptionFilter,
647    {
648        let token = self.token.clone();
649        self.with_enhancer(ProviderEnhancerMarker::filter::<T>(token))
650    }
651
652    /// Mark this provider as an application-wide WebSocket guard.
653    pub fn with_app_websocket_guard<T>(self) -> Self
654    where
655        T: WebSocketGuard,
656    {
657        let token = self.token.clone();
658        self.with_enhancer(ProviderEnhancerMarker::websocket_guard::<T>(token))
659    }
660
661    /// Mark this provider as an application-wide WebSocket pipe.
662    pub fn with_app_websocket_pipe<T>(self) -> Self
663    where
664        T: WebSocketPipe,
665    {
666        let token = self.token.clone();
667        self.with_enhancer(ProviderEnhancerMarker::websocket_pipe::<T>(token))
668    }
669
670    /// Mark this provider as an application-wide WebSocket interceptor.
671    pub fn with_app_websocket_interceptor<T>(self) -> Self
672    where
673        T: WebSocketInterceptor,
674    {
675        let token = self.token.clone();
676        self.with_enhancer(ProviderEnhancerMarker::websocket_interceptor::<T>(token))
677    }
678
679    /// Mark this provider as an application-wide WebSocket exception filter.
680    pub fn with_app_websocket_filter<T>(self) -> Self
681    where
682        T: WebSocketExceptionFilter,
683    {
684        let token = self.token.clone();
685        self.with_enhancer(ProviderEnhancerMarker::websocket_filter::<T>(token))
686    }
687
688    /// Mark this provider as an application-wide transport guard.
689    pub fn with_app_transport_guard<T>(self) -> Self
690    where
691        T: TransportGuard,
692    {
693        let token = self.token.clone();
694        self.with_enhancer(ProviderEnhancerMarker::transport_guard::<T>(token))
695    }
696
697    /// Mark this provider as an application-wide transport pipe.
698    pub fn with_app_transport_pipe<T>(self) -> Self
699    where
700        T: TransportPipe,
701    {
702        let token = self.token.clone();
703        self.with_enhancer(ProviderEnhancerMarker::transport_pipe::<T>(token))
704    }
705
706    /// Mark this provider as an application-wide transport interceptor.
707    pub fn with_app_transport_interceptor<T>(self) -> Self
708    where
709        T: TransportInterceptor,
710    {
711        let token = self.token.clone();
712        self.with_enhancer(ProviderEnhancerMarker::transport_interceptor::<T>(token))
713    }
714
715    /// Mark this provider as an application-wide transport exception filter.
716    pub fn with_app_transport_filter<T>(self) -> Self
717    where
718        T: TransportExceptionFilter,
719    {
720        let token = self.token.clone();
721        self.with_enhancer(ProviderEnhancerMarker::transport_filter::<T>(token))
722    }
723
724    pub fn with_scope(mut self, scope: ProviderScope) -> Self {
725        self.scope = scope;
726        self
727    }
728
729    fn with_enhancer(mut self, enhancer: ProviderEnhancerMarker) -> Self {
730        let mut enhancers = self.enhancers.to_vec();
731        enhancers.push(enhancer);
732        self.enhancers = enhancers.into();
733        self
734    }
735
736    /// Declare the dependencies captured by this provider factory.
737    pub fn with_dependencies<I>(mut self, dependencies: I) -> Self
738    where
739        I: IntoIterator<Item = ProviderDependency>,
740    {
741        self.dependencies = Some(dependencies.into_iter().collect::<Vec<_>>().into());
742        self
743    }
744
745    /// Add one required typed dependency to this provider factory.
746    pub fn depends_on<T>(self) -> Self
747    where
748        T: Send + Sync + 'static,
749    {
750        self.with_dependency(ProviderDependency::typed::<T>())
751    }
752
753    /// Add one required named dependency to this provider factory.
754    pub fn depends_on_named(self, token: impl Into<String>) -> Self {
755        self.with_dependency(ProviderDependency::named(token))
756    }
757
758    /// Add one dependency while retaining previously declared metadata.
759    pub fn with_dependency(mut self, dependency: ProviderDependency) -> Self {
760        let mut dependencies = self
761            .dependencies
762            .as_deref()
763            .map(<[ProviderDependency]>::to_vec)
764            .unwrap_or_default();
765        dependencies.push(dependency);
766        self.dependencies = Some(dependencies.into());
767        self
768    }
769
770    pub fn with_on_module_init<T>(mut self) -> Self
771    where
772        T: ProviderOnModuleInit,
773    {
774        self.lifecycle.on_module_init = Some(Arc::new(|provider, module_ref| {
775            let provider = downcast_lifecycle_provider::<T>(provider)?;
776            provider.on_module_init(module_ref)
777        }));
778        self
779    }
780
781    pub fn with_on_application_bootstrap<T>(mut self) -> Self
782    where
783        T: ProviderOnApplicationBootstrap,
784    {
785        self.lifecycle.on_application_bootstrap =
786            Some(Arc::new(
787                |provider, module_ref| match downcast_lifecycle_provider::<T>(provider) {
788                    Ok(provider) => provider.on_application_bootstrap(module_ref),
789                    Err(error) => Box::pin(async move { Err(error) }),
790                },
791            ));
792        self
793    }
794
795    pub fn with_on_module_destroy<T>(mut self) -> Self
796    where
797        T: ProviderOnModuleDestroy,
798    {
799        self.lifecycle.on_module_destroy =
800            Some(Arc::new(
801                |provider, module_ref, signal| match downcast_lifecycle_provider::<T>(provider) {
802                    Ok(provider) => provider.on_module_destroy(module_ref, signal),
803                    Err(error) => Box::pin(async move { Err(error) }),
804                },
805            ));
806        self
807    }
808
809    pub fn with_before_application_shutdown<T>(mut self) -> Self
810    where
811        T: ProviderBeforeApplicationShutdown,
812    {
813        self.lifecycle.before_application_shutdown = Some(Arc::new(
814            |provider, module_ref, signal| match downcast_lifecycle_provider::<T>(provider) {
815                Ok(provider) => provider.before_application_shutdown(module_ref, signal),
816                Err(error) => Box::pin(async move { Err(error) }),
817            },
818        ));
819        self
820    }
821
822    pub fn with_on_application_shutdown<T>(mut self) -> Self
823    where
824        T: ProviderOnApplicationShutdown,
825    {
826        self.lifecycle.on_application_shutdown =
827            Some(Arc::new(
828                |provider, module_ref, signal| match downcast_lifecycle_provider::<T>(provider) {
829                    Ok(provider) => {
830                        provider.on_application_shutdown_with_signal(module_ref, signal)
831                    }
832                    Err(error) => Box::pin(async move { Err(error) }),
833                },
834            ));
835        self
836    }
837
838    pub fn token(&self) -> &ProviderToken {
839        &self.token
840    }
841
842    pub fn scope(&self) -> ProviderScope {
843        self.scope
844    }
845
846    /// Declared dependency metadata, or `None` for an opaque factory.
847    pub fn dependencies(&self) -> Option<&[ProviderDependency]> {
848        self.dependencies.as_deref()
849    }
850
851    pub(super) fn is_alias(&self) -> bool {
852        self.alias_target.is_some()
853    }
854
855    pub(super) fn is_async_factory(&self) -> bool {
856        self.factory.is_async()
857    }
858
859    pub(super) fn alias_target(&self) -> Option<&ProviderToken> {
860        self.alias_target.as_ref()
861    }
862
863    pub(super) fn lifecycle(&self) -> &ProviderLifecycleHooks {
864        &self.lifecycle
865    }
866
867    pub(crate) fn enhancer_markers(&self) -> &[ProviderEnhancerMarker] {
868        &self.enhancers
869    }
870
871    pub(crate) fn with_enhancers_from(mut self, source: &Self) -> Self {
872        self.enhancers = Arc::clone(&source.enhancers);
873        self
874    }
875
876    pub(super) fn build(&self, module_ref: &ModuleRef) -> Result<Arc<AnyProvider>> {
877        match &self.factory {
878            ProviderFactoryKind::Sync(factory) => factory(module_ref),
879            ProviderFactoryKind::Async(_) => Err(BootError::Internal(format!(
880                "async provider factory requires async application build: {}",
881                self.token
882            ))),
883        }
884    }
885
886    pub(super) async fn build_async(&self, module_ref: ModuleRef) -> Result<Arc<AnyProvider>> {
887        match &self.factory {
888            ProviderFactoryKind::Sync(factory) => factory(&module_ref),
889            ProviderFactoryKind::Async(factory) => factory(module_ref).await,
890        }
891    }
892}
893
894fn downcast_lifecycle_provider<T>(provider: Arc<AnyProvider>) -> Result<Arc<T>>
895where
896    T: Send + Sync + 'static,
897{
898    Arc::downcast::<T>(provider)
899        .map_err(|_| BootError::ProviderTypeMismatch(std::any::type_name::<T>().to_string()))
900}