use std::{ any::{Any, TypeId}, collections::HashMap, sync::Arc, }; use crate::{ConfigurableServiceModule, CreatableServiceModule, ServiceContext, ServiceModule}; pub struct ServiceScope { service: Arc, parent: Option>, scoped_modules: HashMap>, scoped_variables: HashMap>, } pub struct ServiceScopeBuilder { service: Arc, parent: Option>, modules: HashMap>, variables: HashMap>, } impl ServiceScopeBuilder { pub fn new(service: Arc, parent: Option>) -> Self { Self { service, parent, modules: HashMap::new(), variables: HashMap::new(), } } pub fn with_variable(mut self, value: T) -> Self { self.variables.insert(TypeId::of::(), Box::new(value)); self } pub fn with_module(self) -> Self { let module = T::new(self.service.as_ref()); self.insert_module(module) } pub fn configure_module( self, config: T::Config, ) -> Self { let module = T::new(self.service.as_ref(), config); self.insert_module(module) } pub fn insert_module(mut self, module: T) -> Self { self.modules.insert(TypeId::of::(), Arc::new(module)); self } pub fn build(self) -> Arc { Arc::new(ServiceScope { service: self.service, parent: self.parent, scoped_modules: self.modules, scoped_variables: self.variables, }) } } impl ServiceScope { pub fn service(&self) -> &Arc { &self.service } pub fn child_scope(self: &Arc) -> Arc { Arc::new(Self { service: Arc::clone(&self.service), parent: Some(Arc::clone(self)), scoped_modules: HashMap::new(), scoped_variables: HashMap::new(), }) } pub fn resolve(&self) -> &T { self.scoped_modules .get(&TypeId::of::()) .map(|service| service.downcast().unwrap()) .unwrap_or_else(|| { if let Some(parent) = self.parent.as_ref() { parent.resolve() } else { self.service.resolve() } }) } pub fn fetch(&self) -> Option<&T> { self.scoped_variables .get(&TypeId::of::()) .map(|variable| variable.downcast_ref().unwrap()) .or_else(|| self.parent.as_ref().and_then(|parent| parent.fetch())) } }