ferrunix_core/
dependency_builder.rs

1//! Implementation of [`DepBuilder`] for tuples to be used with
2//! [`Registry::with_deps`].
3#![allow(clippy::missing_errors_doc, clippy::manual_async_fn)]
4
5use std::any::TypeId;
6
7use crate::error::ResolveError;
8use crate::types::Registerable;
9use crate::Registry;
10
11/// Required for sealing the trait. *Must not be public*.
12pub(crate) mod private {
13    /// This token is used to seal the [`DepBuilder`] trait from downstream
14    /// crates.
15    #[allow(missing_debug_implementations)]
16    #[derive(Clone, Copy)]
17    pub struct SealToken;
18}
19
20/// The [`DepBuilder`] trait is the key to specify a variable amount of
21/// dependencies in the [`Registry::with_deps`] call from [`Registry`].
22///
23/// The trait is implemented by the `DepBuilderImpl!` macro for 0-ary, to 10-ary
24/// tuples (e.g., `(T1,)`, `(T1, T2)`, etc.), which allows these tuples to be
25/// passed as a single type parameter into [`Registry::with_deps`].
26///
27/// This trait is sealed, meaning it cannot be implemented or called by any
28/// downstream crates.
29pub trait DepBuilder<R> {
30    /// When implemented, this should validate that all dependencies which are
31    /// part of `Self` exist to construct the type `R`. If the dependencies
32    /// cannot be fulfilled, `None` must be returned.
33    ///
34    /// If the dependencies can be fulfilled, they must be constructed as an
35    /// N-ary tuple (same length and types as `Self`) and passed as the
36    /// argument to `ctor`. `ctor` is a user provided constructor for the
37    /// type `R`.
38    ///
39    /// An implementation for tuples is provided by `DepBuilderImpl!`.
40    ///
41    /// It's advised to avoid *manually* implementing `build`.
42    #[cfg(not(feature = "tokio"))]
43    fn build(
44        registry: &Registry,
45        ctor: &dyn crate::types::TransientCtorFallibleDeps<R, Self>,
46        _: private::SealToken,
47    ) -> Result<R, ResolveError>
48    where
49        R: Sized;
50
51    /// Similar to [`DepBuilder::build`], except that it takes a boxed `dyn FnOnce` closure.
52    /// This constructor is used for singletons.
53    ///
54    /// Similarly to `build`, this is also implemented by `DepBuilderImpl!`.
55    ///
56    /// It's advised to avoid *manually* implementing `build`.
57    #[cfg(not(feature = "tokio"))]
58    fn build_once(
59        registry: &Registry,
60        ctor: Box<dyn crate::types::SingletonCtorFallibleDeps<R, Self>>,
61        _: private::SealToken,
62    ) -> Result<R, ResolveError>
63    where
64        R: Sized,
65        Self: Sized;
66
67    /// When implemented, this should validate that all dependencies which are
68    /// part of `Self` exist to construct the type `R`. If the dependencies
69    /// cannot be fulfilled, `None` must be returned.
70    ///
71    /// If the dependencies can be fulfilled, they must be constructed as an
72    /// N-ary tuple (same length and types as `Self`) and passed as the
73    /// argument to `ctor`. `ctor` is a user provided constructor for the
74    /// type `R`.
75    ///
76    /// An implementation for tuples is provided by `DepBuilderImpl!`.
77    ///
78    /// It's advised to avoid *manually* implementing `build`.
79    #[cfg(feature = "tokio")]
80    fn build(
81        registry: &Registry,
82        ctor: &(dyn crate::types::TransientCtorFallibleDeps<R, Self> + Send),
83        _: private::SealToken,
84    ) -> impl std::future::Future<Output = Result<R, ResolveError>> + Send + Sync
85    where
86        R: Sized;
87
88    /// Similar to [`DepBuilder::build`], except that it takes a boxed `dyn FnOnce` closure.
89    /// This constructor is used for singletons.
90    ///
91    /// Similarly to `build`, this is also implemented by `DepBuilderImpl!`.
92    ///
93    /// It's advised to avoid *manually* implementing `build`.
94    #[cfg(feature = "tokio")]
95    fn build_once(
96        registry: &Registry,
97        ctor: Box<dyn crate::types::SingletonCtorFallibleDeps<R, Self> + Send>,
98        _: private::SealToken,
99    ) -> impl std::future::Future<Output = Result<R, ResolveError>> + Send + Sync
100    where
101        R: Sized,
102        Self: Sized;
103
104    /// Constructs a [`Vec`] of [`std::any::TypeId`]s from the types in `Self`.
105    /// The resulting vector must have the same length as `Self`.
106    ///
107    /// An implementation for tuples is provided by `DepBuilderImpl!`.
108    ///
109    /// We advise against *manually* implementing `as_typeids`.
110    fn as_typeids(_: private::SealToken) -> Vec<(TypeId, &'static str)>;
111}
112
113impl<R> DepBuilder<R> for ()
114where
115    R: Registerable,
116{
117    #[cfg(not(feature = "tokio"))]
118    fn build(
119        _registry: &Registry,
120        ctor: &dyn crate::types::TransientCtorFallibleDeps<R, Self>,
121        _: private::SealToken,
122    ) -> Result<R, ResolveError> {
123        (ctor)(()).map_err(ResolveError::Ctor)
124    }
125
126    #[cfg(not(feature = "tokio"))]
127    fn build_once(
128        _registry: &Registry,
129        ctor: Box<dyn crate::types::SingletonCtorFallibleDeps<R, Self>>,
130        _: private::SealToken,
131    ) -> Result<R, ResolveError>
132    where
133        R: Sized,
134        Self: Sized,
135    {
136        ctor(()).map_err(ResolveError::Ctor)
137    }
138
139    #[cfg(feature = "tokio")]
140    fn build(
141        _registry: &Registry,
142        ctor: &(dyn crate::types::TransientCtorFallibleDeps<R, Self> + Send),
143        _: private::SealToken,
144    ) -> impl std::future::Future<Output = Result<R, ResolveError>> + Send + Sync
145    {
146        async move {
147            (ctor)(()).await.map_err(ResolveError::Ctor)
148        }
149    }
150
151    #[cfg(feature = "tokio")]
152    fn build_once(
153        _registry: &Registry,
154        ctor: Box<dyn crate::types::SingletonCtorFallibleDeps<R, Self> + Send>,
155        _: private::SealToken,
156    ) -> impl std::future::Future<Output = Result<R, ResolveError>> + Send + Sync
157    where
158        R: Sized,
159        Self: Sized,
160    {
161        async move {
162            (ctor)(()).await.map_err(ResolveError::Ctor)
163        }
164    }
165
166    fn as_typeids(_: private::SealToken) -> Vec<(TypeId, &'static str)> {
167        Vec::new()
168    }
169}
170
171/// Generates the implementation for [`DepBuilder`].
172macro_rules! DepBuilderImpl {
173    ($n:expr, { $($ts:ident),+ }) => {
174        impl<R, $($ts,)*> $crate::dependency_builder::DepBuilder<R> for ($($ts,)*)
175        where
176            R: $crate::types::Registerable,
177            $($ts: $crate::dependencies::Dep,)*
178        {
179            #[cfg(not(feature = "tokio"))]
180            fn build(
181                registry: &$crate::registry::Registry,
182                ctor: &dyn crate::types::TransientCtorFallibleDeps<R, Self>,
183                _: private::SealToken,
184            ) -> Result<R, ResolveError>
185            {
186                registry.validate::<R>()?;
187
188                let deps = (
189                    $(
190                        <$ts>::new(registry),
191                    )*
192                );
193
194                (ctor)(deps).map_err(ResolveError::Ctor)
195            }
196
197            #[cfg(not(feature = "tokio"))]
198            fn build_once(
199                registry: &$crate::registry::Registry,
200                ctor: Box<dyn crate::types::SingletonCtorFallibleDeps<R, Self>>,
201                _: private::SealToken,
202                ) -> Result<R, ResolveError>
203                where
204                    R: Sized,
205                    Self: Sized
206            {
207                registry.validate::<R>()?;
208
209                let deps = (
210                    $(
211                        <$ts>::new(registry),
212                    )*
213                );
214
215                ctor(deps).map_err(ResolveError::Ctor)
216            }
217
218            #[cfg(feature = "tokio")]
219            fn build(
220                registry: &Registry,
221                ctor: &(dyn crate::types::TransientCtorFallibleDeps<R, Self> + Send),
222                _: private::SealToken,
223            ) -> impl std::future::Future<Output = Result<R, ResolveError>> + Send + Sync
224            {
225                async move {
226                    registry.validate::<R>()?;
227
228                    let deps = (
229                        $(
230                            <$ts>::new(registry).await,
231                        )*
232                    );
233
234                    (ctor)(deps).await.map_err(ResolveError::Ctor)
235                }
236            }
237
238            #[cfg(feature = "tokio")]
239            fn build_once(
240                registry: &Registry,
241                ctor: Box<dyn crate::types::SingletonCtorFallibleDeps<R, Self> + Send>,
242                _: private::SealToken,
243            ) -> impl std::future::Future<Output = Result<R, ResolveError>> + Send + Sync
244            {
245                async move {
246                    registry.validate::<R>()?;
247
248                    let deps = (
249                        $(
250                            <$ts>::new(registry).await,
251                        )*
252                    );
253
254                    (ctor)(deps).await.map_err(ResolveError::Ctor)
255                }
256            }
257
258            fn as_typeids(_: private::SealToken) -> ::std::vec::Vec<(::std::any::TypeId, &'static str)> {
259                ::std::vec![ $((<$ts>::type_id(), ::std::any::type_name::<$ts>()),)* ]
260            }
261        }
262    };
263}
264
265DepBuilderImpl!(1, { T1 });
266DepBuilderImpl!(2, { T1, T2 });
267DepBuilderImpl!(3, { T1, T2, T3 });
268DepBuilderImpl!(4, { T1, T2, T3, T4 });
269DepBuilderImpl!(5, { T1, T2, T3, T4, T5 });
270DepBuilderImpl!(6, { T1, T2, T3, T4, T5, T6 });
271DepBuilderImpl!(7, { T1, T2, T3, T4, T5, T6, T8 });
272DepBuilderImpl!(8, { T1, T2, T3, T4, T5, T6, T8, T9 });