1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
use crate::inject::Inject;
use crate::provider::{Provider, RefProvider};
use crate::Container;

#[macro_export]
macro_rules! singleton {
    ($injectable:ty) => {{
        struct SingletonProvider {
            instance: std::sync::Mutex<Option<std::sync::Arc<$injectable>>>,
        }

        impl $crate::Provider for SingletonProvider {
            type ProvidedType = std::sync::Arc<$injectable>;
            fn provide(
                &self,
                c: &$crate::Container,
            ) -> Result<Self::ProvidedType, $crate::InjectError> {
                loop {
                    let mut instance = self.instance.lock().unwrap();

                    if let Some(instance) = instance.as_ref() {
                        return Ok(std::sync::Arc::clone(&instance));
                    } else {
                        let maybe_instance = $crate::get!(&c, $injectable);
                        match maybe_instance {
                            Ok(maybe_instance) => {
                                *instance = Some(std::sync::Arc::new(maybe_instance));
                            }
                            Err(err) => return Err(err),
                        }
                    }
                }
            }
        }
        SingletonProvider {
            instance: std::sync::Mutex::default(),
        }
    }};
}