elif_core/container/
scope.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
3pub enum ServiceScope {
4 #[default]
6 Singleton,
7 Transient,
9 Scoped,
11}
12
13pub type ServiceLifetime = ServiceScope;
15
16impl ServiceScope {
17 pub fn is_singleton(&self) -> bool {
19 matches!(self, ServiceScope::Singleton)
20 }
21
22 pub fn is_transient(&self) -> bool {
24 matches!(self, ServiceScope::Transient)
25 }
26
27 pub fn is_scoped(&self) -> bool {
29 matches!(self, ServiceScope::Scoped)
30 }
31
32 pub fn as_str(&self) -> &'static str {
34 match self {
35 ServiceScope::Singleton => "singleton",
36 ServiceScope::Transient => "transient",
37 ServiceScope::Scoped => "scoped",
38 }
39 }
40}
41
42impl std::fmt::Display for ServiceScope {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "{}", self.as_str())
45 }
46}
47
48impl std::str::FromStr for ServiceScope {
49 type Err = crate::errors::CoreError;
50
51 fn from_str(s: &str) -> Result<Self, Self::Err> {
52 match s.to_lowercase().as_str() {
53 "singleton" => Ok(ServiceScope::Singleton),
54 "transient" => Ok(ServiceScope::Transient),
55 "scoped" => Ok(ServiceScope::Scoped),
56 _ => Err(crate::errors::CoreError::InvalidServiceScope {
57 scope: s.to_string(),
58 }),
59 }
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
65pub struct ScopeId(uuid::Uuid);
66
67impl ScopeId {
68 pub fn new() -> Self {
70 Self(uuid::Uuid::new_v4())
71 }
72
73 pub fn as_uuid(&self) -> uuid::Uuid {
75 self.0
76 }
77}
78
79impl Default for ScopeId {
80 fn default() -> Self {
81 Self::new()
82 }
83}
84
85impl std::fmt::Display for ScopeId {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "{}", self.0)
88 }
89}
90
91#[derive(Debug)]
93pub struct ScopedServiceManager {
94 scope_id: ScopeId,
95 services: std::sync::RwLock<
96 std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any + Send + Sync>>,
97 >,
98 parent: Option<std::sync::Arc<ScopedServiceManager>>,
99}
100
101impl ScopedServiceManager {
102 pub fn new() -> Self {
104 Self {
105 scope_id: ScopeId::new(),
106 services: std::sync::RwLock::new(std::collections::HashMap::new()),
107 parent: None,
108 }
109 }
110
111 pub fn create_child(parent: std::sync::Arc<Self>) -> Self {
114 Self {
115 scope_id: ScopeId::new(),
116 services: std::sync::RwLock::new(std::collections::HashMap::new()),
117 parent: Some(parent),
118 }
119 }
120
121 pub fn scope_id(&self) -> &ScopeId {
123 &self.scope_id
124 }
125
126 pub fn add_service<T>(&self, service: T)
128 where
129 T: Send + Sync + 'static,
130 {
131 let type_id = std::any::TypeId::of::<T>();
132 let mut services = self.services.write().unwrap();
133 services.insert(type_id, Box::new(service));
134 }
135
136 pub fn add_arc_service<T>(&self, service: std::sync::Arc<T>)
138 where
139 T: Send + Sync + 'static,
140 {
141 let type_id = std::any::TypeId::of::<T>();
142 let mut services = self.services.write().unwrap();
143 services.insert(type_id, Box::new(service));
144 }
145
146 pub fn get_arc_service<T>(&self) -> Option<std::sync::Arc<T>>
149 where
150 T: Send + Sync + 'static,
151 {
152 let type_id = std::any::TypeId::of::<T>();
153
154 {
156 let services = self.services.read().unwrap();
157 if let Some(service) = services.get(&type_id) {
158 if let Some(arc) = service.downcast_ref::<std::sync::Arc<T>>() {
159 return Some(arc.clone());
160 }
161 }
162 }
163
164 self.parent.as_ref()?.get_arc_service::<T>()
166 }
167
168 pub fn has_service<T>(&self) -> bool
170 where
171 T: Send + Sync + 'static,
172 {
173 let type_id = std::any::TypeId::of::<T>();
174
175 {
177 let services = self.services.read().unwrap();
178 if services.contains_key(&type_id) {
179 return true;
180 }
181 }
182
183 self.parent.as_ref().is_some_and(|p| p.has_service::<T>())
185 }
186
187 pub fn has_service_local<T>(&self) -> bool
189 where
190 T: Send + Sync + 'static,
191 {
192 let type_id = std::any::TypeId::of::<T>();
193 let services = self.services.read().unwrap();
194 services.contains_key(&type_id)
195 }
196
197 pub fn clear(&self) {
199 let mut services = self.services.write().unwrap();
200 services.clear();
201 }
202
203 pub fn service_count(&self) -> usize {
205 let services = self.services.read().unwrap();
206 services.len()
207 }
208
209 pub fn parent(&self) -> Option<&std::sync::Arc<ScopedServiceManager>> {
211 self.parent.as_ref()
212 }
213}
214
215impl Default for ScopedServiceManager {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_service_scope_from_str() {
231 assert_eq!(
232 "singleton".parse::<ServiceScope>().unwrap(),
233 ServiceScope::Singleton
234 );
235 assert_eq!(
236 "transient".parse::<ServiceScope>().unwrap(),
237 ServiceScope::Transient
238 );
239 assert_eq!(
240 "scoped".parse::<ServiceScope>().unwrap(),
241 ServiceScope::Scoped
242 );
243
244 assert!("invalid".parse::<ServiceScope>().is_err());
245 }
246
247 #[test]
248 fn test_service_scope_display() {
249 assert_eq!(format!("{}", ServiceScope::Singleton), "singleton");
250 assert_eq!(format!("{}", ServiceScope::Transient), "transient");
251 assert_eq!(format!("{}", ServiceScope::Scoped), "scoped");
252 }
253
254 #[test]
255 fn test_scoped_service_manager() {
256 let manager = ScopedServiceManager::new();
257
258 manager.add_arc_service(std::sync::Arc::new("test_string".to_string()));
260 manager.add_arc_service(std::sync::Arc::new(42u32));
261
262 assert!(manager.has_service::<String>());
263 assert!(manager.has_service::<u32>());
264 assert!(!manager.has_service::<i32>());
265
266 assert_eq!(
267 *manager.get_arc_service::<String>().unwrap(),
268 "test_string".to_string()
269 );
270 assert_eq!(*manager.get_arc_service::<u32>().unwrap(), 42u32);
271
272 assert_eq!(manager.service_count(), 2);
273
274 manager.clear();
275 assert_eq!(manager.service_count(), 0);
276 }
277
278 #[test]
279 fn test_scope_inheritance() {
280 let parent = std::sync::Arc::new(ScopedServiceManager::new());
281
282 parent.add_arc_service(std::sync::Arc::new("parent_string".to_string()));
284 parent.add_arc_service(std::sync::Arc::new(100u32));
285
286 let child = std::sync::Arc::new(ScopedServiceManager::create_child(parent.clone()));
288
289 child.add_arc_service(std::sync::Arc::new(200u32));
291
292 assert_eq!(*child.get_arc_service::<u32>().unwrap(), 200u32);
294
295 assert_eq!(
297 *child.get_arc_service::<String>().unwrap(),
298 "parent_string".to_string()
299 );
300
301 assert_eq!(*parent.get_arc_service::<u32>().unwrap(), 100u32);
303
304 assert_eq!(parent.service_count(), 2);
306 assert_eq!(child.service_count(), 1); assert!(child.has_service::<String>()); assert!(child.has_service::<u32>()); assert!(!child.has_service_local::<String>()); assert!(child.has_service_local::<u32>()); }
314}