1use crate::{KeyedRef, KeyedRefMut, Mut, Ref, RefMut, ServiceProvider};
2use spin::Once;
3use std::any::Any;
4
5pub 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 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#[inline]
51pub fn exactly_one<T: Any + ?Sized>(services: ServiceProvider) -> Lazy<Ref<T>> {
52 Lazy::new(services, ServiceProvider::get_required::<T>)
53}
54
55#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[inline]
182pub fn missing<T: Any + ?Sized>() -> Lazy<Option<Ref<T>>> {
183 Lazy::new(ServiceProvider::default(), ServiceProvider::get::<T>)
184}
185
186#[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#[inline]
197pub fn empty<T: Any + ?Sized>() -> Lazy<Vec<Ref<T>>> {
198 Lazy::new(ServiceProvider::default(), to_vec::<T>)
199}
200
201#[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
207pub 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
220pub 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
233pub 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
246pub 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 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 let foo = provider.get_required::<Foo>();
334
335 assert_eq!("Delayed!", foo.echo());
337 }
338
339 #[test]
340 fn lazy_should_return_optional_service() {
341 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 let foo = provider.get_required::<Foo2>();
354
355 assert_eq!("Delayed!", foo.echo().unwrap());
357 }
358
359 #[test]
360 fn lazy_should_allow_missing_optional_service() {
361 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 let foo = provider.get_required::<Foo2>();
373
374 assert_eq!(None, foo.echo());
376 }
377
378 #[test]
379 fn missing_should_initialize_lazy() {
380 let lazy = lazy::missing::<Bar>();
382
383 let value = lazy.value();
385
386 assert!(value.is_none());
388 }
389
390 #[test]
391 fn empty_should_initialize_lazy() {
392 let lazy = lazy::empty::<Bar>();
394
395 let value = lazy.value();
397
398 assert!(value.is_empty());
400 }
401
402 #[test]
403 #[allow(clippy::vtable_address_comparisons)]
404 fn lazy_should_return_same_scoped_service() {
405 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 let foo = provider.get_required::<Foo>();
418 let bar1 = provider.get_required::<Bar>();
419 let bar2 = provider.clone().get_required::<Bar>();
420
421 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 let instance: Box<dyn IPityTheFoo> = Box::new(FooImpl);
430
431 let lazy = lazy::init(instance);
433
434 assert_eq!(lazy.value().speak(), "I pity the foo!");
436 }
437
438 #[test]
439 fn init_with_key_should_create_lazy_from_instance() {
440 let instance = FooImpl;
442
443 let lazy = lazy::init_with_key::<Bar, dyn IPityTheFoo>(Box::new(instance));
445
446 assert_eq!(lazy.value().speak(), "I pity the foo!");
448 }
449
450 #[test]
451 fn init_mut_should_create_lazy_from_instance() {
452 let instance: Box<Mut<dyn IPityTheFoo>> = Box::new(Mut::new(FooImpl));
454
455 let lazy = lazy::init_mut(instance);
457
458 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 let instance: Box<Mut<dyn IPityTheFoo>> = Box::new(Mut::new(FooImpl));
472
473 let lazy = lazy::init_with_key_mut::<Bar, _>(instance);
475
476 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}