• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Core dependency injection objects
2 
3 use std::any::{Any, TypeId};
4 use std::collections::HashMap;
5 use std::future::Future;
6 use std::pin::Pin;
7 use std::sync::Arc;
8 use tokio::sync::Mutex;
9 
10 pub use gddi_macros::{module, part_out, provides, Stoppable};
11 
12 type InstanceBox = Box<dyn Any + Send + Sync>;
13 /// A box around a future for a provider that is safe to send between threads
14 pub type ProviderFutureBox = Box<dyn Future<Output = Box<dyn Any>> + Send + Sync>;
15 type ProviderFnBox = Box<dyn Fn(Arc<Registry>) -> Pin<ProviderFutureBox> + Send + Sync>;
16 
17 /// Called to stop an injected object
18 pub trait Stoppable {
19     /// Stop and close all resources
stop(&self)20     fn stop(&self) {}
21 }
22 
23 /// Builder for Registry
24 pub struct RegistryBuilder {
25     providers: HashMap<TypeId, Provider>,
26 }
27 
28 /// Keeps track of central injection state
29 pub struct Registry {
30     providers: Arc<Mutex<HashMap<TypeId, Provider>>>,
31     instances: Arc<Mutex<HashMap<TypeId, InstanceBox>>>,
32     start_order: Arc<Mutex<Vec<Box<dyn Stoppable + Send + Sync>>>>,
33 }
34 
35 #[derive(Clone)]
36 struct Provider {
37     f: Arc<ProviderFnBox>,
38 }
39 
40 impl Default for RegistryBuilder {
default() -> Self41     fn default() -> Self {
42         Self::new()
43     }
44 }
45 
46 impl RegistryBuilder {
47     /// Creates a new RegistryBuilder
new() -> Self48     pub fn new() -> Self {
49         RegistryBuilder { providers: HashMap::new() }
50     }
51 
52     /// Registers a module with this registry
register_module<F>(self, init: F) -> Self where F: Fn(Self) -> Self,53     pub fn register_module<F>(self, init: F) -> Self
54     where
55         F: Fn(Self) -> Self,
56     {
57         init(self)
58     }
59 
60     /// Registers a provider function with this registry
register_provider<T: 'static>(mut self, f: ProviderFnBox) -> Self61     pub fn register_provider<T: 'static>(mut self, f: ProviderFnBox) -> Self {
62         self.providers.insert(TypeId::of::<T>(), Provider { f: Arc::new(f) });
63 
64         self
65     }
66 
67     /// Construct the Registry from this builder
build(self) -> Registry68     pub fn build(self) -> Registry {
69         Registry {
70             providers: Arc::new(Mutex::new(self.providers)),
71             instances: Arc::new(Mutex::new(HashMap::new())),
72             start_order: Arc::new(Mutex::new(Vec::new())),
73         }
74     }
75 }
76 
77 impl Registry {
78     /// Gets an instance of a type, implicitly starting any dependencies if necessary
get<T: 'static + Clone + Send + Sync + Stoppable>(self: &Arc<Self>) -> T79     pub async fn get<T: 'static + Clone + Send + Sync + Stoppable>(self: &Arc<Self>) -> T {
80         let typeid = TypeId::of::<T>();
81         {
82             let instances = self.instances.lock().await;
83             if let Some(value) = instances.get(&typeid) {
84                 return value.downcast_ref::<T>().expect("was not correct type").clone();
85             }
86         }
87 
88         let casted = {
89             let provider = { self.providers.lock().await[&typeid].clone() };
90             let result = (provider.f)(self.clone()).await;
91             (*result.downcast::<T>().expect("was not correct type")).clone()
92         };
93 
94         let mut instances = self.instances.lock().await;
95         instances.insert(typeid, Box::new(casted.clone()));
96 
97         let mut start_order = self.start_order.lock().await;
98         start_order.push(Box::new(casted.clone()));
99 
100         casted
101     }
102 
103     /// Inject an already created instance of T. Useful for config.
inject<T: 'static + Clone + Send + Sync>(self: &Arc<Self>, obj: T)104     pub async fn inject<T: 'static + Clone + Send + Sync>(self: &Arc<Self>, obj: T) {
105         let mut instances = self.instances.lock().await;
106         instances.insert(TypeId::of::<T>(), Box::new(obj));
107     }
108 
109     /// Stop all instances, in reverse order of start.
stop_all(self: &Arc<Self>)110     pub async fn stop_all(self: &Arc<Self>) {
111         let mut start_order = self.start_order.lock().await;
112         while let Some(obj) = start_order.pop() {
113             obj.stop();
114         }
115         self.instances.lock().await.clear();
116     }
117 }
118 
119 impl<T> Stoppable for std::sync::Arc<T> {}
120