1use crate::Container;
2use std::any::Any;
3use std::fmt::Debug;
4use std::sync::Arc;
5
6#[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 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 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}