1use std::any::Any;
2use std::collections::HashMap;
3use std::sync::{Arc, RwLock};
4
5use crate::container::autowiring::{DependencyResolver, Injectable};
6use crate::container::binding::{ServiceBinder, ServiceBindings};
7use crate::container::descriptor::ServiceId;
8use crate::container::lifecycle::ServiceLifecycleManager;
9use crate::container::resolver::DependencyResolver as GraphDependencyResolver;
10use crate::container::scope::{ScopeId, ScopedServiceManager, ServiceScope};
11use crate::container::tokens::{ServiceToken, TokenRegistry};
12use crate::errors::CoreError;
13
14#[derive(Debug)]
16enum ServiceInstance {
17 Singleton(Arc<dyn Any + Send + Sync>),
19 Scoped(HashMap<ScopeId, Arc<dyn Any + Send + Sync>>),
21}
22
23#[derive(Debug)]
25pub struct IocContainer {
26 bindings: ServiceBindings,
28 tokens: TokenRegistry,
30 resolver: Option<GraphDependencyResolver>,
32 instances: Arc<RwLock<HashMap<ServiceId, ServiceInstance>>>,
34 lifecycle_manager: ServiceLifecycleManager,
36 scopes: Arc<RwLock<HashMap<ScopeId, Arc<ScopedServiceManager>>>>,
38 is_built: bool,
40}
41
42impl IocContainer {
43 pub fn new() -> Self {
45 Self {
46 bindings: ServiceBindings::new(),
47 tokens: TokenRegistry::new(),
48 resolver: None,
49 instances: Arc::new(RwLock::new(HashMap::new())),
50 lifecycle_manager: ServiceLifecycleManager::new(),
51 scopes: Arc::new(RwLock::new(HashMap::new())),
52 is_built: false,
53 }
54 }
55
56 pub fn from_bindings(bindings: ServiceBindings) -> Self {
58 Self {
59 bindings,
60 tokens: TokenRegistry::new(),
61 resolver: None,
62 instances: Arc::new(RwLock::new(HashMap::new())),
63 lifecycle_manager: ServiceLifecycleManager::new(),
64 scopes: Arc::new(RwLock::new(HashMap::new())),
65 is_built: false,
66 }
67 }
68
69 pub fn build(&mut self) -> Result<(), CoreError> {
71 if self.is_built {
72 return Ok(());
73 }
74
75 let resolver = GraphDependencyResolver::new(self.bindings.descriptors())?;
77 self.resolver = Some(resolver);
78
79 let service_ids = self.bindings.service_ids().into_iter().collect();
81 if let Some(resolver) = &self.resolver {
82 resolver.validate_dependencies(&service_ids)?;
83 }
84
85 self.is_built = true;
86 Ok(())
87 }
88
89 pub async fn initialize_async(&mut self) -> Result<(), CoreError> {
91 self.lifecycle_manager.initialize_all().await
92 }
93
94 pub async fn initialize_async_with_timeout(
96 &mut self,
97 timeout: std::time::Duration,
98 ) -> Result<(), CoreError> {
99 self.lifecycle_manager
100 .initialize_all_with_timeout(timeout)
101 .await
102 }
103
104 pub fn create_scope(&self) -> Result<ScopeId, CoreError> {
106 let scope_manager = Arc::new(ScopedServiceManager::new());
107 let scope_id = scope_manager.scope_id().clone();
108
109 let mut scopes = self.scopes.write().map_err(|_| CoreError::LockError {
110 resource: "scopes".to_string(),
111 })?;
112
113 scopes.insert(scope_id.clone(), scope_manager);
114 Ok(scope_id)
115 }
116
117 pub fn create_child_scope(&self, parent_scope_id: &ScopeId) -> Result<ScopeId, CoreError> {
119 let mut scopes = self.scopes.write().map_err(|_| CoreError::LockError {
120 resource: "scopes".to_string(),
121 })?;
122
123 let parent_scope = scopes
124 .get(parent_scope_id)
125 .ok_or_else(|| CoreError::ServiceNotFound {
126 service_type: format!("parent scope {}", parent_scope_id),
127 })?
128 .clone(); let child_scope = Arc::new(ScopedServiceManager::create_child(parent_scope));
131 let child_scope_id = child_scope.scope_id().clone();
132
133 scopes.insert(child_scope_id.clone(), child_scope);
134 Ok(child_scope_id)
135 }
136
137 pub async fn dispose_scope(&self, scope_id: &ScopeId) -> Result<(), CoreError> {
139 let was_removed = {
140 let mut scopes = self.scopes.write().map_err(|_| CoreError::LockError {
141 resource: "scopes".to_string(),
142 })?;
143 scopes.remove(scope_id).is_some()
144 };
145
146 if was_removed {
147 let mut instances = self.instances.write().map_err(|_| CoreError::LockError {
149 resource: "service_instances".to_string(),
150 })?;
151
152 for (_, instance) in instances.iter_mut() {
153 if let ServiceInstance::Scoped(scoped_instances) = instance {
154 scoped_instances.remove(scope_id);
155 }
156 }
157 }
158
159 Ok(())
160 }
161
162 pub async fn dispose_all(&mut self) -> Result<(), CoreError> {
164 let scope_ids: Vec<ScopeId> = {
166 let scopes = self.scopes.read().map_err(|_| CoreError::LockError {
167 resource: "scopes".to_string(),
168 })?;
169 scopes.keys().cloned().collect()
170 };
171
172 for scope_id in scope_ids {
173 self.dispose_scope(&scope_id).await?;
174 }
175
176 self.lifecycle_manager.dispose_all().await?;
178
179 Ok(())
180 }
181
182 pub fn lifecycle_manager(&self) -> &ServiceLifecycleManager {
184 &self.lifecycle_manager
185 }
186
187 pub fn lifecycle_manager_mut(&mut self) -> &mut ServiceLifecycleManager {
189 &mut self.lifecycle_manager
190 }
191
192 pub fn resolve<T: Send + Sync + 'static>(&self) -> Result<Arc<T>, CoreError> {
194 let service_id = ServiceId::of::<T>();
195 self.resolve_by_id(&service_id)
196 }
197
198 pub fn resolve_scoped<T: Send + Sync + 'static>(
200 &self,
201 scope_id: &ScopeId,
202 ) -> Result<Arc<T>, CoreError> {
203 let service_id = ServiceId::of::<T>();
204 self.resolve_by_id_scoped(&service_id, scope_id)
205 }
206
207 pub fn resolve_named<T: Send + Sync + 'static>(&self, name: &str) -> Result<Arc<T>, CoreError> {
209 self.resolve_named_by_str::<T>(name)
210 }
211
212 fn resolve_named_by_str<T: Send + Sync + 'static>(
214 &self,
215 name: &str,
216 ) -> Result<Arc<T>, CoreError> {
217 if !self.is_built {
218 return Err(CoreError::InvalidServiceDescriptor {
219 message: "Container must be built before resolving services".to_string(),
220 });
221 }
222
223 let service_id = ServiceId::named::<T>(name.to_string());
225 {
226 let instances = self.instances.read().map_err(|_| CoreError::LockError {
227 resource: "service_instances".to_string(),
228 })?;
229
230 if let Some(ServiceInstance::Singleton(instance)) = instances.get(&service_id) {
231 return instance
232 .clone()
233 .downcast::<T>()
234 .map_err(|_| CoreError::ServiceNotFound {
235 service_type: format!("{}({})", std::any::type_name::<T>(), name),
236 });
237 }
238 }
239
240 let descriptor = self
242 .bindings
243 .get_descriptor_named::<T>(name)
244 .ok_or_else(|| CoreError::ServiceNotFound {
245 service_type: format!("{}({})", std::any::type_name::<T>(), name),
246 })?;
247
248 self.resolve_dependencies(&descriptor.dependencies)?;
250
251 let arc_instance = match &descriptor.activation_strategy {
253 crate::container::descriptor::ServiceActivationStrategy::Factory(factory) => {
254 let instance = factory()?;
255 let typed_instance =
256 instance
257 .downcast::<T>()
258 .map_err(|_| CoreError::ServiceNotFound {
259 service_type: format!("{}({})", std::any::type_name::<T>(), name),
260 })?;
261 Arc::new(*typed_instance)
262 }
263 crate::container::descriptor::ServiceActivationStrategy::AutoWired => {
264 return Err(CoreError::InvalidServiceDescriptor {
265 message: format!(
266 "Service {}({}) is marked as auto-wired but resolve_named was called instead of resolve_injectable. Use resolve_injectable() for auto-wired services.",
267 std::any::type_name::<T>(),
268 name
269 ),
270 });
271 }
272 };
273
274 if descriptor.lifetime == ServiceScope::Singleton {
276 let mut instances = self.instances.write().map_err(|_| CoreError::LockError {
277 resource: "service_instances".to_string(),
278 })?;
279 instances.insert(service_id, ServiceInstance::Singleton(arc_instance.clone()));
280 }
281
282 Ok(arc_instance)
283 }
284
285 fn resolve_by_id<T: Send + Sync + 'static>(
287 &self,
288 service_id: &ServiceId,
289 ) -> Result<Arc<T>, CoreError> {
290 if !self.is_built {
291 return Err(CoreError::InvalidServiceDescriptor {
292 message: "Container must be built before resolving services".to_string(),
293 });
294 }
295
296 {
298 let instances = self.instances.read().map_err(|_| CoreError::LockError {
299 resource: "service_instances".to_string(),
300 })?;
301
302 if let Some(ServiceInstance::Singleton(instance)) = instances.get(service_id) {
303 return instance
304 .clone()
305 .downcast::<T>()
306 .map_err(|_| CoreError::ServiceNotFound {
307 service_type: format!(
308 "{}({})",
309 std::any::type_name::<T>(),
310 service_id.name.as_deref().unwrap_or("default")
311 ),
312 });
313 }
314 }
315
316 let descriptor =
318 self.bindings
319 .get_descriptor(service_id)
320 .ok_or_else(|| CoreError::ServiceNotFound {
321 service_type: format!(
322 "{}({})",
323 std::any::type_name::<T>(),
324 service_id.name.as_deref().unwrap_or("default")
325 ),
326 })?;
327
328 self.resolve_dependencies(&descriptor.dependencies)?;
330
331 let arc_instance = match &descriptor.activation_strategy {
333 crate::container::descriptor::ServiceActivationStrategy::Factory(factory) => {
334 let instance = factory()?;
335 let typed_instance =
336 instance
337 .downcast::<T>()
338 .map_err(|_| CoreError::ServiceNotFound {
339 service_type: format!(
340 "{}({})",
341 std::any::type_name::<T>(),
342 service_id.name.as_deref().unwrap_or("default")
343 ),
344 })?;
345 Arc::new(*typed_instance)
346 }
347 crate::container::descriptor::ServiceActivationStrategy::AutoWired => {
348 return Err(CoreError::InvalidServiceDescriptor {
349 message: format!(
350 "Service {} is marked as auto-wired but resolve_by_id was called instead of resolve_injectable. Use resolve_injectable() for auto-wired services.",
351 std::any::type_name::<T>()
352 ),
353 });
354 }
355 };
356
357 if descriptor.lifetime == ServiceScope::Singleton {
359 let mut instances = self.instances.write().map_err(|_| CoreError::LockError {
360 resource: "service_instances".to_string(),
361 })?;
362 instances.insert(
363 service_id.clone(),
364 ServiceInstance::Singleton(arc_instance.clone()),
365 );
366 }
367
368 Ok(arc_instance)
369 }
370
371 fn resolve_by_id_scoped<T: Send + Sync + 'static>(
373 &self,
374 service_id: &ServiceId,
375 scope_id: &ScopeId,
376 ) -> Result<Arc<T>, CoreError> {
377 if !self.is_built {
378 return Err(CoreError::InvalidServiceDescriptor {
379 message: "Container must be built before resolving services".to_string(),
380 });
381 }
382
383 let descriptor =
385 self.bindings
386 .get_descriptor(service_id)
387 .ok_or_else(|| CoreError::ServiceNotFound {
388 service_type: format!(
389 "{}({})",
390 std::any::type_name::<T>(),
391 service_id.name.as_deref().unwrap_or("default")
392 ),
393 })?;
394
395 match descriptor.lifetime {
397 ServiceScope::Singleton => {
398 self.resolve_by_id(service_id)
400 }
401 ServiceScope::Transient => {
402 self.create_service_instance::<T>(service_id, descriptor)
404 }
405 ServiceScope::Scoped => {
406 {
408 let instances = self.instances.read().map_err(|_| CoreError::LockError {
409 resource: "service_instances".to_string(),
410 })?;
411
412 if let Some(ServiceInstance::Scoped(scoped_instances)) =
413 instances.get(service_id)
414 {
415 if let Some(instance) = scoped_instances.get(scope_id) {
416 return instance.clone().downcast::<T>().map_err(|_| {
417 CoreError::ServiceNotFound {
418 service_type: format!(
419 "{}({})",
420 std::any::type_name::<T>(),
421 service_id.name.as_deref().unwrap_or("default")
422 ),
423 }
424 });
425 }
426 }
427 }
428
429 let arc_instance = self.create_service_instance::<T>(service_id, descriptor)?;
431
432 let mut instances = self.instances.write().map_err(|_| CoreError::LockError {
434 resource: "service_instances".to_string(),
435 })?;
436
437 use std::collections::hash_map::Entry;
438 match instances.entry(service_id.clone()) {
439 Entry::Occupied(mut entry) => match entry.get_mut() {
440 ServiceInstance::Scoped(scoped_instances) => {
441 scoped_instances.insert(
442 scope_id.clone(),
443 arc_instance.clone() as Arc<dyn Any + Send + Sync>,
444 );
445 }
446 ServiceInstance::Singleton(_) => {
447 return Err(CoreError::InvalidServiceDescriptor {
448 message: format!(
449 "Service {} is registered as both Singleton and Scoped. This is a configuration error.",
450 std::any::type_name::<T>()
451 ),
452 });
453 }
454 },
455 Entry::Vacant(entry) => {
456 let mut scoped_map = HashMap::new();
457 scoped_map.insert(
458 scope_id.clone(),
459 arc_instance.clone() as Arc<dyn Any + Send + Sync>,
460 );
461 entry.insert(ServiceInstance::Scoped(scoped_map));
462 }
463 }
464
465 Ok(arc_instance)
466 }
467 }
468 }
469
470 fn create_service_instance<T: Send + Sync + 'static>(
472 &self,
473 service_id: &ServiceId,
474 descriptor: &crate::container::descriptor::ServiceDescriptor,
475 ) -> Result<Arc<T>, CoreError> {
476 self.resolve_dependencies(&descriptor.dependencies)?;
478
479 match &descriptor.activation_strategy {
481 crate::container::descriptor::ServiceActivationStrategy::Factory(factory) => {
482 let instance = factory()?;
483 let typed_instance = instance.downcast::<T>()
484 .map_err(|_| CoreError::ServiceNotFound {
485 service_type: format!("{}({})",
486 std::any::type_name::<T>(),
487 service_id.name.as_deref().unwrap_or("default")
488 ),
489 })?;
490 Ok(Arc::new(*typed_instance))
491 },
492 crate::container::descriptor::ServiceActivationStrategy::AutoWired => {
493 Err(CoreError::InvalidServiceDescriptor {
494 message: format!(
495 "Service {} is marked as auto-wired but create_service_instance was called. Use resolve_injectable() for auto-wired services.",
496 std::any::type_name::<T>()
497 ),
498 })
499 }
500 }
501 }
502
503 fn resolve_dependencies(&self, dependencies: &[ServiceId]) -> Result<(), CoreError> {
505 for dep_id in dependencies {
506 if !self.bindings.contains(dep_id) {
508 return Err(CoreError::ServiceNotFound {
509 service_type: format!(
510 "{}({})",
511 dep_id.type_name(),
512 dep_id.name.as_deref().unwrap_or("default")
513 ),
514 });
515 }
516 }
517 Ok(())
518 }
519
520 pub fn try_resolve<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
522 self.resolve::<T>().ok()
523 }
524
525 pub fn try_resolve_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
527 self.resolve_named::<T>(name).ok()
528 }
529
530 pub fn resolve_injectable<T: Injectable>(&self) -> Result<Arc<T>, CoreError> {
532 if !self.is_built {
533 return Err(CoreError::InvalidServiceDescriptor {
534 message: "Container must be built before resolving services".to_string(),
535 });
536 }
537
538 let service_id = ServiceId::of::<T>();
539
540 {
542 let instances = self.instances.read().map_err(|_| CoreError::LockError {
543 resource: "service_instances".to_string(),
544 })?;
545
546 if let Some(ServiceInstance::Singleton(instance)) = instances.get(&service_id) {
547 return instance
548 .clone()
549 .downcast::<T>()
550 .map_err(|_| CoreError::ServiceNotFound {
551 service_type: std::any::type_name::<T>().to_string(),
552 });
553 }
554 }
555
556 let descriptor = self.bindings.get_descriptor(&service_id).ok_or_else(|| {
558 CoreError::ServiceNotFound {
559 service_type: std::any::type_name::<T>().to_string(),
560 }
561 })?;
562
563 let arc_instance = match &descriptor.activation_strategy {
564 crate::container::descriptor::ServiceActivationStrategy::AutoWired => {
565 let service_instance = T::create(self)?;
567 Arc::new(service_instance)
568 }
569 crate::container::descriptor::ServiceActivationStrategy::Factory(_) => {
570 return Err(CoreError::InvalidServiceDescriptor {
571 message: format!(
572 "Service {} is configured with a factory but resolve_injectable was called. Use resolve() for factory-based services.",
573 std::any::type_name::<T>()
574 ),
575 });
576 }
577 };
578
579 if descriptor.lifetime == ServiceScope::Singleton {
581 let mut instances = self.instances.write().map_err(|_| CoreError::LockError {
582 resource: "service_instances".to_string(),
583 })?;
584 instances.insert(service_id, ServiceInstance::Singleton(arc_instance.clone()));
585 }
586
587 Ok(arc_instance)
588 }
589
590 pub fn resolve_trait<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, CoreError> {
592 Err(CoreError::ServiceNotFound {
596 service_type: std::any::type_name::<T>().to_string(),
597 })
598 }
599
600 pub fn bind_token<Token, Impl>(&mut self) -> Result<&mut Self, CoreError>
627 where
628 Token: ServiceToken,
629 Impl: Send + Sync + Default + 'static,
630 {
631 self.bind_token_with_lifetime::<Token, Impl>(ServiceScope::Transient)
632 }
633
634 pub fn bind_token_singleton<Token, Impl>(&mut self) -> Result<&mut Self, CoreError>
636 where
637 Token: ServiceToken,
638 Impl: Send + Sync + Default + 'static,
639 {
640 self.bind_token_with_lifetime::<Token, Impl>(ServiceScope::Singleton)
641 }
642
643 pub fn bind_token_scoped<Token, Impl>(&mut self) -> Result<&mut Self, CoreError>
645 where
646 Token: ServiceToken,
647 Impl: Send + Sync + Default + 'static,
648 {
649 self.bind_token_with_lifetime::<Token, Impl>(ServiceScope::Scoped)
650 }
651
652 pub fn bind_token_with_lifetime<Token, Impl>(
654 &mut self,
655 lifetime: ServiceScope,
656 ) -> Result<&mut Self, CoreError>
657 where
658 Token: ServiceToken,
659 Impl: Send + Sync + Default + 'static,
660 {
661 if self.is_built {
662 return Err(CoreError::InvalidServiceDescriptor {
663 message: "Cannot bind tokens after container is built".to_string(),
664 });
665 }
666
667 self.tokens
669 .register::<Token, Impl>()
670 .map_err(|e| CoreError::InvalidServiceDescriptor {
671 message: format!("Failed to register token binding: {}", e),
672 })?;
673
674 let token_binding = self.tokens.get_default::<Token>().ok_or_else(|| {
676 CoreError::InvalidServiceDescriptor {
677 message: "Failed to retrieve token binding after registration".to_string(),
678 }
679 })?;
680
681 let service_id = token_binding.to_service_id();
683
684 let descriptor = crate::container::descriptor::ServiceDescriptor {
686 service_id,
687 implementation_id: std::any::TypeId::of::<Impl>(),
688 lifetime,
689 activation_strategy: crate::container::descriptor::ServiceActivationStrategy::Factory(
690 Box::new(|| Ok(Box::new(Impl::default()) as Box<dyn Any + Send + Sync>)),
691 ),
692 dependencies: Vec::new(),
693 };
694
695 self.bindings.add_descriptor(descriptor);
696
697 Ok(self)
698 }
699
700 pub fn bind_token_named<Token, Impl>(
702 &mut self,
703 name: impl Into<String>,
704 ) -> Result<&mut Self, CoreError>
705 where
706 Token: ServiceToken,
707 Impl: Send + Sync + Default + 'static,
708 {
709 if self.is_built {
710 return Err(CoreError::InvalidServiceDescriptor {
711 message: "Cannot bind tokens after container is built".to_string(),
712 });
713 }
714
715 let name = name.into();
716
717 self.tokens
719 .register_named::<Token, Impl>(&name)
720 .map_err(|e| CoreError::InvalidServiceDescriptor {
721 message: format!("Failed to register named token binding: {}", e),
722 })?;
723
724 let token_binding = self.tokens.get_named::<Token>(&name).ok_or_else(|| {
726 CoreError::InvalidServiceDescriptor {
727 message: "Failed to retrieve named token binding after registration".to_string(),
728 }
729 })?;
730
731 let service_id = token_binding.to_service_id();
733
734 let descriptor = crate::container::descriptor::ServiceDescriptor {
736 service_id,
737 implementation_id: std::any::TypeId::of::<Impl>(),
738 lifetime: ServiceScope::Transient,
739 activation_strategy: crate::container::descriptor::ServiceActivationStrategy::Factory(
740 Box::new(|| Ok(Box::new(Impl::default()) as Box<dyn Any + Send + Sync>)),
741 ),
742 dependencies: Vec::new(),
743 };
744
745 self.bindings.add_descriptor(descriptor);
746
747 Ok(self)
748 }
749
750 pub fn resolve_by_token<Token>(&self) -> Result<Arc<Token::Service>, CoreError>
790 where
791 Token: ServiceToken,
792 Token::Service: 'static,
793 {
794 if !self.is_built {
795 return Err(CoreError::InvalidServiceDescriptor {
796 message: "Container must be built before resolving services".to_string(),
797 });
798 }
799
800 let token_binding =
802 self.tokens
803 .get_default::<Token>()
804 .ok_or_else(|| CoreError::ServiceNotFound {
805 service_type: format!(
806 "token {} -> {}",
807 Token::token_type_name(),
808 Token::service_type_name()
809 ),
810 })?;
811
812 let service_id = token_binding.to_service_id();
814
815 self.resolve_by_id_as_trait::<Token::Service>(&service_id)
818 }
819
820 pub fn resolve_by_token_named<Token>(
822 &self,
823 name: &str,
824 ) -> Result<Arc<Token::Service>, CoreError>
825 where
826 Token: ServiceToken,
827 Token::Service: 'static,
828 {
829 if !self.is_built {
830 return Err(CoreError::InvalidServiceDescriptor {
831 message: "Container must be built before resolving services".to_string(),
832 });
833 }
834
835 let token_binding =
837 self.tokens
838 .get_named::<Token>(name)
839 .ok_or_else(|| CoreError::ServiceNotFound {
840 service_type: format!(
841 "named token {}({}) -> {}",
842 Token::token_type_name(),
843 name,
844 Token::service_type_name()
845 ),
846 })?;
847
848 let service_id = token_binding.to_service_id();
850
851 self.resolve_by_id_as_trait::<Token::Service>(&service_id)
853 }
854
855 pub fn try_resolve_by_token<Token>(&self) -> Option<Arc<Token::Service>>
857 where
858 Token: ServiceToken,
859 Token::Service: 'static,
860 {
861 self.resolve_by_token::<Token>().ok()
862 }
863
864 pub fn try_resolve_by_token_named<Token>(&self, name: &str) -> Option<Arc<Token::Service>>
866 where
867 Token: ServiceToken,
868 Token::Service: 'static,
869 {
870 self.resolve_by_token_named::<Token>(name).ok()
871 }
872
873 pub fn resolve_by_token_scoped<Token>(
878 &self,
879 scope_id: &ScopeId,
880 ) -> Result<Arc<Token::Service>, CoreError>
881 where
882 Token: ServiceToken,
883 Token::Service: 'static,
884 {
885 if !self.is_built {
886 return Err(CoreError::InvalidServiceDescriptor {
887 message: "Container must be built before resolving services".to_string(),
888 });
889 }
890
891 let token_binding =
893 self.tokens
894 .get_default::<Token>()
895 .ok_or_else(|| CoreError::ServiceNotFound {
896 service_type: format!(
897 "token {} -> {}",
898 Token::token_type_name(),
899 Token::service_type_name()
900 ),
901 })?;
902
903 let service_id = token_binding.to_service_id();
905
906 self.resolve_by_id_as_trait_scoped::<Token::Service>(&service_id, scope_id)
908 }
909
910 pub fn resolve_by_token_named_scoped<Token>(
912 &self,
913 name: &str,
914 scope_id: &ScopeId,
915 ) -> Result<Arc<Token::Service>, CoreError>
916 where
917 Token: ServiceToken,
918 Token::Service: 'static,
919 {
920 if !self.is_built {
921 return Err(CoreError::InvalidServiceDescriptor {
922 message: "Container must be built before resolving services".to_string(),
923 });
924 }
925
926 let token_binding =
928 self.tokens
929 .get_named::<Token>(name)
930 .ok_or_else(|| CoreError::ServiceNotFound {
931 service_type: format!(
932 "named token {}({}) -> {}",
933 Token::token_type_name(),
934 name,
935 Token::service_type_name()
936 ),
937 })?;
938
939 let service_id = token_binding.to_service_id();
941
942 self.resolve_by_id_as_trait_scoped::<Token::Service>(&service_id, scope_id)
944 }
945
946 pub fn try_resolve_by_token_scoped<Token>(
948 &self,
949 scope_id: &ScopeId,
950 ) -> Option<Arc<Token::Service>>
951 where
952 Token: ServiceToken,
953 Token::Service: 'static,
954 {
955 self.resolve_by_token_scoped::<Token>(scope_id).ok()
956 }
957
958 pub fn try_resolve_by_token_named_scoped<Token>(
960 &self,
961 name: &str,
962 scope_id: &ScopeId,
963 ) -> Option<Arc<Token::Service>>
964 where
965 Token: ServiceToken,
966 Token::Service: 'static,
967 {
968 self.resolve_by_token_named_scoped::<Token>(name, scope_id)
969 .ok()
970 }
971
972 pub fn contains_token<Token: ServiceToken>(&self) -> bool {
974 self.tokens.contains::<Token>()
975 }
976
977 pub fn contains_token_named<Token: ServiceToken>(&self, name: &str) -> bool {
979 self.tokens.contains_named::<Token>(name)
980 }
981
982 pub fn token_stats(&self) -> crate::container::tokens::TokenRegistryStats {
984 self.tokens.stats()
985 }
986
987 fn resolve_by_id_as_trait<T: ?Sized + Send + Sync + 'static>(
991 &self,
992 service_id: &ServiceId,
993 ) -> Result<Arc<T>, CoreError> {
994 Err(CoreError::ServiceNotFound {
1001 service_type: format!(
1002 "trait object resolution not yet fully implemented for service {}",
1003 service_id.type_name()
1004 ),
1005 })
1006 }
1007
1008 fn resolve_by_id_as_trait_scoped<T: ?Sized + Send + Sync + 'static>(
1012 &self,
1013 service_id: &ServiceId,
1014 _scope_id: &ScopeId,
1015 ) -> Result<Arc<T>, CoreError> {
1016 Err(CoreError::ServiceNotFound {
1024 service_type: format!(
1025 "scoped trait object resolution not yet fully implemented for service {}",
1026 service_id.type_name()
1027 ),
1028 })
1029 }
1030
1031 pub fn contains<T: 'static>(&self) -> bool {
1033 let service_id = ServiceId::of::<T>();
1034 self.bindings.contains(&service_id)
1035 }
1036
1037 pub fn contains_named<T: 'static>(&self, name: &str) -> bool {
1039 self.bindings.contains_named::<T>(name)
1040 }
1041
1042 pub fn service_count(&self) -> usize {
1044 self.bindings.count()
1045 }
1046
1047 pub fn registered_services(&self) -> Vec<ServiceId> {
1049 self.bindings.service_ids()
1050 }
1051
1052 pub fn is_built(&self) -> bool {
1054 self.is_built
1055 }
1056
1057 pub fn validate(&self) -> Result<(), CoreError> {
1059 if !self.is_built {
1060 return Err(CoreError::InvalidServiceDescriptor {
1061 message: "Container must be built before validation".to_string(),
1062 });
1063 }
1064
1065 if let Some(resolver) = &self.resolver {
1067 let service_ids = self.bindings.service_ids().into_iter().collect();
1068 resolver.validate_dependencies(&service_ids)?;
1069 }
1070
1071 Ok(())
1072 }
1073
1074 pub fn resolve_all<T: Send + Sync + 'static>(&self) -> Result<Vec<Arc<T>>, CoreError> {
1076 if !self.is_built {
1077 return Err(CoreError::InvalidServiceDescriptor {
1078 message: "Container must be built before resolving services".to_string(),
1079 });
1080 }
1081
1082 let mut implementations = Vec::new();
1083
1084 for descriptor in self.bindings.descriptors() {
1086 if descriptor.service_id.type_id == std::any::TypeId::of::<T>() {
1087 match self.resolve_by_id::<T>(&descriptor.service_id) {
1088 Ok(instance) => implementations.push(instance),
1089 Err(_) => continue, }
1091 }
1092 }
1093
1094 if implementations.is_empty() {
1095 return Err(CoreError::ServiceNotFound {
1096 service_type: std::any::type_name::<T>().to_string(),
1097 });
1098 }
1099
1100 Ok(implementations)
1101 }
1102
1103 pub fn resolve_all_named<T: Send + Sync + 'static>(
1105 &self,
1106 ) -> Result<std::collections::HashMap<String, Arc<T>>, CoreError> {
1107 if !self.is_built {
1108 return Err(CoreError::InvalidServiceDescriptor {
1109 message: "Container must be built before resolving services".to_string(),
1110 });
1111 }
1112
1113 let mut implementations = std::collections::HashMap::new();
1114
1115 for descriptor in self.bindings.descriptors() {
1117 if descriptor.service_id.type_id == std::any::TypeId::of::<T>() {
1118 if let Some(name) = &descriptor.service_id.name {
1119 match self.resolve_by_id::<T>(&descriptor.service_id) {
1120 Ok(instance) => {
1121 implementations.insert(name.clone(), instance);
1122 }
1123 Err(_) => continue, }
1125 }
1126 }
1127 }
1128
1129 if implementations.is_empty() {
1130 return Err(CoreError::ServiceNotFound {
1131 service_type: format!("named implementations of {}", std::any::type_name::<T>()),
1132 });
1133 }
1134
1135 Ok(implementations)
1136 }
1137
1138 pub fn resolve_default<T: Send + Sync + 'static>(&self) -> Result<Arc<T>, CoreError> {
1140 self.resolve::<T>()
1143 }
1144
1145 pub fn get_service_info<T: 'static>(&self) -> Option<String> {
1147 let service_id = ServiceId::of::<T>();
1148 self.bindings
1149 .get_descriptor(&service_id)
1150 .map(|desc| format!("{:?}", desc))
1151 }
1152
1153 pub fn get_registered_services(&self) -> Vec<String> {
1155 self.bindings
1156 .service_ids()
1157 .into_iter()
1158 .map(|id| {
1159 format!(
1160 "{} ({})",
1161 id.type_name(),
1162 id.name.unwrap_or_else(|| "default".to_string())
1163 )
1164 })
1165 .collect()
1166 }
1167
1168 pub fn validate_all_services(&self) -> Result<(), Vec<CoreError>> {
1170 if !self.is_built {
1171 return Err(vec![CoreError::InvalidServiceDescriptor {
1172 message: "Container must be built before validation".to_string(),
1173 }]);
1174 }
1175
1176 let mut errors = Vec::new();
1177
1178 for descriptor in self.bindings.descriptors() {
1179 for dependency in &descriptor.dependencies {
1181 if !self.bindings.contains(dependency) {
1182 errors.push(CoreError::ServiceNotFound {
1183 service_type: format!(
1184 "{} (dependency of {})",
1185 dependency.type_name(),
1186 descriptor.service_id.type_name()
1187 ),
1188 });
1189 }
1190 }
1191 }
1192
1193 if errors.is_empty() {
1194 Ok(())
1195 } else {
1196 Err(errors)
1197 }
1198 }
1199
1200 pub fn get_statistics(&self) -> ServiceStatistics {
1202 let mut stats = ServiceStatistics::default();
1203
1204 stats.total_services = self.bindings.count();
1205 stats.singleton_services = 0;
1206 stats.transient_services = 0;
1207 stats.scoped_services = 0;
1208 stats.cached_instances = 0;
1209
1210 for descriptor in self.bindings.descriptors() {
1211 match descriptor.lifetime {
1212 crate::container::scope::ServiceScope::Singleton => stats.singleton_services += 1,
1213 crate::container::scope::ServiceScope::Transient => stats.transient_services += 1,
1214 crate::container::scope::ServiceScope::Scoped => stats.scoped_services += 1,
1215 }
1216 }
1217
1218 if let Ok(instances) = self.instances.read() {
1219 stats.cached_instances = instances.len();
1220 }
1221
1222 stats
1223 }
1224}
1225
1226#[derive(Debug, Default)]
1228pub struct ServiceStatistics {
1229 pub total_services: usize,
1230 pub singleton_services: usize,
1231 pub transient_services: usize,
1232 pub scoped_services: usize,
1233 pub cached_instances: usize,
1234}
1235
1236impl ServiceBinder for IocContainer {
1237 fn add_service_descriptor(
1238 &mut self,
1239 descriptor: crate::container::descriptor::ServiceDescriptor,
1240 ) -> Result<&mut Self, CoreError> {
1241 if self.is_built {
1242 return Err(CoreError::InvalidServiceDescriptor {
1243 message: "Cannot add service descriptors after container is built".to_string(),
1244 });
1245 }
1246 self.bindings.add_descriptor(descriptor);
1247 Ok(self)
1248 }
1249
1250 fn bind<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
1251 &mut self,
1252 ) -> &mut Self {
1253 if self.is_built {
1254 panic!("Cannot add bindings after container is built");
1255 }
1256 self.bindings.bind::<TInterface, TImpl>();
1257 self
1258 }
1259
1260 fn bind_singleton<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
1261 &mut self,
1262 ) -> &mut Self {
1263 if self.is_built {
1264 panic!("Cannot add bindings after container is built");
1265 }
1266 self.bindings.bind_singleton::<TInterface, TImpl>();
1267 self
1268 }
1269
1270 fn bind_transient<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
1271 &mut self,
1272 ) -> &mut Self {
1273 if self.is_built {
1274 panic!("Cannot add bindings after container is built");
1275 }
1276 self.bindings.bind_transient::<TInterface, TImpl>();
1277 self
1278 }
1279
1280 fn bind_factory<TInterface: ?Sized + 'static, F, T>(&mut self, factory: F) -> &mut Self
1281 where
1282 F: Fn() -> Result<T, CoreError> + Send + Sync + 'static,
1283 T: Send + Sync + 'static,
1284 {
1285 if self.is_built {
1286 panic!("Cannot add bindings after container is built");
1287 }
1288 self.bindings.bind_factory::<TInterface, _, _>(factory);
1289 self
1290 }
1291
1292 fn bind_instance<TInterface: ?Sized + 'static, TImpl: Send + Sync + Clone + 'static>(
1293 &mut self,
1294 instance: TImpl,
1295 ) -> &mut Self {
1296 if self.is_built {
1297 panic!("Cannot add bindings after container is built");
1298 }
1299 self.bindings.bind_instance::<TInterface, TImpl>(instance);
1300 self
1301 }
1302
1303 fn bind_named<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
1304 &mut self,
1305 name: &str,
1306 ) -> &mut Self {
1307 if self.is_built {
1308 panic!("Cannot add bindings after container is built");
1309 }
1310 self.bindings.bind_named::<TInterface, TImpl>(name);
1311 self
1312 }
1313
1314 fn bind_injectable<T: Injectable>(&mut self) -> &mut Self {
1315 if self.is_built {
1316 panic!("Cannot add bindings after container is built");
1317 }
1318 self.bindings.bind_injectable::<T>();
1319 self
1320 }
1321
1322 fn bind_injectable_singleton<T: Injectable>(&mut self) -> &mut Self {
1323 if self.is_built {
1324 panic!("Cannot add bindings after container is built");
1325 }
1326 self.bindings.bind_injectable_singleton::<T>();
1327 self
1328 }
1329
1330 fn bind_with<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
1333 &mut self,
1334 ) -> crate::container::binding::AdvancedBindingBuilder<TInterface> {
1335 if self.is_built {
1336 panic!("Cannot add bindings after container is built");
1337 }
1338 self.bindings.bind_with::<TInterface, TImpl>()
1339 }
1340
1341 fn with_implementation<TInterface: ?Sized + 'static, TImpl: Send + Sync + Default + 'static>(
1342 &mut self,
1343 config: crate::container::binding::BindingConfig,
1344 ) -> &mut Self {
1345 if self.is_built {
1346 panic!("Cannot add bindings after container is built");
1347 }
1348 self.bindings
1349 .with_implementation::<TInterface, TImpl>(config);
1350 self
1351 }
1352
1353 fn bind_lazy<TInterface: ?Sized + 'static, F, T>(&mut self, factory: F) -> &mut Self
1354 where
1355 F: Fn() -> T + Send + Sync + 'static,
1356 T: Send + Sync + 'static,
1357 {
1358 if self.is_built {
1359 panic!("Cannot add bindings after container is built");
1360 }
1361 self.bindings.bind_lazy::<TInterface, F, T>(factory);
1362 self
1363 }
1364
1365 fn bind_parameterized_factory<TInterface: ?Sized + 'static, P, F, T>(
1366 &mut self,
1367 factory: F,
1368 ) -> &mut Self
1369 where
1370 F: Fn(P) -> Result<T, CoreError> + Send + Sync + 'static,
1371 T: Send + Sync + 'static,
1372 P: Send + Sync + 'static,
1373 {
1374 if self.is_built {
1375 panic!("Cannot add bindings after container is built");
1376 }
1377 self.bindings
1378 .bind_parameterized_factory::<TInterface, P, F, T>(factory);
1379 self
1380 }
1381
1382 fn bind_collection<TInterface: ?Sized + 'static, F>(&mut self, configure: F) -> &mut Self
1383 where
1384 F: FnOnce(&mut crate::container::binding::CollectionBindingBuilder<TInterface>),
1385 {
1386 if self.is_built {
1387 panic!("Cannot add bindings after container is built");
1388 }
1389 self.bindings.bind_collection::<TInterface, F>(configure);
1390 self
1391 }
1392}
1393
1394impl Default for IocContainer {
1395 fn default() -> Self {
1396 Self::new()
1397 }
1398}
1399
1400impl DependencyResolver for IocContainer {
1401 fn resolve<T: Send + Sync + 'static>(&self) -> Result<Arc<T>, CoreError> {
1402 self.resolve::<T>()
1403 }
1404
1405 fn resolve_named<T: Send + Sync + 'static>(&self, name: &str) -> Result<Arc<T>, CoreError> {
1406 self.resolve_named::<T>(name)
1407 }
1408
1409 fn try_resolve<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
1410 self.try_resolve::<T>()
1411 }
1412
1413 fn try_resolve_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
1414 self.try_resolve_named::<T>(name)
1415 }
1416}
1417
1418#[cfg(test)]
1419mod tests {
1420 use super::*;
1421
1422 trait TestRepository: Send + Sync {
1423 fn find(&self, id: u32) -> Option<String>;
1424 }
1425
1426 #[derive(Default)]
1427 struct PostgresRepository;
1428
1429 unsafe impl Send for PostgresRepository {}
1430 unsafe impl Sync for PostgresRepository {}
1431
1432 impl TestRepository for PostgresRepository {
1433 fn find(&self, _id: u32) -> Option<String> {
1434 Some("postgres_data".to_string())
1435 }
1436 }
1437
1438 trait TestService: Send + Sync {
1439 fn get_data(&self) -> String;
1440 }
1441
1442 #[derive(Default)]
1443 struct UserService;
1444
1445 unsafe impl Send for UserService {}
1446 unsafe impl Sync for UserService {}
1447
1448 impl TestService for UserService {
1449 fn get_data(&self) -> String {
1450 "user_data".to_string()
1451 }
1452 }
1453
1454 #[test]
1455 fn test_basic_binding_and_resolution() {
1456 let mut container = IocContainer::new();
1457
1458 container
1459 .bind::<PostgresRepository, PostgresRepository>()
1460 .bind_singleton::<UserService, UserService>();
1461
1462 container.build().unwrap();
1463
1464 let repo = container.resolve::<PostgresRepository>().unwrap();
1465 assert_eq!(repo.find(1), Some("postgres_data".to_string()));
1466
1467 let service = container.resolve::<UserService>().unwrap();
1468 assert_eq!(service.get_data(), "user_data");
1469 }
1470
1471 #[test]
1472 fn test_named_services() {
1473 let mut container = IocContainer::new();
1474
1475 container
1476 .bind_named::<PostgresRepository, PostgresRepository>("postgres")
1477 .bind_named::<PostgresRepository, PostgresRepository>("backup");
1478
1479 container.build().unwrap();
1480
1481 let postgres_repo = container
1482 .resolve_named::<PostgresRepository>("postgres")
1483 .unwrap();
1484 let backup_repo = container
1485 .resolve_named::<PostgresRepository>("backup")
1486 .unwrap();
1487
1488 assert_eq!(postgres_repo.find(1), Some("postgres_data".to_string()));
1489 assert_eq!(backup_repo.find(1), Some("postgres_data".to_string()));
1490 }
1491
1492 #[test]
1493 fn test_singleton_behavior() {
1494 let mut container = IocContainer::new();
1495
1496 container.bind_singleton::<UserService, UserService>();
1497 container.build().unwrap();
1498
1499 let service1 = container.resolve::<UserService>().unwrap();
1500 let service2 = container.resolve::<UserService>().unwrap();
1501
1502 assert!(Arc::ptr_eq(&service1, &service2));
1504 }
1505
1506 #[test]
1507 fn test_transient_behavior() {
1508 let mut container = IocContainer::new();
1509
1510 container.bind_transient::<UserService, UserService>();
1511 container.build().unwrap();
1512
1513 let service1 = container.resolve::<UserService>().unwrap();
1514 let service2 = container.resolve::<UserService>().unwrap();
1515
1516 assert!(!Arc::ptr_eq(&service1, &service2));
1518 }
1519
1520 #[test]
1521 #[should_panic(expected = "Cannot add bindings after container is built")]
1522 fn test_cannot_bind_after_build() {
1523 let mut container = IocContainer::new();
1524 container.build().unwrap();
1525
1526 container.bind::<UserService, UserService>();
1528 }
1529
1530 #[test]
1531 fn test_service_not_found() {
1532 let mut container = IocContainer::new();
1533 container.build().unwrap();
1534
1535 let result = container.resolve::<UserService>();
1536 assert!(result.is_err());
1537
1538 if let Err(CoreError::ServiceNotFound { service_type }) = result {
1539 assert!(service_type.contains("UserService"));
1540 }
1541 }
1542}