Skip to main content

blazingly_di/
lib.rs

1#![forbid(unsafe_code)]
2
3use blazingly_contract::OperationFailure;
4use core::any::{Any, TypeId};
5use core::fmt;
6use core::future::Future;
7use core::ops::Deref;
8use core::pin::Pin;
9use std::rc::Rc;
10
11/// A resolved typed dependency passed to a handler or provider.
12#[derive(Clone, Debug)]
13pub struct Depends<T> {
14    value: Rc<T>,
15}
16
17impl<T> Depends<T> {
18    #[doc(hidden)]
19    #[must_use]
20    pub const fn from_rc(value: Rc<T>) -> Self {
21        Self { value }
22    }
23
24    #[must_use]
25    pub fn into_inner(self) -> Rc<T> {
26        self.value
27    }
28}
29
30impl<T> Deref for Depends<T> {
31    type Target = T;
32
33    fn deref(&self) -> &Self::Target {
34        &self.value
35    }
36}
37
38/// The lifetime of a dependency provider.
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub enum DependencyLifetime {
41    /// Created once while the executable application is compiled.
42    Singleton,
43    /// Created once for each operation invocation that needs it.
44    Request,
45    /// Created independently for every injection edge.
46    Transient,
47}
48
49/// Runtime identity of a typed dependency.
50#[derive(Clone, Copy, Eq, Hash, PartialEq)]
51pub struct DependencyKey {
52    type_id: TypeId,
53    type_name: &'static str,
54}
55
56impl DependencyKey {
57    #[must_use]
58    pub fn of<T: 'static>() -> Self {
59        Self {
60            type_id: TypeId::of::<T>(),
61            type_name: core::any::type_name::<T>(),
62        }
63    }
64
65    #[must_use]
66    pub const fn type_id(self) -> TypeId {
67        self.type_id
68    }
69
70    #[must_use]
71    pub const fn type_name(self) -> &'static str {
72        self.type_name
73    }
74}
75
76impl fmt::Debug for DependencyKey {
77    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
78        formatter
79            .debug_tuple("DependencyKey")
80            .field(&self.type_name)
81            .finish()
82    }
83}
84
85/// A dependency required by one operation handler.
86#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
87pub struct DependencyRequest {
88    key: DependencyKey,
89}
90
91impl DependencyRequest {
92    #[must_use]
93    pub fn of<T: 'static>() -> Self {
94        Self {
95            key: DependencyKey::of::<T>(),
96        }
97    }
98
99    #[must_use]
100    pub const fn key(self) -> DependencyKey {
101        self.key
102    }
103}
104
105/// A stable request rejection or an internal dependency failure.
106#[derive(Clone, Debug, PartialEq)]
107pub enum DependencyError {
108    Rejected(OperationFailure),
109    Internal { code: &'static str, message: String },
110}
111
112impl DependencyError {
113    #[must_use]
114    pub const fn rejected(failure: OperationFailure) -> Self {
115        Self::Rejected(failure)
116    }
117
118    #[must_use]
119    pub fn internal(code: &'static str, message: impl Into<String>) -> Self {
120        Self::Internal {
121            code,
122            message: message.into(),
123        }
124    }
125}
126
127impl fmt::Display for DependencyError {
128    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
129        match self {
130            Self::Rejected(failure) => write!(formatter, "{}", failure.message),
131            Self::Internal { message, .. } => formatter.write_str(message),
132        }
133    }
134}
135
136impl std::error::Error for DependencyError {}
137
138#[doc(hidden)]
139pub type DependencyValue = Rc<dyn Any>;
140
141/// A numeric source selected by the dependency compiler.
142#[doc(hidden)]
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
144pub enum DependencySlot {
145    Singleton(usize),
146    Request(usize),
147}
148
149/// A provider with all of its dependency slots compiled.
150#[doc(hidden)]
151#[derive(Clone)]
152pub struct CompiledProvider {
153    runner: ProviderRunner,
154    finalizer: Option<ProviderFinalizer>,
155}
156
157type SyncProviderRunner = Rc<
158    dyn Fn(
159        &[Option<DependencyValue>],
160        &[Option<DependencyValue>],
161    ) -> Result<DependencyValue, DependencyError>,
162>;
163type ProviderFuture =
164    Pin<Box<dyn Future<Output = Result<DependencyValue, DependencyError>> + 'static>>;
165type AsyncProviderRunner =
166    Rc<dyn Fn(&[Option<DependencyValue>], &[Option<DependencyValue>]) -> ProviderFuture>;
167
168#[derive(Clone)]
169enum ProviderRunner {
170    Sync(SyncProviderRunner),
171    Async(AsyncProviderRunner),
172}
173
174type SyncProviderFinalizer = Rc<dyn Fn(&DependencyValue) -> Result<(), DependencyError>>;
175type FinalizerFuture = Pin<Box<dyn Future<Output = Result<(), DependencyError>> + 'static>>;
176type AsyncProviderFinalizer = Rc<dyn Fn(&DependencyValue) -> FinalizerFuture>;
177
178#[derive(Clone)]
179enum ProviderFinalizer {
180    Sync(SyncProviderFinalizer),
181    Async(AsyncProviderFinalizer),
182}
183
184impl CompiledProvider {
185    #[doc(hidden)]
186    #[must_use]
187    pub fn run(
188        &self,
189        singletons: &[Option<DependencyValue>],
190        requests: &[Option<DependencyValue>],
191    ) -> ProviderFuture {
192        match &self.runner {
193            ProviderRunner::Sync(runner) => {
194                let result = runner(singletons, requests);
195                Box::pin(async move { result })
196            }
197            ProviderRunner::Async(runner) => runner(singletons, requests),
198        }
199    }
200
201    #[doc(hidden)]
202    pub fn run_sync(
203        &self,
204        singletons: &[Option<DependencyValue>],
205        requests: &[Option<DependencyValue>],
206    ) -> Result<DependencyValue, DependencyError> {
207        match &self.runner {
208            ProviderRunner::Sync(runner) => runner(singletons, requests),
209            ProviderRunner::Async(_) => Err(DependencyError::internal(
210                "async_singleton_provider",
211                "async providers cannot use the singleton lifetime",
212            )),
213        }
214    }
215
216    #[doc(hidden)]
217    pub fn finalize(&self, value: &DependencyValue) -> FinalizerFuture {
218        match &self.finalizer {
219            None => Box::pin(async { Ok(()) }),
220            Some(ProviderFinalizer::Sync(finalizer)) => {
221                let result = finalizer(value);
222                Box::pin(async move { result })
223            }
224            Some(ProviderFinalizer::Async(finalizer)) => finalizer(value),
225        }
226    }
227}
228
229/// Internal compilation error. A valid framework-generated plan never exposes
230/// this to request handling.
231#[doc(hidden)]
232#[derive(Clone, Copy, Debug, Eq, PartialEq)]
233pub struct ProviderCompileError {
234    expected: usize,
235    actual: usize,
236}
237
238impl ProviderCompileError {
239    const fn arity(expected: usize, actual: usize) -> Self {
240        Self { expected, actual }
241    }
242}
243
244impl fmt::Display for ProviderCompileError {
245    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
246        write!(
247            formatter,
248            "provider expected {} dependency slots but received {}",
249            self.expected, self.actual
250        )
251    }
252}
253
254impl std::error::Error for ProviderCompileError {}
255
256type ProviderCompiler =
257    Rc<dyn Fn(&[DependencySlot]) -> Result<CompiledProvider, ProviderCompileError>>;
258
259/// A typed dependency provider registered in a plugin scope.
260#[derive(Clone)]
261pub struct Provider {
262    key: DependencyKey,
263    lifetime: DependencyLifetime,
264    dependencies: Vec<DependencyKey>,
265    compiler: ProviderCompiler,
266    finalizer: Option<ProviderFinalizer>,
267}
268
269impl Provider {
270    /// Registers an already-created singleton value.
271    #[must_use]
272    pub fn value<T: 'static>(value: T) -> Self {
273        let value: DependencyValue = Rc::new(value);
274        let compiler = Rc::new(move |slots: &[DependencySlot]| {
275            if !slots.is_empty() {
276                return Err(ProviderCompileError::arity(0, slots.len()));
277            }
278            let value = Rc::clone(&value);
279            Ok(CompiledProvider {
280                runner: ProviderRunner::Sync(Rc::new(move |_, _| Ok(Rc::clone(&value)))),
281                finalizer: None,
282            })
283        });
284        Self {
285            key: DependencyKey::of::<T>(),
286            lifetime: DependencyLifetime::Singleton,
287            dependencies: Vec::new(),
288            compiler,
289            finalizer: None,
290        }
291    }
292
293    /// Registers an infallible singleton factory.
294    #[must_use]
295    pub fn singleton<Arguments, Output, Factory>(factory: Factory) -> Self
296    where
297        Factory: ProviderFactory<Arguments, Output>,
298        Output: 'static,
299    {
300        Self::from_factory(DependencyLifetime::Singleton, factory)
301    }
302
303    /// Registers an infallible request-scoped factory.
304    #[must_use]
305    pub fn request<Arguments, Output, Factory>(factory: Factory) -> Self
306    where
307        Factory: ProviderFactory<Arguments, Output>,
308        Output: 'static,
309    {
310        Self::from_factory(DependencyLifetime::Request, factory)
311    }
312
313    /// Registers an infallible transient factory.
314    #[must_use]
315    pub fn transient<Arguments, Output, Factory>(factory: Factory) -> Self
316    where
317        Factory: ProviderFactory<Arguments, Output>,
318        Output: 'static,
319    {
320        Self::from_factory(DependencyLifetime::Transient, factory)
321    }
322
323    /// Registers a fallible singleton factory.
324    #[must_use]
325    pub fn try_singleton<Arguments, Output, Factory>(factory: Factory) -> Self
326    where
327        Factory: FallibleProviderFactory<Arguments, Output>,
328        Output: 'static,
329    {
330        Self::from_fallible_factory(DependencyLifetime::Singleton, factory)
331    }
332
333    /// Registers a fallible request-scoped factory.
334    #[must_use]
335    pub fn try_request<Arguments, Output, Factory>(factory: Factory) -> Self
336    where
337        Factory: FallibleProviderFactory<Arguments, Output>,
338        Output: 'static,
339    {
340        Self::from_fallible_factory(DependencyLifetime::Request, factory)
341    }
342
343    /// Registers a fallible transient factory.
344    #[must_use]
345    pub fn try_transient<Arguments, Output, Factory>(factory: Factory) -> Self
346    where
347        Factory: FallibleProviderFactory<Arguments, Output>,
348        Output: 'static,
349    {
350        Self::from_fallible_factory(DependencyLifetime::Transient, factory)
351    }
352
353    /// Registers a request provider with a reverse-order finalizer.
354    #[must_use]
355    pub fn request_scoped<Arguments, Output, Factory, Finalizer>(
356        factory: Factory,
357        finalizer: Finalizer,
358    ) -> Self
359    where
360        Factory: ProviderFactory<Arguments, Output>,
361        Finalizer: Fn(Depends<Output>) + 'static,
362        Output: 'static,
363    {
364        let mut provider = Self::from_factory(DependencyLifetime::Request, factory);
365        provider.finalizer = Some(typed_finalizer(finalizer));
366        provider
367    }
368
369    /// Registers a fallible request provider with a reverse-order finalizer.
370    #[must_use]
371    pub fn try_request_scoped<Arguments, Output, Factory, Finalizer>(
372        factory: Factory,
373        finalizer: Finalizer,
374    ) -> Self
375    where
376        Factory: FallibleProviderFactory<Arguments, Output>,
377        Finalizer: Fn(Depends<Output>) + 'static,
378        Output: 'static,
379    {
380        let mut provider = Self::from_fallible_factory(DependencyLifetime::Request, factory);
381        provider.finalizer = Some(typed_finalizer(finalizer));
382        provider
383    }
384
385    /// Registers an async request-scoped factory.
386    #[must_use]
387    pub fn request_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
388    where
389        Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
390        FactoryFuture: Future<Output = Output> + 'static,
391        Output: 'static,
392    {
393        Self::from_async_factory(DependencyLifetime::Request, factory)
394    }
395
396    /// Registers an async transient factory.
397    #[must_use]
398    pub fn transient_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
399    where
400        Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
401        FactoryFuture: Future<Output = Output> + 'static,
402        Output: 'static,
403    {
404        Self::from_async_factory(DependencyLifetime::Transient, factory)
405    }
406
407    /// Registers a fallible async request-scoped factory.
408    #[must_use]
409    pub fn try_request_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
410    where
411        Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
412        FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
413        Output: 'static,
414    {
415        Self::from_fallible_async_factory(DependencyLifetime::Request, factory)
416    }
417
418    /// Registers a fallible async transient factory.
419    #[must_use]
420    pub fn try_transient_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
421    where
422        Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
423        FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
424        Output: 'static,
425    {
426        Self::from_fallible_async_factory(DependencyLifetime::Transient, factory)
427    }
428
429    /// Registers an async request provider with an async finalizer.
430    #[must_use]
431    pub fn request_async_scoped<
432        Arguments,
433        Output,
434        Factory,
435        FactoryFuture,
436        Finalizer,
437        FinalizerFuture,
438    >(
439        factory: Factory,
440        finalizer: Finalizer,
441    ) -> Self
442    where
443        Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
444        FactoryFuture: Future<Output = Output> + 'static,
445        Finalizer: Fn(Depends<Output>) -> FinalizerFuture + 'static,
446        FinalizerFuture: Future<Output = ()> + 'static,
447        Output: 'static,
448    {
449        let mut provider = Self::from_async_factory(DependencyLifetime::Request, factory);
450        provider.finalizer = Some(typed_async_finalizer(finalizer));
451        provider
452    }
453
454    /// Registers a fallible async request provider with an async finalizer.
455    #[must_use]
456    pub fn try_request_async_scoped<
457        Arguments,
458        Output,
459        Factory,
460        FactoryFuture,
461        Finalizer,
462        FinalizerFuture,
463    >(
464        factory: Factory,
465        finalizer: Finalizer,
466    ) -> Self
467    where
468        Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
469        FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
470        Finalizer: Fn(Depends<Output>) -> FinalizerFuture + 'static,
471        FinalizerFuture: Future<Output = ()> + 'static,
472        Output: 'static,
473    {
474        let mut provider = Self::from_fallible_async_factory(DependencyLifetime::Request, factory);
475        provider.finalizer = Some(typed_async_finalizer(finalizer));
476        provider
477    }
478
479    fn from_factory<Arguments, Output, Factory>(
480        lifetime: DependencyLifetime,
481        factory: Factory,
482    ) -> Self
483    where
484        Factory: ProviderFactory<Arguments, Output>,
485        Output: 'static,
486    {
487        let dependencies = Factory::dependency_keys();
488        let factory = Rc::new(factory);
489        let compiler =
490            Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
491        Self {
492            key: DependencyKey::of::<Output>(),
493            lifetime,
494            dependencies,
495            compiler,
496            finalizer: None,
497        }
498    }
499
500    fn from_fallible_factory<Arguments, Output, Factory>(
501        lifetime: DependencyLifetime,
502        factory: Factory,
503    ) -> Self
504    where
505        Factory: FallibleProviderFactory<Arguments, Output>,
506        Output: 'static,
507    {
508        let dependencies = Factory::dependency_keys();
509        let factory = Rc::new(factory);
510        let compiler =
511            Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
512        Self {
513            key: DependencyKey::of::<Output>(),
514            lifetime,
515            dependencies,
516            compiler,
517            finalizer: None,
518        }
519    }
520
521    fn from_async_factory<Arguments, Output, Factory, FactoryFuture>(
522        lifetime: DependencyLifetime,
523        factory: Factory,
524    ) -> Self
525    where
526        Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
527        FactoryFuture: Future<Output = Output> + 'static,
528        Output: 'static,
529    {
530        let dependencies = Factory::dependency_keys();
531        let factory = Rc::new(factory);
532        let compiler =
533            Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
534        Self {
535            key: DependencyKey::of::<Output>(),
536            lifetime,
537            dependencies,
538            compiler,
539            finalizer: None,
540        }
541    }
542
543    fn from_fallible_async_factory<Arguments, Output, Factory, FactoryFuture>(
544        lifetime: DependencyLifetime,
545        factory: Factory,
546    ) -> Self
547    where
548        Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
549        FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
550        Output: 'static,
551    {
552        let dependencies = Factory::dependency_keys();
553        let factory = Rc::new(factory);
554        let compiler =
555            Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
556        Self {
557            key: DependencyKey::of::<Output>(),
558            lifetime,
559            dependencies,
560            compiler,
561            finalizer: None,
562        }
563    }
564
565    #[must_use]
566    pub const fn key(&self) -> DependencyKey {
567        self.key
568    }
569
570    #[must_use]
571    pub const fn lifetime(&self) -> DependencyLifetime {
572        self.lifetime
573    }
574
575    #[must_use]
576    pub fn dependencies(&self) -> &[DependencyKey] {
577        &self.dependencies
578    }
579
580    #[doc(hidden)]
581    pub fn compile(
582        &self,
583        slots: &[DependencySlot],
584    ) -> Result<CompiledProvider, ProviderCompileError> {
585        let mut compiled = (self.compiler)(slots)?;
586        compiled.finalizer.clone_from(&self.finalizer);
587        Ok(compiled)
588    }
589}
590
591/// Converts an infallible typed closure into a provider factory.
592#[doc(hidden)]
593pub trait ProviderFactory<Arguments, Output>: 'static {
594    fn dependency_keys() -> Vec<DependencyKey>;
595
596    fn compile(
597        factory: Rc<Self>,
598        slots: &[DependencySlot],
599    ) -> Result<CompiledProvider, ProviderCompileError>;
600}
601
602/// Converts a fallible typed closure into a provider factory.
603#[doc(hidden)]
604pub trait FallibleProviderFactory<Arguments, Output>: 'static {
605    fn dependency_keys() -> Vec<DependencyKey>;
606
607    fn compile(
608        factory: Rc<Self>,
609        slots: &[DependencySlot],
610    ) -> Result<CompiledProvider, ProviderCompileError>;
611}
612
613/// Converts an async typed closure into a provider factory.
614#[doc(hidden)]
615pub trait AsyncProviderFactory<Arguments, Output, FactoryFuture>: 'static
616where
617    FactoryFuture: Future<Output = Output> + 'static,
618{
619    fn dependency_keys() -> Vec<DependencyKey>;
620
621    fn compile(
622        factory: Rc<Self>,
623        slots: &[DependencySlot],
624    ) -> Result<CompiledProvider, ProviderCompileError>;
625}
626
627/// Converts a fallible async typed closure into a provider factory.
628#[doc(hidden)]
629pub trait FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>: 'static
630where
631    FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
632{
633    fn dependency_keys() -> Vec<DependencyKey>;
634
635    fn compile(
636        factory: Rc<Self>,
637        slots: &[DependencySlot],
638    ) -> Result<CompiledProvider, ProviderCompileError>;
639}
640
641impl<Factory, Output> ProviderFactory<(), Output> for Factory
642where
643    Factory: Fn() -> Output + 'static,
644    Output: 'static,
645{
646    fn dependency_keys() -> Vec<DependencyKey> {
647        Vec::new()
648    }
649
650    fn compile(
651        factory: Rc<Self>,
652        slots: &[DependencySlot],
653    ) -> Result<CompiledProvider, ProviderCompileError> {
654        expect_arity(slots, 0)?;
655        Ok(CompiledProvider {
656            runner: ProviderRunner::Sync(Rc::new(move |_, _| {
657                Ok(Rc::new(factory()) as DependencyValue)
658            })),
659            finalizer: None,
660        })
661    }
662}
663
664impl<Factory, Output, FactoryFuture> AsyncProviderFactory<(), Output, FactoryFuture> for Factory
665where
666    Factory: Fn() -> FactoryFuture + 'static,
667    FactoryFuture: Future<Output = Output> + 'static,
668    Output: 'static,
669{
670    fn dependency_keys() -> Vec<DependencyKey> {
671        Vec::new()
672    }
673
674    fn compile(
675        factory: Rc<Self>,
676        slots: &[DependencySlot],
677    ) -> Result<CompiledProvider, ProviderCompileError> {
678        expect_arity(slots, 0)?;
679        Ok(CompiledProvider {
680            runner: ProviderRunner::Async(Rc::new(move |_, _| {
681                let future = factory();
682                Box::pin(async move { Ok(Rc::new(future.await) as DependencyValue) })
683            })),
684            finalizer: None,
685        })
686    }
687}
688
689impl<Factory, Output, FactoryFuture> FallibleAsyncProviderFactory<(), Output, FactoryFuture>
690    for Factory
691where
692    Factory: Fn() -> FactoryFuture + 'static,
693    FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
694    Output: 'static,
695{
696    fn dependency_keys() -> Vec<DependencyKey> {
697        Vec::new()
698    }
699
700    fn compile(
701        factory: Rc<Self>,
702        slots: &[DependencySlot],
703    ) -> Result<CompiledProvider, ProviderCompileError> {
704        expect_arity(slots, 0)?;
705        Ok(CompiledProvider {
706            runner: ProviderRunner::Async(Rc::new(move |_, _| {
707                let future = factory();
708                Box::pin(async move { future.await.map(|value| Rc::new(value) as DependencyValue) })
709            })),
710            finalizer: None,
711        })
712    }
713}
714
715impl<Factory, Output> FallibleProviderFactory<(), Output> for Factory
716where
717    Factory: Fn() -> Result<Output, DependencyError> + 'static,
718    Output: 'static,
719{
720    fn dependency_keys() -> Vec<DependencyKey> {
721        Vec::new()
722    }
723
724    fn compile(
725        factory: Rc<Self>,
726        slots: &[DependencySlot],
727    ) -> Result<CompiledProvider, ProviderCompileError> {
728        expect_arity(slots, 0)?;
729        Ok(CompiledProvider {
730            runner: ProviderRunner::Sync(Rc::new(move |_, _| {
731                factory().map(|value| Rc::new(value) as DependencyValue)
732            })),
733            finalizer: None,
734        })
735    }
736}
737
738macro_rules! provider_factory {
739    ($(($argument:ident, $value:ident, $index:tt)),+ $(,)?) => {
740        impl<Factory, Output, $($argument),+> ProviderFactory<($($argument,)+), Output> for Factory
741        where
742            Factory: Fn($(Depends<$argument>),+) -> Output + 'static,
743            Output: 'static,
744            $($argument: 'static),+
745        {
746            fn dependency_keys() -> Vec<DependencyKey> {
747                vec![$(DependencyKey::of::<$argument>()),+]
748            }
749
750            fn compile(
751                factory: Rc<Self>,
752                slots: &[DependencySlot],
753            ) -> Result<CompiledProvider, ProviderCompileError> {
754                expect_arity(slots, provider_factory!(@count $($argument),+))?;
755                $(let $value = slots[$index];)+
756                Ok(CompiledProvider {
757                    runner: ProviderRunner::Sync(Rc::new(move |singletons, requests| {
758                        $(
759                            let $value =
760                                resolve::<$argument>($value, singletons, requests)?;
761                        )+
762                        Ok(Rc::new(factory($($value),+)) as DependencyValue)
763                    })),
764                    finalizer: None,
765                })
766            }
767        }
768
769        impl<Factory, Output, $($argument),+>
770            FallibleProviderFactory<($($argument,)+), Output> for Factory
771        where
772            Factory: Fn($(Depends<$argument>),+) -> Result<Output, DependencyError> + 'static,
773            Output: 'static,
774            $($argument: 'static),+
775        {
776            fn dependency_keys() -> Vec<DependencyKey> {
777                vec![$(DependencyKey::of::<$argument>()),+]
778            }
779
780            fn compile(
781                factory: Rc<Self>,
782                slots: &[DependencySlot],
783            ) -> Result<CompiledProvider, ProviderCompileError> {
784                expect_arity(slots, provider_factory!(@count $($argument),+))?;
785                $(let $value = slots[$index];)+
786                Ok(CompiledProvider {
787                    runner: ProviderRunner::Sync(Rc::new(move |singletons, requests| {
788                        $(
789                            let $value =
790                                resolve::<$argument>($value, singletons, requests)?;
791                        )+
792                        factory($($value),+)
793                            .map(|value| Rc::new(value) as DependencyValue)
794                    })),
795                    finalizer: None,
796                })
797            }
798        }
799
800        impl<Factory, Output, FactoryFuture, $($argument),+>
801            AsyncProviderFactory<($($argument,)+), Output, FactoryFuture> for Factory
802        where
803            Factory: Fn($(Depends<$argument>),+) -> FactoryFuture + 'static,
804            FactoryFuture: Future<Output = Output> + 'static,
805            Output: 'static,
806            $($argument: 'static),+
807        {
808            fn dependency_keys() -> Vec<DependencyKey> {
809                vec![$(DependencyKey::of::<$argument>()),+]
810            }
811
812            fn compile(
813                factory: Rc<Self>,
814                slots: &[DependencySlot],
815            ) -> Result<CompiledProvider, ProviderCompileError> {
816                expect_arity(slots, provider_factory!(@count $($argument),+))?;
817                $(let $value = slots[$index];)+
818                Ok(CompiledProvider {
819                    runner: ProviderRunner::Async(Rc::new(move |singletons, requests| {
820                        $(
821                            let $value = match
822                                resolve::<$argument>($value, singletons, requests)
823                            {
824                                Ok(value) => value,
825                                Err(error) => return failed_provider_future(error),
826                            };
827                        )+
828                        let future = factory($($value),+);
829                        Box::pin(async move {
830                            Ok(Rc::new(future.await) as DependencyValue)
831                        })
832                    })),
833                    finalizer: None,
834                })
835            }
836        }
837
838        impl<Factory, Output, FactoryFuture, $($argument),+>
839            FallibleAsyncProviderFactory<($($argument,)+), Output, FactoryFuture> for Factory
840        where
841            Factory: Fn($(Depends<$argument>),+) -> FactoryFuture + 'static,
842            FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
843            Output: 'static,
844            $($argument: 'static),+
845        {
846            fn dependency_keys() -> Vec<DependencyKey> {
847                vec![$(DependencyKey::of::<$argument>()),+]
848            }
849
850            fn compile(
851                factory: Rc<Self>,
852                slots: &[DependencySlot],
853            ) -> Result<CompiledProvider, ProviderCompileError> {
854                expect_arity(slots, provider_factory!(@count $($argument),+))?;
855                $(let $value = slots[$index];)+
856                Ok(CompiledProvider {
857                    runner: ProviderRunner::Async(Rc::new(move |singletons, requests| {
858                        $(
859                            let $value = match
860                                resolve::<$argument>($value, singletons, requests)
861                            {
862                                Ok(value) => value,
863                                Err(error) => return failed_provider_future(error),
864                            };
865                        )+
866                        let future = factory($($value),+);
867                        Box::pin(async move {
868                            future
869                                .await
870                                .map(|value| Rc::new(value) as DependencyValue)
871                        })
872                    })),
873                    finalizer: None,
874                })
875            }
876        }
877    };
878    (@count $($argument:ident),+) => {
879        <[()]>::len(&[$(provider_factory!(@unit $argument)),+])
880    };
881    (@unit $argument:ident) => { () };
882}
883
884provider_factory!((A, a, 0));
885provider_factory!((A, a, 0), (B, b, 1));
886provider_factory!((A, a, 0), (B, b, 1), (C, c, 2));
887provider_factory!((A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3));
888provider_factory!((A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4));
889provider_factory!(
890    (A, a, 0),
891    (B, b, 1),
892    (C, c, 2),
893    (D, d, 3),
894    (E, e, 4),
895    (F, f, 5)
896);
897provider_factory!(
898    (A, a, 0),
899    (B, b, 1),
900    (C, c, 2),
901    (D, d, 3),
902    (E, e, 4),
903    (F, f, 5),
904    (G, g, 6)
905);
906provider_factory!(
907    (A, a, 0),
908    (B, b, 1),
909    (C, c, 2),
910    (D, d, 3),
911    (E, e, 4),
912    (F, f, 5),
913    (G, g, 6),
914    (H, h, 7)
915);
916
917fn typed_finalizer<T, Finalizer>(finalizer: Finalizer) -> ProviderFinalizer
918where
919    Finalizer: Fn(Depends<T>) + 'static,
920    T: 'static,
921{
922    ProviderFinalizer::Sync(Rc::new(move |value| {
923        let dependency = Rc::clone(value).downcast::<T>().map_err(|_| {
924            DependencyError::internal(
925                "dependency_type_mismatch",
926                "compiled finalizer received an unexpected dependency type",
927            )
928        })?;
929        finalizer(Depends::from_rc(dependency));
930        Ok(())
931    }))
932}
933
934fn typed_async_finalizer<T, Finalizer, FinalizerOutput>(finalizer: Finalizer) -> ProviderFinalizer
935where
936    Finalizer: Fn(Depends<T>) -> FinalizerOutput + 'static,
937    FinalizerOutput: Future<Output = ()> + 'static,
938    T: 'static,
939{
940    ProviderFinalizer::Async(Rc::new(move |value| {
941        let Ok(dependency) = Rc::clone(value).downcast::<T>() else {
942            return Box::pin(async {
943                Err(DependencyError::internal(
944                    "dependency_type_mismatch",
945                    "compiled async finalizer received an unexpected dependency type",
946                ))
947            });
948        };
949        let future = finalizer(Depends::from_rc(dependency));
950        Box::pin(async move {
951            future.await;
952            Ok(())
953        })
954    }))
955}
956
957fn failed_provider_future(error: DependencyError) -> ProviderFuture {
958    Box::pin(async move { Err(error) })
959}
960
961fn expect_arity(slots: &[DependencySlot], expected: usize) -> Result<(), ProviderCompileError> {
962    if slots.len() == expected {
963        Ok(())
964    } else {
965        Err(ProviderCompileError::arity(expected, slots.len()))
966    }
967}
968
969fn resolve<T: 'static>(
970    slot: DependencySlot,
971    singletons: &[Option<DependencyValue>],
972    requests: &[Option<DependencyValue>],
973) -> Result<Depends<T>, DependencyError> {
974    let value = match slot {
975        DependencySlot::Singleton(index) => singletons.get(index),
976        DependencySlot::Request(index) => requests.get(index),
977    }
978    .and_then(Option::as_ref)
979    .ok_or_else(|| {
980        DependencyError::internal(
981            "invalid_dependency_slot",
982            "compiled dependency slot was not initialized",
983        )
984    })?;
985    Rc::clone(value)
986        .downcast::<T>()
987        .map(Depends::from_rc)
988        .map_err(|_| {
989            DependencyError::internal(
990                "dependency_type_mismatch",
991                "compiled dependency slot contained an unexpected type",
992            )
993        })
994}