Skip to main content

di/
builder.rs

1use crate::{
2    Ref, ServiceCardinality::*, ServiceDependency, ServiceDescriptor, ServiceDescriptorBuilder, ServiceLifetime::*,
3    ServiceProvider, Type,
4};
5use std::any::Any;
6use std::mem::MaybeUninit;
7use std::sync::OnceLock;
8
9type Sdb<TSvc, TImpl> = ServiceDescriptorBuilder<TSvc, TImpl>;
10
11macro_rules! service_from_type {
12    ($($traits:tt)+) => {
13        #[inline(always)]
14        fn no_op(_: &ServiceProvider) -> Ref<dyn $($traits)+> {
15            Ref::new(MaybeUninit::<Box<dyn $($traits)+>>::uninit())
16        }
17
18        /// Initializes a new singleton [ServiceDescriptorBuilder].
19        #[inline]
20        pub fn singleton<TSvc: ?Sized + $($traits)+, TImpl>() -> ServiceDescriptorBuilder<TSvc, TImpl> {
21            Sdb::new(Singleton, Type::of::<TImpl>())
22        }
23
24        /// Initializes a new keyed singleton [ServiceDescriptorBuilder].
25        #[inline]
26        pub fn singleton_with_key<TKey, TSvc: ?Sized + $($traits)+, TImpl>() -> ServiceDescriptorBuilder<TSvc, TImpl> {
27            Sdb::keyed::<TKey>(Singleton, Type::of::<TImpl>())
28        }
29
30        /// Initializes a new singleton [ServiceDescriptorBuilder].
31        ///
32        /// # Remarks
33        ///
34        /// This function maps a concrete type to itself rather than a trait.
35        #[inline]
36        pub fn singleton_as_self<T: $($traits)+>() -> ServiceDescriptorBuilder<T, T> {
37            Sdb::new(Singleton, Type::of::<T>())
38        }
39
40        /// Initializes a new scoped [ServiceDescriptorBuilder].
41        #[inline]
42        pub fn scoped<TSvc: ?Sized + $($traits)+, TImpl>() -> ServiceDescriptorBuilder<TSvc, TImpl> {
43            Sdb::new(Scoped, Type::of::<TImpl>())
44        }
45
46        /// Initializes a new scoped keyed [ServiceDescriptorBuilder].
47        #[inline]
48        pub fn scoped_with_key<TKey, TSvc: ?Sized + $($traits)+, TImpl>() -> ServiceDescriptorBuilder<TSvc, TImpl> {
49            Sdb::keyed::<TKey>(Scoped, Type::of::<TImpl>())
50        }
51
52        /// Initializes a new transient [ServiceDescriptorBuilder].
53        #[inline]
54        pub fn transient<TSvc: ?Sized + $($traits)+, TImpl>() -> ServiceDescriptorBuilder<TSvc, TImpl> {
55            Sdb::new(Transient, Type::of::<TImpl>())
56        }
57
58        /// Initializes a new keyed transient [ServiceDescriptorBuilder].
59        #[inline]
60        pub fn transient_with_key<TKey, TSvc: ?Sized + $($traits)+, TImpl>() -> ServiceDescriptorBuilder<TSvc, TImpl> {
61            Sdb::keyed::<TKey>(Transient, Type::of::<TImpl>())
62        }
63
64        /// Initializes a new transient [ServiceDescriptorBuilder].
65        ///
66        /// # Remarks
67        ///
68        /// This function maps a concrete type to itself rather than a trait.
69        #[inline]
70        pub fn transient_as_self<T: $($traits)+>() -> ServiceDescriptorBuilder<T, T> {
71            Sdb::new(Transient, Type::of::<T>())
72        }
73
74        /// Initializes a new transient keyed [ServiceDescriptorBuilder].
75        ///
76        /// # Remarks
77        ///
78        /// This function maps a concrete type to itself rather than a trait.
79        #[inline]
80        pub fn transient_with_key_as_self<TKey, TSvc: $($traits)+>() -> ServiceDescriptorBuilder<TSvc, TSvc> {
81            Sdb::keyed::<TKey>(Transient, Type::of::<TSvc>())
82        }
83
84        /// Creates a new singleton [ServiceDescriptor] for an existing service instance.
85        ///
86        /// # Arguments
87        ///
88        /// * `instance` - The existing service instance
89        ///
90        /// # Remarks
91        ///
92        /// This function maps an existing instance to a trait.
93        #[inline]
94        pub fn existing<TSvc: ?Sized + $($traits)+, TImpl>(instance: Box<TSvc>) -> ServiceDescriptor {
95            ServiceDescriptor::new(
96                Singleton,
97                Type::of::<TSvc>(),
98                Type::of::<TImpl>(),
99                Vec::new(),
100                OnceLock::from(Ref::new(Ref::<TSvc>::from(instance)) as Ref<dyn $($traits)+>),
101                Ref::new(no_op),
102            )
103        }
104
105        /// Creates a new singleton [ServiceDescriptor] for an existing service instance.
106        ///
107        /// # Arguments
108        ///
109        /// * `instance` - The existing service instance
110        ///
111        /// # Remarks
112        ///
113        /// This function maps an existing instance to itself rather than a trait.
114        #[inline]
115        pub fn existing_as_self<T: $($traits)+>(instance: T) -> ServiceDescriptor {
116            ServiceDescriptor::new(
117                Singleton,
118                Type::of::<T>(),
119                Type::of::<T>(),
120                Vec::new(),
121                OnceLock::from(Ref::new(Ref::from(instance)) as Ref<dyn $($traits)+>),
122                Ref::new(no_op),
123            )
124        }
125
126        /// Creates a new singleton [ServiceDescriptor] for an existing service instance with a key.
127        ///
128        /// # Arguments
129        ///
130        /// * `instance` - The existing service instance
131        ///
132        /// # Remarks
133        ///
134        /// This function maps an existing instance to a trait.
135        #[inline]
136        pub fn existing_with_key<TKey, TSvc: ?Sized + $($traits)+, TImpl>(instance: Box<TSvc>) -> ServiceDescriptor {
137            ServiceDescriptor::new(
138                Singleton,
139                Type::keyed::<TKey, TSvc>(),
140                Type::of::<TImpl>(),
141                Vec::new(),
142                OnceLock::from(Ref::new(Ref::<TSvc>::from(instance)) as Ref<dyn $($traits)+>),
143                Ref::new(no_op),
144            )
145        }
146
147        /// Creates a new singleton [ServiceDescriptor] for an existing service instance with a key.
148        ///
149        /// # Arguments
150        ///
151        /// * `instance` - The existing service instance
152        ///
153        /// # Remarks
154        ///
155        /// This function maps an existing instance to itself rather than a trait.
156        #[inline]
157        pub fn existing_with_key_as_self<TKey, TSvc: $($traits)+>(instance: TSvc) -> ServiceDescriptor {
158            ServiceDescriptor::new(
159                Singleton,
160                Type::keyed::<TKey, TSvc>(),
161                Type::of::<TSvc>(),
162                Vec::new(),
163                OnceLock::from(Ref::new(Ref::from(instance)) as Ref<dyn $($traits)+>),
164                Ref::new(no_op),
165            )
166        }
167    };
168}
169
170macro_rules! service_from_func {
171    (($($traits:tt)+), ($($bounds:tt)+)) => {
172        /// Initializes a new singleton [ServiceDescriptor].
173        ///
174        /// # Arguments
175        ///
176        /// * `factory` - The factory method used to create the service
177        #[inline]
178        pub fn singleton_factory<T: ?Sized + $($traits)+, F>(factory: F) -> ServiceDescriptor
179        where
180            F: Fn(&ServiceProvider) -> Ref<T> + $($bounds)+,
181        {
182            Sdb::<T, ()>::new(Singleton, Type::factory_of::<T>()).from(factory)
183        }
184
185        /// Initializes a new keyed singleton [ServiceDescriptor].
186        ///
187        /// # Arguments
188        ///
189        /// * `factory` - The factory method used to create the service
190        #[inline]
191        pub fn singleton_with_key_factory<TKey, TSvc: ?Sized + $($traits)+, F>(factory: F) -> ServiceDescriptor
192        where
193            F: Fn(&ServiceProvider) -> Ref<TSvc> + $($bounds)+,
194        {
195            Sdb::<TSvc, ()>::keyed::<TKey>(Singleton, Type::factory_of::<TSvc>()).from(factory)
196        }
197
198        /// Initializes a new scoped [ServiceDescriptor].
199        ///
200        /// # Arguments
201        ///
202        /// * `factory` - The factory method used to create the service
203        #[inline]
204        pub fn scoped_factory<T: ?Sized + $($traits)+, F>(factory: F) -> ServiceDescriptor
205        where
206            F: Fn(&ServiceProvider) -> Ref<T> + $($bounds)+,
207        {
208            Sdb::<T, ()>::new(Scoped, Type::factory_of::<T>()).from(factory)
209        }
210
211        /// Initializes a new keyed scoped [ServiceDescriptor].
212        ///
213        /// # Arguments
214        ///
215        /// * `factory` - The factory method used to create the service
216        #[inline]
217        pub fn scoped_with_key_factory<TKey, TSvc: ?Sized + $($traits)+, F>(factory: F) -> ServiceDescriptor
218        where
219            F: Fn(&ServiceProvider) -> Ref<TSvc> + $($bounds)+,
220        {
221            Sdb::<TSvc, ()>::keyed::<TKey>(Scoped, Type::factory_of::<TSvc>()).from(factory)
222        }
223
224        /// Initializes a new transient [ServiceDescriptor].
225        ///
226        /// # Arguments
227        ///
228        /// * `factory` - The factory method used to create the service
229        #[inline]
230        pub fn transient_factory<T: ?Sized + $($traits)+, F>(factory: F) -> ServiceDescriptor
231        where
232            F: Fn(&ServiceProvider) -> Ref<T> + $($bounds)+,
233        {
234            Sdb::<T, ()>::new(Transient, Type::factory_of::<T>()).from(factory)
235        }
236
237        /// Initializes a new keyed transient [ServiceDescriptor].
238        ///
239        /// # Arguments
240        ///
241        /// * `factory` - The factory method used to create the service
242        #[inline]
243        pub fn transient_with_key_factory<TKey, TSvc: ?Sized + $($traits)+, F>(factory: F) -> ServiceDescriptor
244        where
245            F: Fn(&ServiceProvider) -> Ref<TSvc> + $($bounds)+,
246        {
247            Sdb::<TSvc, ()>::keyed::<TKey>(Transient, Type::factory_of::<TSvc>()).from(factory)
248        }
249    };
250}
251
252cfg_if::cfg_if! {
253    if #[cfg(feature = "async")] {
254        service_from_type!(Any + Send + Sync);
255        service_from_func!((Any + Send + Sync), (Send + Sync + 'static));
256    } else {
257        service_from_type!(Any);
258        service_from_func!((Any), ('static));
259    }
260}
261
262/// Creates a new [ServiceDependency] with a cardinality of exactly one (1:1).
263#[inline]
264pub fn exactly_one<T: Any + ?Sized>() -> ServiceDependency {
265    ServiceDependency::new(Type::of::<T>(), ExactlyOne)
266}
267
268/// Creates a new keyed [ServiceDependency] with a cardinality of exactly one (1:1).
269#[inline]
270pub fn exactly_one_with_key<TKey, TSvc: Any + ?Sized>() -> ServiceDependency {
271    ServiceDependency::new(Type::keyed::<TKey, TSvc>(), ExactlyOne)
272}
273
274/// Creates a new [ServiceDependency] with a cardinality of zero or one (0:1).
275#[inline]
276pub fn zero_or_one<T: Any + ?Sized>() -> ServiceDependency {
277    ServiceDependency::new(Type::of::<T>(), ZeroOrOne)
278}
279
280/// Creates a new keyed [ServiceDependency] with a cardinality of zero or one (0:1).
281#[inline]
282pub fn zero_or_one_with_key<TKey, TSvc: Any + ?Sized>() -> ServiceDependency {
283    ServiceDependency::new(Type::keyed::<TKey, TSvc>(), ZeroOrOne)
284}
285
286/// Creates a new [ServiceDependency] with a cardinality of zero or more (0:*).
287#[inline]
288pub fn zero_or_more<T: Any + ?Sized>() -> ServiceDependency {
289    ServiceDependency::new(Type::of::<T>(), ZeroOrMore)
290}
291
292/// Creates a new keyed [ServiceDependency] with a cardinality of zero or more (0:*).
293#[inline]
294pub fn zero_or_more_with_key<TKey, TSvc: Any + ?Sized>() -> ServiceDependency {
295    ServiceDependency::new(Type::keyed::<TKey, TSvc>(), ZeroOrMore)
296}