1use std::collections::HashMap;
10use std::sync::{Arc, Mutex, RwLock};
11use std::time::{Duration, Instant};
13use crate::{Key, DiResult, DiError};
14use crate::registration::AnyArc;
15
16#[derive(Debug)]
21pub struct ResolutionCache {
22 cache: RwLock<HashMap<Key, CacheEntry>>,
24 config: CacheConfig,
26 stats: Mutex<CacheStats>,
28}
29
30#[derive(Debug, Clone)]
31struct CacheEntry {
32 service: AnyArc,
34 created_at: Instant,
36 access_count: u64,
38 last_accessed: Instant,
40}
41
42#[derive(Debug, Clone)]
43pub struct CacheConfig {
44 pub max_entries: usize,
46 pub ttl: Option<Duration>,
48 pub enable_lru: bool,
50 pub track_access_count: bool,
52}
53
54impl Default for CacheConfig {
55 fn default() -> Self {
56 Self {
57 max_entries: 1000,
58 ttl: Some(Duration::from_secs(300)), enable_lru: true,
60 track_access_count: true,
61 }
62 }
63}
64
65#[derive(Debug, Default)]
66pub struct CacheStats {
67 pub hits: u64,
69 pub misses: u64,
71 pub ttl_evictions: u64,
73 pub lru_evictions: u64,
75}
76
77impl CacheStats {
78 pub fn hit_ratio(&self) -> f64 {
80 let total = self.hits + self.misses;
81 if total == 0 {
82 0.0
83 } else {
84 (self.hits as f64 / total as f64) * 100.0
85 }
86 }
87}
88
89impl ResolutionCache {
90 pub fn new() -> Self {
92 Self::with_config(CacheConfig::default())
93 }
94
95 pub fn with_config(config: CacheConfig) -> Self {
97 Self {
98 cache: RwLock::new(HashMap::new()),
99 config,
100 stats: Mutex::new(CacheStats::default()),
101 }
102 }
103
104 pub fn get(&self, key: &Key) -> Option<AnyArc> {
106 let mut stats = self.stats.lock().unwrap();
107
108 if let Ok(mut cache) = self.cache.write() {
110 if let Some(entry) = cache.get_mut(key) {
111 if let Some(ttl) = self.config.ttl {
113 if entry.created_at.elapsed() > ttl {
114 cache.remove(key);
115 stats.ttl_evictions += 1;
116 stats.misses += 1;
117 return None;
118 }
119 }
120
121 if self.config.track_access_count {
123 entry.access_count += 1;
124 entry.last_accessed = Instant::now();
125 }
126
127 stats.hits += 1;
128 return Some(entry.service.clone());
129 }
130 }
131
132 stats.misses += 1;
133 None
134 }
135
136 pub fn put(&self, key: Key, service: AnyArc) -> DiResult<()> {
138 if let Ok(mut cache) = self.cache.write() {
139 if cache.len() >= self.config.max_entries {
141 if self.config.enable_lru {
142 self.evict_lru(&mut cache)?;
143 } else {
144 return Err(DiError::TypeMismatch("Cache capacity exceeded"));
145 }
146 }
147
148 let entry = CacheEntry {
149 service,
150 created_at: Instant::now(),
151 access_count: 0,
152 last_accessed: Instant::now(),
153 };
154
155 cache.insert(key, entry);
156 }
157
158 Ok(())
159 }
160
161 fn evict_lru(&self, cache: &mut HashMap<Key, CacheEntry>) -> DiResult<()> {
163 if cache.is_empty() {
164 return Ok(());
165 }
166
167 let lru_key = cache
169 .iter()
170 .min_by_key(|(_, entry)| entry.last_accessed)
171 .map(|(key, _)| key.clone())
172 .ok_or(DiError::TypeMismatch("Failed to find LRU entry"))?;
173
174 cache.remove(&lru_key);
175
176 if let Ok(mut stats) = self.stats.lock() {
178 stats.lru_evictions += 1;
179 }
180
181 Ok(())
182 }
183
184 pub fn clear(&self) {
186 if let Ok(mut cache) = self.cache.write() {
187 cache.clear();
188 }
189 }
190
191 pub fn stats(&self) -> CacheStats {
193 let stats = self.stats.lock().unwrap();
194 CacheStats {
195 hits: stats.hits,
196 misses: stats.misses,
197 ttl_evictions: stats.ttl_evictions,
198 lru_evictions: stats.lru_evictions,
199 }
200 }
201
202 pub fn size(&self) -> usize {
204 self.cache.read().unwrap().len()
205 }
206}
207
208impl Default for ResolutionCache {
209 fn default() -> Self {
210 Self::new()
211 }
212}
213
214pub struct ServicePool<T> {
219 pool: Mutex<Vec<T>>,
221 factory: Box<dyn Fn() -> T + Send + Sync>,
223 max_size: usize,
225}
226
227impl<T> std::fmt::Debug for ServicePool<T>
228where
229 T: Send + 'static,
230{
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 f.debug_struct("ServicePool")
233 .field("pool_size", &self.size())
234 .field("max_size", &self.max_size)
235 .finish()
236 }
237}
238
239impl<T> ServicePool<T>
240where
241 T: Send + 'static,
242{
243 pub fn new<F>(factory: F, max_size: usize) -> Self
245 where
246 F: Fn() -> T + Send + Sync + 'static,
247 {
248 Self {
249 pool: Mutex::new(Vec::new()),
250 factory: Box::new(factory),
251 max_size,
252 }
253 }
254
255 pub fn get(&self) -> T {
257 if let Ok(mut pool) = self.pool.lock() {
258 if let Some(instance) = pool.pop() {
259 return instance;
260 }
261 }
262
263 (self.factory)()
265 }
266
267 pub fn put(&self, instance: T) {
269 if let Ok(mut pool) = self.pool.lock() {
270 if pool.len() < self.max_size {
271 pool.push(instance);
272 }
273 }
275 }
276
277 pub fn size(&self) -> usize {
279 self.pool.lock().unwrap().len()
280 }
281
282 pub fn clear(&self) {
284 if let Ok(mut pool) = self.pool.lock() {
285 pool.clear();
286 }
287 }
288}
289
290pub struct LazyService<T> {
294 value: RwLock<Option<Arc<T>>>,
296 init: Box<dyn Fn() -> DiResult<T> + Send + Sync>,
298}
299
300impl<T> std::fmt::Debug for LazyService<T>
301where
302 T: Send + Sync + 'static,
303{
304 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
305 f.debug_struct("LazyService")
306 .field("is_initialized", &self.is_initialized())
307 .finish()
308 }
309}
310
311impl<T> LazyService<T>
312where
313 T: Send + Sync + 'static,
314{
315 pub fn new<F>(init: F) -> Self
317 where
318 F: Fn() -> DiResult<T> + Send + Sync + 'static,
319 {
320 Self {
321 value: RwLock::new(None),
322 init: Box::new(init),
323 }
324 }
325
326 pub fn get(&self) -> DiResult<Arc<T>> {
328 if let Ok(value) = self.value.read() {
330 if let Some(service) = value.as_ref() {
331 return Ok(service.clone());
332 }
333 }
334
335 if let Ok(mut value) = self.value.write() {
337 if let Some(service) = value.as_ref() {
339 return Ok(service.clone());
340 }
341
342 let service = (self.init)()?;
344 let service_arc = Arc::new(service);
345 *value = Some(service_arc.clone());
346 Ok(service_arc)
347 } else {
348 Err(DiError::TypeMismatch("Failed to acquire write lock for lazy initialization"))
349 }
350 }
351
352 pub fn is_initialized(&self) -> bool {
354 if let Ok(value) = self.value.read() {
355 value.is_some()
356 } else {
357 false
358 }
359 }
360}
361
362#[derive(Debug)]
366pub struct DependencyGraphOptimizer {
367 paths: RwLock<HashMap<Key, ResolutionPath>>,
369 stats: Mutex<GraphStats>,
371}
372
373#[derive(Debug, Clone)]
374pub struct ResolutionPath {
375 pub steps: Vec<Key>,
377 pub cost: u32,
379 pub depth: usize,
381}
382
383#[derive(Debug, Default)]
384pub struct GraphStats {
385 pub paths_analyzed: u64,
387 pub paths_optimized: u64,
389 pub avg_depth: f64,
391 pub max_depth: usize,
393}
394
395impl DependencyGraphOptimizer {
396 pub fn new() -> Self {
398 Self {
399 paths: RwLock::new(HashMap::new()),
400 stats: Mutex::new(GraphStats::default()),
401 }
402 }
403
404 pub fn optimize_path(&self, root_key: &Key, dependencies: &[Key]) -> DiResult<ResolutionPath> {
406 if let Ok(paths) = self.paths.read() {
407 if let Some(cached_path) = paths.get(root_key) {
408 return Ok(cached_path.clone());
409 }
410 }
411
412 let optimized_steps = self.compute_optimal_order(dependencies)?;
414 let path = ResolutionPath {
415 cost: optimized_steps.len() as u32 * 10, depth: optimized_steps.len(),
417 steps: optimized_steps,
418 };
419
420 if let Ok(mut paths) = self.paths.write() {
422 paths.insert(root_key.clone(), path.clone());
423 }
424
425 if let Ok(mut stats) = self.stats.lock() {
427 stats.paths_analyzed += 1;
428 stats.paths_optimized += 1;
429 stats.max_depth = stats.max_depth.max(path.depth);
430
431 let total_depth = stats.avg_depth * (stats.paths_analyzed - 1) as f64 + path.depth as f64;
433 stats.avg_depth = total_depth / stats.paths_analyzed as f64;
434 }
435
436 Ok(path)
437 }
438
439 fn compute_optimal_order(&self, dependencies: &[Key]) -> DiResult<Vec<Key>> {
441 Ok(dependencies.to_vec())
444 }
445
446 pub fn stats(&self) -> GraphStats {
448 let stats = self.stats.lock().unwrap();
449 GraphStats {
450 paths_analyzed: stats.paths_analyzed,
451 paths_optimized: stats.paths_optimized,
452 avg_depth: stats.avg_depth,
453 max_depth: stats.max_depth,
454 }
455 }
456
457 pub fn clear(&self) {
459 if let Ok(mut paths) = self.paths.write() {
460 paths.clear();
461 }
462 }
463}
464
465impl Default for DependencyGraphOptimizer {
466 fn default() -> Self {
467 Self::new()
468 }
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474 use std::any::TypeId;
475 use std::thread;
476 use std::time::Duration;
477
478 #[test]
479 fn test_resolution_cache_basic_operations() {
480 let cache = ResolutionCache::new();
481 let key = Key::Type(TypeId::of::<String>(), "String");
482 let service = Arc::new("test_service".to_string()) as AnyArc;
483
484 assert!(cache.get(&key).is_none());
486
487 cache.put(key.clone(), service.clone()).unwrap();
489 let cached = cache.get(&key).unwrap();
490
491 assert!(Arc::ptr_eq(&service, &cached));
493
494 let stats = cache.stats();
496 assert_eq!(stats.hits, 1);
497 assert_eq!(stats.misses, 1);
498 assert!(stats.hit_ratio() > 0.0);
499 }
500
501 #[test]
502 fn test_resolution_cache_ttl_expiration() {
503 let config = CacheConfig {
504 max_entries: 10,
505 ttl: Some(Duration::from_millis(50)),
506 enable_lru: true,
507 track_access_count: true,
508 };
509
510 let cache = ResolutionCache::with_config(config);
511 let key = Key::Type(TypeId::of::<String>(), "String");
512 let service = Arc::new("test_service".to_string()) as AnyArc;
513
514 cache.put(key.clone(), service).unwrap();
516
517 assert!(cache.get(&key).is_some());
519
520 thread::sleep(Duration::from_millis(60));
522
523 assert!(cache.get(&key).is_none());
525
526 let stats = cache.stats();
527 assert_eq!(stats.ttl_evictions, 1);
528 }
529
530 #[test]
531 fn test_service_pool_reuse() {
532 let pool = ServicePool::new(|| "new_instance".to_string(), 5);
533
534 let instance1 = pool.get();
536 assert_eq!(instance1, "new_instance");
537
538 pool.put(instance1);
540 assert_eq!(pool.size(), 1);
541
542 let instance2 = pool.get();
544 assert_eq!(instance2, "new_instance");
545 assert_eq!(pool.size(), 0);
546 }
547
548 #[test]
549 fn test_lazy_service_initialization() {
550 let counter = Arc::new(Mutex::new(0));
551 let counter_clone = counter.clone();
552
553 let lazy = LazyService::new(move || {
554 let mut c = counter_clone.lock().unwrap();
555 *c += 1;
556 Ok(format!("initialized_{}", *c))
557 });
558
559 assert!(!lazy.is_initialized());
561
562 let service1 = lazy.get().unwrap();
564 assert!(lazy.is_initialized());
565 assert_eq!(*service1, "initialized_1");
566
567 let service2 = lazy.get().unwrap();
569 assert!(Arc::ptr_eq(&service1, &service2));
570
571 assert_eq!(*counter.lock().unwrap(), 1);
573 }
574
575 #[test]
576 fn test_dependency_graph_optimizer() {
577 let optimizer = DependencyGraphOptimizer::new();
578 let root_key = Key::Type(TypeId::of::<String>(), "Root");
579 let deps = vec![
580 Key::Type(TypeId::of::<i32>(), "Dep1"),
581 Key::Type(TypeId::of::<f64>(), "Dep2"),
582 ];
583
584 let path = optimizer.optimize_path(&root_key, &deps).unwrap();
585
586 assert_eq!(path.steps.len(), 2);
587 assert_eq!(path.depth, 2);
588 assert!(path.cost > 0);
589
590 let path2 = optimizer.optimize_path(&root_key, &deps).unwrap();
592 assert_eq!(path.steps, path2.steps);
593
594 let stats = optimizer.stats();
595 assert_eq!(stats.paths_analyzed, 1);
596 assert_eq!(stats.paths_optimized, 1);
597 }
598}