di/
lazy_init.rs

1use crate::{KeyedRef, KeyedRefMut, Mut, Ref, RefMut, ServiceProvider};
2use spin::Once;
3use std::any::Any;
4
5/// Represents a holder for lazily-initialized service resolution.
6pub struct Lazy<T> {
7    services: ServiceProvider,
8    resolve: fn(&ServiceProvider) -> T,
9    value: Once<T>,
10}
11
12impl<T> Lazy<T> {
13    fn new(services: ServiceProvider, resolve: fn(&ServiceProvider) -> T) -> Self {
14        Self {
15            services,
16            resolve,
17            value: Once::new(),
18        }
19    }
20
21    /// Resolves and returns a reference to the underlying, lazy-initialized service.
22    pub fn value(&self) -> &T {
23        self.value.call_once(|| (self.resolve)(&self.services))
24    }
25}
26
27fn to_vec<T: Any + ?Sized>(services: &ServiceProvider) -> Vec<Ref<T>> {
28    services.get_all::<T>().collect()
29}
30
31fn to_vec_mut<T: Any + ?Sized>(services: &ServiceProvider) -> Vec<RefMut<T>> {
32    services.get_all_mut::<T>().collect()
33}
34
35fn to_keyed_vec<TKey, TSvc: Any + ?Sized>(services: &ServiceProvider) -> Vec<KeyedRef<TKey, TSvc>> {
36    services.get_all_by_key::<TKey, TSvc>().collect()
37}
38
39fn to_keyed_vec_mut<TKey, TSvc: Any + ?Sized>(
40    services: &ServiceProvider,
41) -> Vec<KeyedRefMut<TKey, TSvc>> {
42    services.get_all_by_key_mut::<TKey, TSvc>().collect()
43}
44
45/// Creates and returns a holder for a lazily-initialized, required service.
46///
47/// # Arguments
48///
49/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
50#[inline]
51pub fn exactly_one<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<Ref<T>> {
52    Lazy::new(services, ServiceProvider::get_required::<T>)
53}
54
55/// Creates and returns a holder for a lazily-initialized, required, mutable service.
56///
57/// # Arguments
58///
59/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
60#[inline]
61pub fn exactly_one_mut<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<RefMut<T>> {
62    Lazy::new(services, ServiceProvider::get_required_mut::<T>)
63}
64
65/// Creates and returns a holder for a lazily-initialized, keyed, required service.
66///
67/// # Arguments
68///
69/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
70#[inline]
71pub fn exactly_one_with_key<TKey, TSvc: Any + ?Sized>(
72    services: ServiceProvider,
73) -> Lazy<KeyedRef<TKey, TSvc>> {
74    Lazy::new(services, ServiceProvider::get_required_by_key::<TKey, TSvc>)
75}
76
77/// Creates and returns a holder for a lazily-initialized, keyed, required, mutable service.
78///
79/// # Arguments
80///
81/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
82#[inline]
83pub fn exactly_one_with_key_mut<TKey, TSvc: Any + ?Sized>(
84    services: ServiceProvider,
85) -> Lazy<KeyedRefMut<TKey, TSvc>> {
86    Lazy::new(
87        services,
88        ServiceProvider::get_required_by_key_mut::<TKey, TSvc>,
89    )
90}
91
92/// Creates and returns a holder for a lazily-initialized, optional service.
93///
94/// # Arguments
95///
96/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
97#[inline]
98pub fn zero_or_one<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<Option<Ref<T>>> {
99    Lazy::new(services, ServiceProvider::get::<T>)
100}
101
102/// Creates and returns a holder for a lazily-initialized, optional, mutable service.
103///
104/// # Arguments
105///
106/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
107#[inline]
108pub fn zero_or_one_mut<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<Option<RefMut<T>>> {
109    Lazy::new(services, ServiceProvider::get_mut::<T>)
110}
111
112/// Creates and returns a holder for a lazily-initialized, keyed, optional service.
113///
114/// # Arguments
115///
116/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
117#[inline]
118pub fn zero_or_one_with_key<TKey, TSvc: Any + ?Sized>(
119    services: ServiceProvider,
120) -> Lazy<Option<KeyedRef<TKey, TSvc>>> {
121    Lazy::new(services, ServiceProvider::get_by_key::<TKey, TSvc>)
122}
123
124/// Creates and returns a holder for a lazily-initialized, keyed, optional, mutable service.
125///
126/// # Arguments
127///
128/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the service
129#[inline]
130pub fn zero_or_one_with_key_mut<TKey, TSvc: Any + ?Sized>(
131    services: ServiceProvider,
132) -> Lazy<Option<KeyedRefMut<TKey, TSvc>>> {
133    Lazy::new(services, ServiceProvider::get_by_key_mut::<TKey, TSvc>)
134}
135
136/// Creates and returns a holder for multiple, lazily-initialized services.
137///
138/// # Arguments
139///
140/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the services
141#[inline]
142pub fn zero_or_more<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<Vec<Ref<T>>> {
143    Lazy::new(services, to_vec::<T>)
144}
145
146/// Creates and returns a holder for multiple, lazily-initialized, mutable services.
147///
148/// # Arguments
149///
150/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the services
151#[inline]
152pub fn zero_or_more_mut<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<Vec<RefMut<T>>> {
153    Lazy::new(services, to_vec_mut::<T>)
154}
155
156/// Creates and returns a holder for multiple, lazily-initialized, keyed services.
157///
158/// # Arguments
159///
160/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the services
161#[inline]
162pub fn zero_or_more_with_key<TKey, TSvc: Any + ?Sized>(
163    services: ServiceProvider,
164) -> Lazy<Vec<KeyedRef<TKey, TSvc>>> {
165    Lazy::new(services, to_keyed_vec::<TKey, TSvc>)
166}
167
168/// Creates and returns a holder for multiple, lazily-initialized, keyed, mutable services.
169///
170/// # Arguments
171///
172/// * `services` - The [`ServiceProvider`](crate::ServiceProvider) used to resolve the services
173#[inline]
174pub fn zero_or_more_with_key_mut<TKey, TSvc: Any + ?Sized>(
175    services: ServiceProvider,
176) -> Lazy<Vec<KeyedRefMut<TKey, TSvc>>> {
177    Lazy::new(services, to_keyed_vec_mut::<TKey, TSvc>)
178}
179
180/// Creates and return a holder for a lazy-initialized, optional service that is missing.
181#[inline]
182pub fn missing<T: Any + ?Sized>() -> Lazy<Option<Ref<T>>> {
183    Lazy::new(ServiceProvider::default(), ServiceProvider::get::<T>)
184}
185
186/// Creates and return a holder for a lazy-initialized, keyed, optional service that is missing.
187#[inline]
188pub fn missing_with_key<TKey, TSvc: Any + ?Sized>() -> Lazy<Option<KeyedRef<TKey, TSvc>>> {
189    Lazy::new(
190        ServiceProvider::default(),
191        ServiceProvider::get_by_key::<TKey, TSvc>,
192    )
193}
194
195/// Creates and return a holder for any empty collection of lazy-initialized services.
196#[inline]
197pub fn empty<T: Any + ?Sized>() -> Lazy<Vec<Ref<T>>> {
198    Lazy::new(ServiceProvider::default(), to_vec::<T>)
199}
200
201/// Creates and return a holder for any empty collection of lazy-initialized, keyed services.
202#[inline]
203pub fn empty_with_key<TKey, TSvc: Any + ?Sized>() -> Lazy<Vec<KeyedRef<TKey, TSvc>>> {
204    Lazy::new(ServiceProvider::default(), to_keyed_vec::<TKey, TSvc>)
205}
206
207/// Creates and returns a holder from an existing instance.
208/// 
209/// # Arguments
210/// 
211/// * `instance` - The existing instance used to initialize with
212pub fn init<T: Any + ?Sized>(instance: Box<T>) -> Lazy<Ref<T>> {
213    Lazy {
214        resolve: |_| unimplemented!(),
215        services: ServiceProvider::default(),
216        value: Once::initialized(Ref::from(instance)),
217    }
218}
219
220/// Creates and returns a holder from an existing, mutable instance.
221/// 
222/// # Arguments
223/// 
224/// * `instance` - The existing instance used to initialize with
225pub fn init_mut<T: Any + ?Sized>(instance: Box<Mut<T>>) -> Lazy<RefMut<T>> {
226    Lazy {
227        resolve: |_| unimplemented!(),
228        services: ServiceProvider::default(),
229        value: Once::initialized(RefMut::from(instance)),
230    }
231}
232
233/// Creates and returns a holder from an existing instance with a key.
234/// 
235/// # Arguments
236/// 
237/// * `instance` - The existing instance used to initialize with
238pub fn init_with_key<TKey, TSvc: Any + ?Sized>(instance: Box<TSvc>) -> Lazy<KeyedRef<TKey, TSvc>> {
239    Lazy {
240        resolve: |_| unimplemented!(),
241        services: ServiceProvider::default(),
242        value: Once::initialized(KeyedRef::<TKey, TSvc>::new(Ref::from(instance))),
243    }
244}
245
246/// Creates and returns a holder from an existing, mutable instance with a key.
247/// 
248/// # Arguments
249/// 
250/// * `instance` - The existing instance used to initialize with
251pub fn init_with_key_mut<TKey, TSvc: Any + ?Sized>(
252    instance: Box<Mut<TSvc>>,
253) -> Lazy<KeyedRefMut<TKey, TSvc>> {
254    Lazy {
255        resolve: |_| unimplemented!(),
256        services: ServiceProvider::default(),
257        value: Once::initialized(KeyedRefMut::<TKey, TSvc>::new(Ref::from(instance))),
258    }
259}
260
261#[cfg(test)]
262mod tests {
263    use super::*;
264    use crate::*;
265    use cfg_if::cfg_if;
266
267    #[derive(Default)]
268    struct Bar;
269
270    struct Foo {
271        bar: Lazy<Ref<Bar>>,
272    }
273
274    struct Foo2 {
275        bar: Lazy<Option<Ref<Bar>>>,
276    }
277
278    impl Bar {
279        fn echo(&self) -> &str {
280            "Delayed!"
281        }
282    }
283
284    impl Foo {
285        fn new(bar: Lazy<Ref<Bar>>) -> Self {
286            Self { bar }
287        }
288
289        fn echo(&self) -> &str {
290            self.bar.value().echo()
291        }
292    }
293
294    impl Foo2 {
295        fn new(bar: Lazy<Option<Ref<Bar>>>) -> Self {
296            Self { bar }
297        }
298
299        fn echo(&self) -> Option<&str> {
300            match self.bar.value() {
301                Some(bar) => Some(bar.echo()),
302                _ => None,
303            }
304        }
305    }
306
307    trait IPityTheFoo {
308        fn speak(&self) -> &str;
309    }
310
311    struct FooImpl;
312
313    impl IPityTheFoo for FooImpl {
314        fn speak(&self) -> &str {
315            "I pity the foo!"
316        }
317    }
318
319    #[test]
320    fn lazy_should_return_required_service() {
321        // arrange
322        let provider = ServiceCollection::new()
323            .add(transient_as_self::<Bar>().from(|_| Ref::new(Bar::default())))
324            .add(
325                transient_as_self::<Foo>()
326                    .depends_on(crate::exactly_one::<Bar>())
327                    .from(|sp| Ref::new(Foo::new(lazy::exactly_one::<Bar>(sp.clone())))),
328            )
329            .build_provider()
330            .unwrap();
331
332        // act
333        let foo = provider.get_required::<Foo>();
334
335        // assert
336        assert_eq!("Delayed!", foo.echo());
337    }
338
339    #[test]
340    fn lazy_should_return_optional_service() {
341        // arrange
342        let provider = ServiceCollection::new()
343            .add(transient_as_self::<Bar>().from(|_| Ref::new(Bar::default())))
344            .add(
345                transient_as_self::<Foo2>()
346                    .depends_on(crate::zero_or_one::<Bar>())
347                    .from(|sp| Ref::new(Foo2::new(lazy::zero_or_one::<Bar>(sp.clone())))),
348            )
349            .build_provider()
350            .unwrap();
351
352        // act
353        let foo = provider.get_required::<Foo2>();
354
355        // assert
356        assert_eq!("Delayed!", foo.echo().unwrap());
357    }
358
359    #[test]
360    fn lazy_should_allow_missing_optional_service() {
361        // arrange
362        let provider = ServiceCollection::new()
363            .add(
364                transient_as_self::<Foo2>()
365                    .depends_on(crate::zero_or_one::<Bar>())
366                    .from(|sp| Ref::new(Foo2::new(lazy::zero_or_one::<Bar>(sp.clone())))),
367            )
368            .build_provider()
369            .unwrap();
370
371        // act
372        let foo = provider.get_required::<Foo2>();
373
374        // assert
375        assert_eq!(None, foo.echo());
376    }
377
378    #[test]
379    fn missing_should_initialize_lazy() {
380        // arrange
381        let lazy = lazy::missing::<Bar>();
382
383        // act
384        let value = lazy.value();
385
386        // assert
387        assert!(value.is_none());
388    }
389
390    #[test]
391    fn empty_should_initialize_lazy() {
392        // arrange
393        let lazy = lazy::empty::<Bar>();
394
395        // act
396        let value = lazy.value();
397
398        // assert
399        assert!(value.is_empty());
400    }
401
402    #[test]
403    #[allow(clippy::vtable_address_comparisons)]
404    fn lazy_should_return_same_scoped_service() {
405        // arrange
406        let provider = ServiceCollection::new()
407            .add(scoped_factory(|_| Ref::new(Bar::default())))
408            .add(
409                transient_as_self::<Foo>()
410                    .depends_on(crate::exactly_one::<Bar>())
411                    .from(|sp| Ref::new(Foo::new(lazy::exactly_one::<Bar>(sp.clone())))),
412            )
413            .build_provider()
414            .unwrap();
415
416        // act
417        let foo = provider.get_required::<Foo>();
418        let bar1 = provider.get_required::<Bar>();
419        let bar2 = provider.clone().get_required::<Bar>();
420
421        // assert
422        assert!(Ref::ptr_eq(foo.bar.value(), &bar1));
423        assert!(Ref::ptr_eq(&bar1, &bar2));
424    }
425
426    #[test]
427    fn init_should_create_lazy_from_instance() {
428        // arrange
429        let instance: Box<dyn IPityTheFoo> = Box::new(FooImpl);
430
431        // act
432        let lazy = lazy::init(instance);
433
434        // assert
435        assert_eq!(lazy.value().speak(), "I pity the foo!");
436    }
437
438    #[test]
439    fn init_with_key_should_create_lazy_from_instance() {
440        // arrange
441        let instance = FooImpl;
442
443        // act
444        let lazy = lazy::init_with_key::<Bar, dyn IPityTheFoo>(Box::new(instance));
445
446        // assert
447        assert_eq!(lazy.value().speak(), "I pity the foo!");
448    }
449
450    #[test]
451    fn init_mut_should_create_lazy_from_instance() {
452        // arrange
453        let instance: Box<Mut<dyn IPityTheFoo>> = Box::new(Mut::new(FooImpl));
454
455        // act
456        let lazy = lazy::init_mut(instance);
457
458        // assert
459        cfg_if! {
460            if #[cfg(feature = "async")] {
461                assert_eq!(lazy.value().read().unwrap().speak(), "I pity the foo!");
462            } else {
463                assert_eq!(lazy.value().borrow().speak(), "I pity the foo!");
464            }
465        }
466    }
467
468    #[test]
469    fn init_with_key_mut_should_create_lazy_from_instance() {
470        // arrange
471        let instance: Box<Mut<dyn IPityTheFoo>> = Box::new(Mut::new(FooImpl));
472
473        // act
474        let lazy = lazy::init_with_key_mut::<Bar, _>(instance);
475
476        // assert
477        cfg_if! {
478            if #[cfg(feature = "async")] {
479                assert_eq!(lazy.value().write().unwrap().speak(), "I pity the foo!");
480            } else {
481                assert_eq!(lazy.value().borrow().speak(), "I pity the foo!");
482            }
483        }
484    }
485}