dilib/
scoped.rs

1use crate::Container;
2use std::any::Any;
3use std::fmt::Debug;
4use std::sync::Arc;
5
6/// Represents an `Scoped` provider which provide a new instance each time.
7#[derive(Clone)]
8pub enum Scoped {
9    Factory(Arc<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>),
10    Construct(Arc<dyn Fn(&Container) -> Box<dyn Any + Send + Sync> + Send + Sync>),
11}
12
13impl Scoped {
14    /// Creates a new `Scoped` provider from a factory function.
15    pub fn from_factory<T, F>(f: F) -> Self
16    where
17        T: Send + Sync + 'static,
18        F: Fn() -> T + Send + Sync + 'static,
19    {
20        let factory = Arc::new(move || -> Box<dyn Any + Send + Sync> { Box::new(f()) });
21
22        Scoped::Factory(factory)
23    }
24
25    /// Creates a new `Scoped` provider from an inject function.
26    pub fn from_construct<T, F>(f: F) -> Self
27    where
28        T: Send + Sync + 'static,
29        F: Fn(&Container) -> T + Send + Sync + 'static,
30    {
31        let factory =
32            Arc::new(move |c: &Container| -> Box<dyn Any + Send + Sync> { Box::new(f(c)) });
33
34        Scoped::Construct(factory)
35    }
36
37    pub(crate) fn call_factory<T>(&self) -> Option<T>
38    where
39        T: Send + Sync + 'static,
40    {
41        match self {
42            Scoped::Factory(f) => {
43                let x: Box<dyn Any + Send + Sync> = f.as_ref()();
44                x.downcast().map(|x| *x).ok()
45            }
46            _ => None,
47        }
48    }
49
50    pub(crate) fn call_construct<T>(&self, container: &Container) -> Option<T>
51    where
52        T: 'static,
53    {
54        match self {
55            Scoped::Construct(f) => {
56                let x: Box<dyn Any + Send + Sync> = f.as_ref()(container);
57                x.downcast().map(|x| *x).ok()
58            }
59            _ => None,
60        }
61    }
62}
63
64impl Debug for Scoped {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        match self {
67            Scoped::Factory(_) => write!(f, "Scoped::Factory(..)"),
68            Scoped::Construct(_) => write!(f, "Scoped::Inject(..)"),
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use crate::scoped::Scoped;
76    use crate::Container;
77
78    #[test]
79    fn call_factory_test() {
80        let factory = Scoped::from_factory(|| "hello".to_string());
81        assert_eq!(factory.call_factory::<String>(), Some("hello".to_string()));
82    }
83
84    #[test]
85    fn call_construct_test() {
86        let mut container = Container::new();
87        container.add_singleton(5_i32).unwrap();
88
89        let inject = Scoped::from_construct(|c| c.get::<i32>().unwrap().cloned() + 1);
90        assert_eq!(inject.call_construct(&container), Some(6));
91    }
92}