firebase_rs_sdk/component/
provider.rs

1use 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}