firebase_rs_sdk/component/
provider.rs1use std::any::Any;
2use std::collections::HashMap;
3use std::sync::{Arc, Mutex, Weak};
4
5use serde_json::Value;
6
7use crate::component::component::Component;
8use crate::component::constants::DEFAULT_ENTRY_NAME;
9use crate::component::container::{ComponentContainer, ComponentContainerInner};
10use crate::component::types::{
11 ComponentError, DynService, InstanceFactoryOptions, InstantiationMode,
12};
13
14#[derive(Clone)]
15pub struct Provider {
16 inner: Arc<ProviderInner>,
17}
18
19struct ProviderInner {
20 name: Arc<str>,
21 container: Weak<ComponentContainerInner>,
22 component: Mutex<Option<Component>>,
23 instances: Mutex<HashMap<Arc<str>, DynService>>,
24 instance_options: Mutex<HashMap<Arc<str>, Value>>,
25}
26
27impl Provider {
28 pub(crate) fn new(name: &str, container: ComponentContainer) -> Self {
29 let inner = ProviderInner {
30 name: Arc::from(name.to_owned()),
31 container: Arc::downgrade(&container.inner),
32 component: Mutex::new(None),
33 instances: Mutex::new(HashMap::new()),
34 instance_options: Mutex::new(HashMap::new()),
35 };
36 Self {
37 inner: Arc::new(inner),
38 }
39 }
40
41 pub fn name(&self) -> &str {
42 &self.inner.name
43 }
44
45 pub fn component_type(&self) -> Option<crate::component::types::ComponentType> {
46 self.inner
47 .component
48 .lock()
49 .unwrap()
50 .as_ref()
51 .map(|component| component.component_type())
52 }
53
54 pub fn is_component_set(&self) -> bool {
55 self.inner.component.lock().unwrap().is_some()
56 }
57
58 pub fn is_initialized(&self, identifier: Option<&str>) -> bool {
59 let id = self.normalize_identifier(identifier);
60 self.inner.instances.lock().unwrap().contains_key(&id)
61 }
62
63 pub fn clear_instance(&self, identifier: &str) {
64 let id = Arc::from(identifier.to_owned());
65 self.inner.instances.lock().unwrap().remove(&id);
66 self.inner.instance_options.lock().unwrap().remove(&id);
67 }
68
69 pub fn delete(&self) -> Result<(), ComponentError> {
70 self.inner.instances.lock().unwrap().clear();
71 self.inner.instance_options.lock().unwrap().clear();
72 Ok(())
73 }
74
75 pub fn get_immediate<T>(&self) -> Option<Arc<T>>
76 where
77 T: Any + Send + Sync + 'static,
78 {
79 self.get_immediate_with_options::<T>(None, true)
80 .ok()
81 .flatten()
82 }
83
84 pub fn get_immediate_with_options<T>(
85 &self,
86 identifier: Option<&str>,
87 optional: bool,
88 ) -> Result<Option<Arc<T>>, ComponentError>
89 where
90 T: Any + Send + Sync + 'static,
91 {
92 match self.get_or_initialize(identifier, Value::Null, false) {
93 Ok(Some(service)) => match service.downcast::<T>() {
94 Ok(value) => Ok(Some(value)),
95 Err(_) => Ok(None),
96 },
97 Ok(None) => Ok(None),
98 Err(err) => {
99 if optional {
100 Ok(None)
101 } else {
102 Err(err)
103 }
104 }
105 }
106 }
107
108 pub fn initialize<T>(
109 &self,
110 options: Value,
111 identifier: Option<&str>,
112 ) -> Result<Arc<T>, ComponentError>
113 where
114 T: Any + Send + Sync + 'static,
115 {
116 if self.is_initialized(identifier) {
117 return Err(ComponentError::InstanceAlreadyInitialized {
118 name: self.name().to_string(),
119 identifier: identifier.unwrap_or(DEFAULT_ENTRY_NAME).to_string(),
120 });
121 }
122
123 match self.get_or_initialize(identifier, options.clone(), true)? {
124 Some(service) => {
125 service
126 .downcast::<T>()
127 .map_err(|_| ComponentError::InstanceUnavailable {
128 name: self.name().to_string(),
129 })
130 }
131 None => Err(ComponentError::InstanceUnavailable {
132 name: self.name().to_string(),
133 }),
134 }
135 }
136
137 pub fn get_options(&self, identifier: Option<&str>) -> Value {
138 let id = self.normalize_identifier(identifier);
139 self.inner
140 .instance_options
141 .lock()
142 .unwrap()
143 .get(&id)
144 .cloned()
145 .unwrap_or(Value::Null)
146 }
147
148 pub fn set_component(&self, component: Component) -> Result<(), ComponentError> {
149 if component.name() != self.name() {
150 return Err(ComponentError::MismatchingComponent {
151 expected: self.name().to_string(),
152 found: component.name().to_string(),
153 });
154 }
155
156 {
157 let mut guard = self.inner.component.lock().unwrap();
158 if guard.is_some() {
159 return Err(ComponentError::ComponentAlreadyProvided {
160 name: self.name().to_string(),
161 });
162 }
163 *guard = Some(component.clone());
164 }
165
166 if !self.should_auto_initialize() {
167 return Ok(());
168 }
169
170 if component.instantiation_mode() == InstantiationMode::Eager {
171 let _ = self.get_or_initialize(Some(DEFAULT_ENTRY_NAME), Value::Null, true);
172 }
173
174 Ok(())
175 }
176
177 fn get_or_initialize(
178 &self,
179 identifier: Option<&str>,
180 options: Value,
181 force: bool,
182 ) -> Result<Option<DynService>, ComponentError> {
183 let id = self.normalize_identifier(identifier);
184
185 if let Some(instance) = self.inner.instances.lock().unwrap().get(&id) {
186 return Ok(Some(instance.clone()));
187 }
188
189 let component = match self.inner.component.lock().unwrap().clone() {
190 Some(component) => component,
191 None => return Ok(None),
192 };
193
194 if !force && !self.should_auto_initialize() {
195 return Ok(None);
196 }
197
198 let container = match self.inner.container.upgrade() {
199 Some(inner) => ComponentContainer { inner },
200 None => {
201 return Err(ComponentError::InitializationFailed {
202 name: self.name().to_string(),
203 reason: "container dropped".into(),
204 });
205 }
206 };
207
208 let options_record = options.clone();
209 let factory_options = InstanceFactoryOptions::new(
210 if id.as_ref() == DEFAULT_ENTRY_NAME {
211 None
212 } else {
213 Some(id.to_string())
214 },
215 options,
216 );
217
218 let instance = match (component.instance_factory)(&container, factory_options) {
219 Ok(instance) => instance,
220 Err(err) => {
221 return Err(ComponentError::InitializationFailed {
222 name: self.name().to_string(),
223 reason: err.to_string(),
224 });
225 }
226 };
227
228 self.inner
229 .instances
230 .lock()
231 .unwrap()
232 .insert(id.clone(), instance.clone());
233 self.inner
234 .instance_options
235 .lock()
236 .unwrap()
237 .insert(id.clone(), options_record);
238
239 if let Some(callback) = component.on_instance_created() {
240 callback(&container, id.as_ref(), &instance);
241 }
242
243 Ok(Some(instance))
244 }
245
246 fn normalize_identifier(&self, identifier: Option<&str>) -> Arc<str> {
247 let id = identifier.unwrap_or(DEFAULT_ENTRY_NAME);
248 if let Some(component) = self.inner.component.lock().unwrap().as_ref() {
249 if component.multiple_instances() {
250 return Arc::from(id.to_owned());
251 }
252 }
253 Arc::from(DEFAULT_ENTRY_NAME.to_owned())
254 }
255
256 fn should_auto_initialize(&self) -> bool {
257 self.inner
258 .component
259 .lock()
260 .unwrap()
261 .as_ref()
262 .map(|component| component.instantiation_mode() != InstantiationMode::Explicit)
263 .unwrap_or(false)
264 }
265}