1#![forbid(unsafe_code)]
2#![allow(clippy::needless_doctest_main)]
5#![doc = include_str!("../README.md")]
6
7use blazingly_contract::OperationFailure;
8use core::any::{Any, TypeId};
9use core::fmt;
10use core::future::Future;
11use core::ops::Deref;
12use core::pin::Pin;
13use std::rc::Rc;
14
15#[derive(Clone, Debug)]
17pub struct Depends<T> {
18 value: Rc<T>,
19}
20
21impl<T> Depends<T> {
22 #[doc(hidden)]
23 #[must_use]
24 pub const fn from_rc(value: Rc<T>) -> Self {
25 Self { value }
26 }
27
28 #[must_use]
29 pub fn into_inner(self) -> Rc<T> {
30 self.value
31 }
32}
33
34impl<T> Deref for Depends<T> {
35 type Target = T;
36
37 fn deref(&self) -> &Self::Target {
38 &self.value
39 }
40}
41
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
44pub enum DependencyLifetime {
45 Singleton,
47 Request,
49 Transient,
51}
52
53#[derive(Clone, Copy, Eq, Hash, PartialEq)]
55pub struct DependencyKey {
56 type_id: TypeId,
57 type_name: &'static str,
58}
59
60impl DependencyKey {
61 #[must_use]
62 pub fn of<T: 'static>() -> Self {
63 Self {
64 type_id: TypeId::of::<T>(),
65 type_name: core::any::type_name::<T>(),
66 }
67 }
68
69 #[must_use]
70 pub const fn type_id(self) -> TypeId {
71 self.type_id
72 }
73
74 #[must_use]
75 pub const fn type_name(self) -> &'static str {
76 self.type_name
77 }
78}
79
80impl fmt::Debug for DependencyKey {
81 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
82 formatter
83 .debug_tuple("DependencyKey")
84 .field(&self.type_name)
85 .finish()
86 }
87}
88
89#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
91pub struct DependencyRequest {
92 key: DependencyKey,
93}
94
95impl DependencyRequest {
96 #[must_use]
97 pub fn of<T: 'static>() -> Self {
98 Self {
99 key: DependencyKey::of::<T>(),
100 }
101 }
102
103 #[must_use]
104 pub const fn key(self) -> DependencyKey {
105 self.key
106 }
107}
108
109#[derive(Clone, Debug, PartialEq)]
111pub enum DependencyError {
112 Rejected(OperationFailure),
113 Internal { code: &'static str, message: String },
114}
115
116impl DependencyError {
117 #[must_use]
118 pub const fn rejected(failure: OperationFailure) -> Self {
119 Self::Rejected(failure)
120 }
121
122 #[must_use]
123 pub fn internal(code: &'static str, message: impl Into<String>) -> Self {
124 Self::Internal {
125 code,
126 message: message.into(),
127 }
128 }
129}
130
131impl fmt::Display for DependencyError {
132 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
133 match self {
134 Self::Rejected(failure) => write!(formatter, "{}", failure.message),
135 Self::Internal { message, .. } => formatter.write_str(message),
136 }
137 }
138}
139
140impl std::error::Error for DependencyError {}
141
142#[doc(hidden)]
143pub type DependencyValue = Rc<dyn Any>;
144
145#[doc(hidden)]
147#[derive(Clone, Copy, Debug, Eq, PartialEq)]
148pub enum DependencySlot {
149 Singleton(usize),
150 Request(usize),
151}
152
153#[doc(hidden)]
155#[derive(Clone)]
156pub struct CompiledProvider {
157 runner: ProviderRunner,
158 finalizer: Option<ProviderFinalizer>,
159}
160
161type SyncProviderRunner = Rc<
162 dyn Fn(
163 &[Option<DependencyValue>],
164 &[Option<DependencyValue>],
165 ) -> Result<DependencyValue, DependencyError>,
166>;
167type ProviderFuture =
168 Pin<Box<dyn Future<Output = Result<DependencyValue, DependencyError>> + 'static>>;
169type AsyncProviderRunner =
170 Rc<dyn Fn(&[Option<DependencyValue>], &[Option<DependencyValue>]) -> ProviderFuture>;
171
172#[derive(Clone)]
173enum ProviderRunner {
174 Sync(SyncProviderRunner),
175 Async(AsyncProviderRunner),
176}
177
178type SyncProviderFinalizer = Rc<dyn Fn(&DependencyValue) -> Result<(), DependencyError>>;
179type FinalizerFuture = Pin<Box<dyn Future<Output = Result<(), DependencyError>> + 'static>>;
180type AsyncProviderFinalizer = Rc<dyn Fn(&DependencyValue) -> FinalizerFuture>;
181
182#[derive(Clone)]
183enum ProviderFinalizer {
184 Sync(SyncProviderFinalizer),
185 Async(AsyncProviderFinalizer),
186}
187
188impl CompiledProvider {
189 #[doc(hidden)]
190 #[must_use]
191 pub fn run(
192 &self,
193 singletons: &[Option<DependencyValue>],
194 requests: &[Option<DependencyValue>],
195 ) -> ProviderFuture {
196 match &self.runner {
197 ProviderRunner::Sync(runner) => {
198 let result = runner(singletons, requests);
199 Box::pin(async move { result })
200 }
201 ProviderRunner::Async(runner) => runner(singletons, requests),
202 }
203 }
204
205 #[doc(hidden)]
206 pub fn run_sync(
207 &self,
208 singletons: &[Option<DependencyValue>],
209 requests: &[Option<DependencyValue>],
210 ) -> Result<DependencyValue, DependencyError> {
211 match &self.runner {
212 ProviderRunner::Sync(runner) => runner(singletons, requests),
213 ProviderRunner::Async(_) => Err(DependencyError::internal(
214 "async_singleton_provider",
215 "async providers cannot use the singleton lifetime",
216 )),
217 }
218 }
219
220 #[doc(hidden)]
221 pub fn finalize(&self, value: &DependencyValue) -> FinalizerFuture {
222 match &self.finalizer {
223 None => Box::pin(async { Ok(()) }),
224 Some(ProviderFinalizer::Sync(finalizer)) => {
225 let result = finalizer(value);
226 Box::pin(async move { result })
227 }
228 Some(ProviderFinalizer::Async(finalizer)) => finalizer(value),
229 }
230 }
231}
232
233#[doc(hidden)]
236#[derive(Clone, Copy, Debug, Eq, PartialEq)]
237pub struct ProviderCompileError {
238 expected: usize,
239 actual: usize,
240}
241
242impl ProviderCompileError {
243 const fn arity(expected: usize, actual: usize) -> Self {
244 Self { expected, actual }
245 }
246}
247
248impl fmt::Display for ProviderCompileError {
249 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
250 write!(
251 formatter,
252 "provider expected {} dependency slots but received {}",
253 self.expected, self.actual
254 )
255 }
256}
257
258impl std::error::Error for ProviderCompileError {}
259
260type ProviderCompiler =
261 Rc<dyn Fn(&[DependencySlot]) -> Result<CompiledProvider, ProviderCompileError>>;
262
263#[derive(Clone)]
265pub struct Provider {
266 key: DependencyKey,
267 lifetime: DependencyLifetime,
268 dependencies: Vec<DependencyKey>,
269 compiler: ProviderCompiler,
270 finalizer: Option<ProviderFinalizer>,
271}
272
273impl Provider {
274 #[must_use]
276 pub fn value<T: 'static>(value: T) -> Self {
277 let value: DependencyValue = Rc::new(value);
278 let compiler = Rc::new(move |slots: &[DependencySlot]| {
279 if !slots.is_empty() {
280 return Err(ProviderCompileError::arity(0, slots.len()));
281 }
282 let value = Rc::clone(&value);
283 Ok(CompiledProvider {
284 runner: ProviderRunner::Sync(Rc::new(move |_, _| Ok(Rc::clone(&value)))),
285 finalizer: None,
286 })
287 });
288 Self {
289 key: DependencyKey::of::<T>(),
290 lifetime: DependencyLifetime::Singleton,
291 dependencies: Vec::new(),
292 compiler,
293 finalizer: None,
294 }
295 }
296
297 #[must_use]
299 pub fn singleton<Arguments, Output, Factory>(factory: Factory) -> Self
300 where
301 Factory: ProviderFactory<Arguments, Output>,
302 Output: 'static,
303 {
304 Self::from_factory(DependencyLifetime::Singleton, factory)
305 }
306
307 #[must_use]
309 pub fn request<Arguments, Output, Factory>(factory: Factory) -> Self
310 where
311 Factory: ProviderFactory<Arguments, Output>,
312 Output: 'static,
313 {
314 Self::from_factory(DependencyLifetime::Request, factory)
315 }
316
317 #[must_use]
319 pub fn transient<Arguments, Output, Factory>(factory: Factory) -> Self
320 where
321 Factory: ProviderFactory<Arguments, Output>,
322 Output: 'static,
323 {
324 Self::from_factory(DependencyLifetime::Transient, factory)
325 }
326
327 #[must_use]
329 pub fn try_singleton<Arguments, Output, Factory>(factory: Factory) -> Self
330 where
331 Factory: FallibleProviderFactory<Arguments, Output>,
332 Output: 'static,
333 {
334 Self::from_fallible_factory(DependencyLifetime::Singleton, factory)
335 }
336
337 #[must_use]
339 pub fn try_request<Arguments, Output, Factory>(factory: Factory) -> Self
340 where
341 Factory: FallibleProviderFactory<Arguments, Output>,
342 Output: 'static,
343 {
344 Self::from_fallible_factory(DependencyLifetime::Request, factory)
345 }
346
347 #[must_use]
349 pub fn try_transient<Arguments, Output, Factory>(factory: Factory) -> Self
350 where
351 Factory: FallibleProviderFactory<Arguments, Output>,
352 Output: 'static,
353 {
354 Self::from_fallible_factory(DependencyLifetime::Transient, factory)
355 }
356
357 #[must_use]
359 pub fn request_scoped<Arguments, Output, Factory, Finalizer>(
360 factory: Factory,
361 finalizer: Finalizer,
362 ) -> Self
363 where
364 Factory: ProviderFactory<Arguments, Output>,
365 Finalizer: Fn(Depends<Output>) + 'static,
366 Output: 'static,
367 {
368 let mut provider = Self::from_factory(DependencyLifetime::Request, factory);
369 provider.finalizer = Some(typed_finalizer(finalizer));
370 provider
371 }
372
373 #[must_use]
375 pub fn try_request_scoped<Arguments, Output, Factory, Finalizer>(
376 factory: Factory,
377 finalizer: Finalizer,
378 ) -> Self
379 where
380 Factory: FallibleProviderFactory<Arguments, Output>,
381 Finalizer: Fn(Depends<Output>) + 'static,
382 Output: 'static,
383 {
384 let mut provider = Self::from_fallible_factory(DependencyLifetime::Request, factory);
385 provider.finalizer = Some(typed_finalizer(finalizer));
386 provider
387 }
388
389 #[must_use]
391 pub fn request_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
392 where
393 Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
394 FactoryFuture: Future<Output = Output> + 'static,
395 Output: 'static,
396 {
397 Self::from_async_factory(DependencyLifetime::Request, factory)
398 }
399
400 #[must_use]
402 pub fn transient_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
403 where
404 Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
405 FactoryFuture: Future<Output = Output> + 'static,
406 Output: 'static,
407 {
408 Self::from_async_factory(DependencyLifetime::Transient, factory)
409 }
410
411 #[must_use]
413 pub fn try_request_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
414 where
415 Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
416 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
417 Output: 'static,
418 {
419 Self::from_fallible_async_factory(DependencyLifetime::Request, factory)
420 }
421
422 #[must_use]
424 pub fn try_transient_async<Arguments, Output, Factory, FactoryFuture>(factory: Factory) -> Self
425 where
426 Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
427 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
428 Output: 'static,
429 {
430 Self::from_fallible_async_factory(DependencyLifetime::Transient, factory)
431 }
432
433 #[must_use]
435 pub fn request_async_scoped<
436 Arguments,
437 Output,
438 Factory,
439 FactoryFuture,
440 Finalizer,
441 FinalizerFuture,
442 >(
443 factory: Factory,
444 finalizer: Finalizer,
445 ) -> Self
446 where
447 Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
448 FactoryFuture: Future<Output = Output> + 'static,
449 Finalizer: Fn(Depends<Output>) -> FinalizerFuture + 'static,
450 FinalizerFuture: Future<Output = ()> + 'static,
451 Output: 'static,
452 {
453 let mut provider = Self::from_async_factory(DependencyLifetime::Request, factory);
454 provider.finalizer = Some(typed_async_finalizer(finalizer));
455 provider
456 }
457
458 #[must_use]
460 pub fn try_request_async_scoped<
461 Arguments,
462 Output,
463 Factory,
464 FactoryFuture,
465 Finalizer,
466 FinalizerFuture,
467 >(
468 factory: Factory,
469 finalizer: Finalizer,
470 ) -> Self
471 where
472 Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
473 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
474 Finalizer: Fn(Depends<Output>) -> FinalizerFuture + 'static,
475 FinalizerFuture: Future<Output = ()> + 'static,
476 Output: 'static,
477 {
478 let mut provider = Self::from_fallible_async_factory(DependencyLifetime::Request, factory);
479 provider.finalizer = Some(typed_async_finalizer(finalizer));
480 provider
481 }
482
483 fn from_factory<Arguments, Output, Factory>(
484 lifetime: DependencyLifetime,
485 factory: Factory,
486 ) -> Self
487 where
488 Factory: ProviderFactory<Arguments, Output>,
489 Output: 'static,
490 {
491 let dependencies = Factory::dependency_keys();
492 let factory = Rc::new(factory);
493 let compiler =
494 Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
495 Self {
496 key: DependencyKey::of::<Output>(),
497 lifetime,
498 dependencies,
499 compiler,
500 finalizer: None,
501 }
502 }
503
504 fn from_fallible_factory<Arguments, Output, Factory>(
505 lifetime: DependencyLifetime,
506 factory: Factory,
507 ) -> Self
508 where
509 Factory: FallibleProviderFactory<Arguments, Output>,
510 Output: 'static,
511 {
512 let dependencies = Factory::dependency_keys();
513 let factory = Rc::new(factory);
514 let compiler =
515 Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
516 Self {
517 key: DependencyKey::of::<Output>(),
518 lifetime,
519 dependencies,
520 compiler,
521 finalizer: None,
522 }
523 }
524
525 fn from_async_factory<Arguments, Output, Factory, FactoryFuture>(
526 lifetime: DependencyLifetime,
527 factory: Factory,
528 ) -> Self
529 where
530 Factory: AsyncProviderFactory<Arguments, Output, FactoryFuture>,
531 FactoryFuture: Future<Output = Output> + 'static,
532 Output: 'static,
533 {
534 let dependencies = Factory::dependency_keys();
535 let factory = Rc::new(factory);
536 let compiler =
537 Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
538 Self {
539 key: DependencyKey::of::<Output>(),
540 lifetime,
541 dependencies,
542 compiler,
543 finalizer: None,
544 }
545 }
546
547 fn from_fallible_async_factory<Arguments, Output, Factory, FactoryFuture>(
548 lifetime: DependencyLifetime,
549 factory: Factory,
550 ) -> Self
551 where
552 Factory: FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>,
553 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
554 Output: 'static,
555 {
556 let dependencies = Factory::dependency_keys();
557 let factory = Rc::new(factory);
558 let compiler =
559 Rc::new(move |slots: &[DependencySlot]| Factory::compile(Rc::clone(&factory), slots));
560 Self {
561 key: DependencyKey::of::<Output>(),
562 lifetime,
563 dependencies,
564 compiler,
565 finalizer: None,
566 }
567 }
568
569 #[must_use]
570 pub const fn key(&self) -> DependencyKey {
571 self.key
572 }
573
574 #[must_use]
575 pub const fn lifetime(&self) -> DependencyLifetime {
576 self.lifetime
577 }
578
579 #[must_use]
580 pub fn dependencies(&self) -> &[DependencyKey] {
581 &self.dependencies
582 }
583
584 #[doc(hidden)]
585 pub fn compile(
586 &self,
587 slots: &[DependencySlot],
588 ) -> Result<CompiledProvider, ProviderCompileError> {
589 let mut compiled = (self.compiler)(slots)?;
590 compiled.finalizer.clone_from(&self.finalizer);
591 Ok(compiled)
592 }
593}
594
595#[doc(hidden)]
597pub trait ProviderFactory<Arguments, Output>: 'static {
598 fn dependency_keys() -> Vec<DependencyKey>;
599
600 fn compile(
601 factory: Rc<Self>,
602 slots: &[DependencySlot],
603 ) -> Result<CompiledProvider, ProviderCompileError>;
604}
605
606#[doc(hidden)]
608pub trait FallibleProviderFactory<Arguments, Output>: 'static {
609 fn dependency_keys() -> Vec<DependencyKey>;
610
611 fn compile(
612 factory: Rc<Self>,
613 slots: &[DependencySlot],
614 ) -> Result<CompiledProvider, ProviderCompileError>;
615}
616
617#[doc(hidden)]
619pub trait AsyncProviderFactory<Arguments, Output, FactoryFuture>: 'static
620where
621 FactoryFuture: Future<Output = Output> + 'static,
622{
623 fn dependency_keys() -> Vec<DependencyKey>;
624
625 fn compile(
626 factory: Rc<Self>,
627 slots: &[DependencySlot],
628 ) -> Result<CompiledProvider, ProviderCompileError>;
629}
630
631#[doc(hidden)]
633pub trait FallibleAsyncProviderFactory<Arguments, Output, FactoryFuture>: 'static
634where
635 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
636{
637 fn dependency_keys() -> Vec<DependencyKey>;
638
639 fn compile(
640 factory: Rc<Self>,
641 slots: &[DependencySlot],
642 ) -> Result<CompiledProvider, ProviderCompileError>;
643}
644
645impl<Factory, Output> ProviderFactory<(), Output> for Factory
646where
647 Factory: Fn() -> Output + 'static,
648 Output: 'static,
649{
650 fn dependency_keys() -> Vec<DependencyKey> {
651 Vec::new()
652 }
653
654 fn compile(
655 factory: Rc<Self>,
656 slots: &[DependencySlot],
657 ) -> Result<CompiledProvider, ProviderCompileError> {
658 expect_arity(slots, 0)?;
659 Ok(CompiledProvider {
660 runner: ProviderRunner::Sync(Rc::new(move |_, _| {
661 Ok(Rc::new(factory()) as DependencyValue)
662 })),
663 finalizer: None,
664 })
665 }
666}
667
668impl<Factory, Output, FactoryFuture> AsyncProviderFactory<(), Output, FactoryFuture> for Factory
669where
670 Factory: Fn() -> FactoryFuture + 'static,
671 FactoryFuture: Future<Output = Output> + 'static,
672 Output: 'static,
673{
674 fn dependency_keys() -> Vec<DependencyKey> {
675 Vec::new()
676 }
677
678 fn compile(
679 factory: Rc<Self>,
680 slots: &[DependencySlot],
681 ) -> Result<CompiledProvider, ProviderCompileError> {
682 expect_arity(slots, 0)?;
683 Ok(CompiledProvider {
684 runner: ProviderRunner::Async(Rc::new(move |_, _| {
685 let future = factory();
686 Box::pin(async move { Ok(Rc::new(future.await) as DependencyValue) })
687 })),
688 finalizer: None,
689 })
690 }
691}
692
693impl<Factory, Output, FactoryFuture> FallibleAsyncProviderFactory<(), Output, FactoryFuture>
694 for Factory
695where
696 Factory: Fn() -> FactoryFuture + 'static,
697 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
698 Output: 'static,
699{
700 fn dependency_keys() -> Vec<DependencyKey> {
701 Vec::new()
702 }
703
704 fn compile(
705 factory: Rc<Self>,
706 slots: &[DependencySlot],
707 ) -> Result<CompiledProvider, ProviderCompileError> {
708 expect_arity(slots, 0)?;
709 Ok(CompiledProvider {
710 runner: ProviderRunner::Async(Rc::new(move |_, _| {
711 let future = factory();
712 Box::pin(async move { future.await.map(|value| Rc::new(value) as DependencyValue) })
713 })),
714 finalizer: None,
715 })
716 }
717}
718
719impl<Factory, Output> FallibleProviderFactory<(), Output> for Factory
720where
721 Factory: Fn() -> Result<Output, DependencyError> + 'static,
722 Output: 'static,
723{
724 fn dependency_keys() -> Vec<DependencyKey> {
725 Vec::new()
726 }
727
728 fn compile(
729 factory: Rc<Self>,
730 slots: &[DependencySlot],
731 ) -> Result<CompiledProvider, ProviderCompileError> {
732 expect_arity(slots, 0)?;
733 Ok(CompiledProvider {
734 runner: ProviderRunner::Sync(Rc::new(move |_, _| {
735 factory().map(|value| Rc::new(value) as DependencyValue)
736 })),
737 finalizer: None,
738 })
739 }
740}
741
742macro_rules! provider_factory {
743 ($(($argument:ident, $value:ident, $index:tt)),+ $(,)?) => {
744 impl<Factory, Output, $($argument),+> ProviderFactory<($($argument,)+), Output> for Factory
745 where
746 Factory: Fn($(Depends<$argument>),+) -> Output + 'static,
747 Output: 'static,
748 $($argument: 'static),+
749 {
750 fn dependency_keys() -> Vec<DependencyKey> {
751 vec![$(DependencyKey::of::<$argument>()),+]
752 }
753
754 fn compile(
755 factory: Rc<Self>,
756 slots: &[DependencySlot],
757 ) -> Result<CompiledProvider, ProviderCompileError> {
758 expect_arity(slots, provider_factory!(@count $($argument),+))?;
759 $(let $value = slots[$index];)+
760 Ok(CompiledProvider {
761 runner: ProviderRunner::Sync(Rc::new(move |singletons, requests| {
762 $(
763 let $value =
764 resolve::<$argument>($value, singletons, requests)?;
765 )+
766 Ok(Rc::new(factory($($value),+)) as DependencyValue)
767 })),
768 finalizer: None,
769 })
770 }
771 }
772
773 impl<Factory, Output, $($argument),+>
774 FallibleProviderFactory<($($argument,)+), Output> for Factory
775 where
776 Factory: Fn($(Depends<$argument>),+) -> Result<Output, DependencyError> + 'static,
777 Output: 'static,
778 $($argument: 'static),+
779 {
780 fn dependency_keys() -> Vec<DependencyKey> {
781 vec![$(DependencyKey::of::<$argument>()),+]
782 }
783
784 fn compile(
785 factory: Rc<Self>,
786 slots: &[DependencySlot],
787 ) -> Result<CompiledProvider, ProviderCompileError> {
788 expect_arity(slots, provider_factory!(@count $($argument),+))?;
789 $(let $value = slots[$index];)+
790 Ok(CompiledProvider {
791 runner: ProviderRunner::Sync(Rc::new(move |singletons, requests| {
792 $(
793 let $value =
794 resolve::<$argument>($value, singletons, requests)?;
795 )+
796 factory($($value),+)
797 .map(|value| Rc::new(value) as DependencyValue)
798 })),
799 finalizer: None,
800 })
801 }
802 }
803
804 impl<Factory, Output, FactoryFuture, $($argument),+>
805 AsyncProviderFactory<($($argument,)+), Output, FactoryFuture> for Factory
806 where
807 Factory: Fn($(Depends<$argument>),+) -> FactoryFuture + 'static,
808 FactoryFuture: Future<Output = Output> + 'static,
809 Output: 'static,
810 $($argument: 'static),+
811 {
812 fn dependency_keys() -> Vec<DependencyKey> {
813 vec![$(DependencyKey::of::<$argument>()),+]
814 }
815
816 fn compile(
817 factory: Rc<Self>,
818 slots: &[DependencySlot],
819 ) -> Result<CompiledProvider, ProviderCompileError> {
820 expect_arity(slots, provider_factory!(@count $($argument),+))?;
821 $(let $value = slots[$index];)+
822 Ok(CompiledProvider {
823 runner: ProviderRunner::Async(Rc::new(move |singletons, requests| {
824 $(
825 let $value = match
826 resolve::<$argument>($value, singletons, requests)
827 {
828 Ok(value) => value,
829 Err(error) => return failed_provider_future(error),
830 };
831 )+
832 let future = factory($($value),+);
833 Box::pin(async move {
834 Ok(Rc::new(future.await) as DependencyValue)
835 })
836 })),
837 finalizer: None,
838 })
839 }
840 }
841
842 impl<Factory, Output, FactoryFuture, $($argument),+>
843 FallibleAsyncProviderFactory<($($argument,)+), Output, FactoryFuture> for Factory
844 where
845 Factory: Fn($(Depends<$argument>),+) -> FactoryFuture + 'static,
846 FactoryFuture: Future<Output = Result<Output, DependencyError>> + 'static,
847 Output: 'static,
848 $($argument: 'static),+
849 {
850 fn dependency_keys() -> Vec<DependencyKey> {
851 vec![$(DependencyKey::of::<$argument>()),+]
852 }
853
854 fn compile(
855 factory: Rc<Self>,
856 slots: &[DependencySlot],
857 ) -> Result<CompiledProvider, ProviderCompileError> {
858 expect_arity(slots, provider_factory!(@count $($argument),+))?;
859 $(let $value = slots[$index];)+
860 Ok(CompiledProvider {
861 runner: ProviderRunner::Async(Rc::new(move |singletons, requests| {
862 $(
863 let $value = match
864 resolve::<$argument>($value, singletons, requests)
865 {
866 Ok(value) => value,
867 Err(error) => return failed_provider_future(error),
868 };
869 )+
870 let future = factory($($value),+);
871 Box::pin(async move {
872 future
873 .await
874 .map(|value| Rc::new(value) as DependencyValue)
875 })
876 })),
877 finalizer: None,
878 })
879 }
880 }
881 };
882 (@count $($argument:ident),+) => {
883 <[()]>::len(&[$(provider_factory!(@unit $argument)),+])
884 };
885 (@unit $argument:ident) => { () };
886}
887
888provider_factory!((A, a, 0));
889provider_factory!((A, a, 0), (B, b, 1));
890provider_factory!((A, a, 0), (B, b, 1), (C, c, 2));
891provider_factory!((A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3));
892provider_factory!((A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4));
893provider_factory!(
894 (A, a, 0),
895 (B, b, 1),
896 (C, c, 2),
897 (D, d, 3),
898 (E, e, 4),
899 (F, f, 5)
900);
901provider_factory!(
902 (A, a, 0),
903 (B, b, 1),
904 (C, c, 2),
905 (D, d, 3),
906 (E, e, 4),
907 (F, f, 5),
908 (G, g, 6)
909);
910provider_factory!(
911 (A, a, 0),
912 (B, b, 1),
913 (C, c, 2),
914 (D, d, 3),
915 (E, e, 4),
916 (F, f, 5),
917 (G, g, 6),
918 (H, h, 7)
919);
920
921fn typed_finalizer<T, Finalizer>(finalizer: Finalizer) -> ProviderFinalizer
922where
923 Finalizer: Fn(Depends<T>) + 'static,
924 T: 'static,
925{
926 ProviderFinalizer::Sync(Rc::new(move |value| {
927 let dependency = Rc::clone(value).downcast::<T>().map_err(|_| {
928 DependencyError::internal(
929 "dependency_type_mismatch",
930 "compiled finalizer received an unexpected dependency type",
931 )
932 })?;
933 finalizer(Depends::from_rc(dependency));
934 Ok(())
935 }))
936}
937
938fn typed_async_finalizer<T, Finalizer, FinalizerOutput>(finalizer: Finalizer) -> ProviderFinalizer
939where
940 Finalizer: Fn(Depends<T>) -> FinalizerOutput + 'static,
941 FinalizerOutput: Future<Output = ()> + 'static,
942 T: 'static,
943{
944 ProviderFinalizer::Async(Rc::new(move |value| {
945 let Ok(dependency) = Rc::clone(value).downcast::<T>() else {
946 return Box::pin(async {
947 Err(DependencyError::internal(
948 "dependency_type_mismatch",
949 "compiled async finalizer received an unexpected dependency type",
950 ))
951 });
952 };
953 let future = finalizer(Depends::from_rc(dependency));
954 Box::pin(async move {
955 future.await;
956 Ok(())
957 })
958 }))
959}
960
961fn failed_provider_future(error: DependencyError) -> ProviderFuture {
962 Box::pin(async move { Err(error) })
963}
964
965fn expect_arity(slots: &[DependencySlot], expected: usize) -> Result<(), ProviderCompileError> {
966 if slots.len() == expected {
967 Ok(())
968 } else {
969 Err(ProviderCompileError::arity(expected, slots.len()))
970 }
971}
972
973#[doc(hidden)]
981pub struct SlotReader<'values> {
982 singletons: &'values [Option<DependencyValue>],
983 requests: &'values [Option<DependencyValue>],
984 slots: &'values [DependencySlot],
985 depends_count: usize,
986}
987
988impl SlotReader<'_> {
989 pub fn depends<T: 'static>(&self, position: usize) -> Result<Depends<T>, DependencyError> {
996 let slot = self.slots.get(position).copied().ok_or_else(|| {
997 DependencyError::internal(
998 "invalid_dependency_slot",
999 "compiled provider requested an undeclared dependency position",
1000 )
1001 })?;
1002 resolve(slot, self.singletons, self.requests)
1003 }
1004
1005 pub fn input<T: 'static>(&self, position: usize) -> Result<Rc<T>, DependencyError> {
1013 let slot = self
1014 .slots
1015 .get(self.depends_count + position)
1016 .copied()
1017 .ok_or_else(|| {
1018 DependencyError::internal(
1019 "invalid_dependency_slot",
1020 "compiled provider requested an undeclared input position",
1021 )
1022 })?;
1023 let value = match slot {
1024 DependencySlot::Singleton(index) => self.singletons.get(index),
1025 DependencySlot::Request(index) => self.requests.get(index),
1026 }
1027 .and_then(Option::as_ref)
1028 .ok_or_else(|| {
1029 DependencyError::internal(
1030 "invalid_dependency_slot",
1031 "compiled request input slot was not initialized",
1032 )
1033 })?;
1034 Rc::clone(value).downcast::<T>().map_err(|_| {
1035 DependencyError::internal(
1036 "dependency_type_mismatch",
1037 "compiled request input slot contained an unexpected type",
1038 )
1039 })
1040 }
1041}
1042
1043#[doc(hidden)]
1045pub type SlotFactory<T> = Rc<dyn Fn(&SlotReader<'_>) -> Result<T, DependencyError>>;
1046
1047#[doc(hidden)]
1052pub type AsyncSlotFactory<T> = Rc<
1053 dyn Fn(&SlotReader<'_>) -> Pin<Box<dyn Future<Output = Result<T, DependencyError>> + 'static>>,
1054>;
1055
1056impl Provider {
1057 fn from_slots_inner<T: 'static>(
1058 lifetime: DependencyLifetime,
1059 dependencies: Vec<DependencyKey>,
1060 input_count: usize,
1061 runner_of: impl Fn(Rc<Vec<DependencySlot>>, usize) -> ProviderRunner + 'static,
1062 ) -> Self {
1063 let depends_count = dependencies.len();
1064 let expected = depends_count + input_count;
1065 let compiler = Rc::new(move |slots: &[DependencySlot]| {
1066 expect_arity(slots, expected)?;
1067 let slots = Rc::new(slots.to_vec());
1068 Ok(CompiledProvider {
1069 runner: runner_of(slots, depends_count),
1070 finalizer: None,
1071 })
1072 });
1073 Self {
1074 key: DependencyKey::of::<T>(),
1075 lifetime,
1076 dependencies,
1077 compiler,
1078 finalizer: None,
1079 }
1080 }
1081
1082 #[doc(hidden)]
1085 #[must_use]
1086 pub fn request_from_slots<T: 'static>(
1087 dependencies: Vec<DependencyKey>,
1088 input_count: usize,
1089 factory: SlotFactory<T>,
1090 ) -> Self {
1091 Self::slot_provider::<T>(
1092 DependencyLifetime::Request,
1093 dependencies,
1094 input_count,
1095 factory,
1096 )
1097 }
1098
1099 #[doc(hidden)]
1101 #[must_use]
1102 pub fn transient_from_slots<T: 'static>(
1103 dependencies: Vec<DependencyKey>,
1104 input_count: usize,
1105 factory: SlotFactory<T>,
1106 ) -> Self {
1107 Self::slot_provider::<T>(
1108 DependencyLifetime::Transient,
1109 dependencies,
1110 input_count,
1111 factory,
1112 )
1113 }
1114
1115 #[doc(hidden)]
1117 #[must_use]
1118 pub fn request_from_slots_async<T: 'static>(
1119 dependencies: Vec<DependencyKey>,
1120 input_count: usize,
1121 factory: AsyncSlotFactory<T>,
1122 ) -> Self {
1123 Self::async_slot_provider::<T>(
1124 DependencyLifetime::Request,
1125 dependencies,
1126 input_count,
1127 factory,
1128 )
1129 }
1130
1131 #[doc(hidden)]
1133 #[must_use]
1134 pub fn transient_from_slots_async<T: 'static>(
1135 dependencies: Vec<DependencyKey>,
1136 input_count: usize,
1137 factory: AsyncSlotFactory<T>,
1138 ) -> Self {
1139 Self::async_slot_provider::<T>(
1140 DependencyLifetime::Transient,
1141 dependencies,
1142 input_count,
1143 factory,
1144 )
1145 }
1146
1147 fn slot_provider<T: 'static>(
1148 lifetime: DependencyLifetime,
1149 dependencies: Vec<DependencyKey>,
1150 input_count: usize,
1151 factory: SlotFactory<T>,
1152 ) -> Self {
1153 Self::from_slots_inner::<T>(
1154 lifetime,
1155 dependencies,
1156 input_count,
1157 move |slots, depends| {
1158 let factory = Rc::clone(&factory);
1159 ProviderRunner::Sync(Rc::new(move |singletons, requests| {
1160 let reader = SlotReader {
1161 singletons,
1162 requests,
1163 slots: &slots,
1164 depends_count: depends,
1165 };
1166 factory(&reader).map(|value| Rc::new(value) as DependencyValue)
1167 }))
1168 },
1169 )
1170 }
1171
1172 fn async_slot_provider<T: 'static>(
1173 lifetime: DependencyLifetime,
1174 dependencies: Vec<DependencyKey>,
1175 input_count: usize,
1176 factory: AsyncSlotFactory<T>,
1177 ) -> Self {
1178 Self::from_slots_inner::<T>(
1179 lifetime,
1180 dependencies,
1181 input_count,
1182 move |slots, depends| {
1183 let factory = Rc::clone(&factory);
1184 ProviderRunner::Async(Rc::new(move |singletons, requests| {
1185 let reader = SlotReader {
1186 singletons,
1187 requests,
1188 slots: &slots,
1189 depends_count: depends,
1190 };
1191 let future = factory(&reader);
1192 Box::pin(
1193 async move { future.await.map(|value| Rc::new(value) as DependencyValue) },
1194 )
1195 }))
1196 },
1197 )
1198 }
1199}
1200
1201fn resolve<T: 'static>(
1202 slot: DependencySlot,
1203 singletons: &[Option<DependencyValue>],
1204 requests: &[Option<DependencyValue>],
1205) -> Result<Depends<T>, DependencyError> {
1206 let value = match slot {
1207 DependencySlot::Singleton(index) => singletons.get(index),
1208 DependencySlot::Request(index) => requests.get(index),
1209 }
1210 .and_then(Option::as_ref)
1211 .ok_or_else(|| {
1212 DependencyError::internal(
1213 "invalid_dependency_slot",
1214 "compiled dependency slot was not initialized",
1215 )
1216 })?;
1217 Rc::clone(value)
1218 .downcast::<T>()
1219 .map(Depends::from_rc)
1220 .map_err(|_| {
1221 DependencyError::internal(
1222 "dependency_type_mismatch",
1223 "compiled dependency slot contained an unexpected type",
1224 )
1225 })
1226}