#![allow(dead_code)]
use crate::utils::error::gateway_error::{GatewayError, Result};
use parking_lot::RwLock;
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;
pub trait Injectable: Send + Sync + 'static {
fn type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
}
impl<T> Injectable for T where T: Send + Sync + 'static {}
#[derive(Default)]
pub struct ServiceContainer {
services: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
singletons: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
}
impl ServiceContainer {
pub fn new() -> Self {
Self::default()
}
pub fn register<T>(&self, service: T) -> Result<()>
where
T: Injectable,
{
let type_id = TypeId::of::<T>();
let service = Arc::new(service);
let mut services = self.services.write();
if services.contains_key(&type_id) {
return Err(GatewayError::Config(format!(
"Service {} is already registered",
std::any::type_name::<T>()
)));
}
services.insert(type_id, service);
Ok(())
}
pub fn register_singleton<T>(&self, service: T) -> Result<()>
where
T: Injectable,
{
let type_id = TypeId::of::<T>();
let service = Arc::new(service);
let mut singletons = self.singletons.write();
if singletons.contains_key(&type_id) {
return Err(GatewayError::Config(format!(
"Singleton {} is already registered",
std::any::type_name::<T>()
)));
}
singletons.insert(type_id, service);
Ok(())
}
pub fn register_factory<T, F>(&self, factory: F) -> Result<()>
where
T: Injectable,
F: Fn() -> T + Send + Sync + 'static,
{
let service = factory();
self.register(service)
}
pub fn get<T>(&self) -> Result<Arc<T>>
where
T: Injectable,
{
let type_id = TypeId::of::<T>();
{
let singletons = self.singletons.read();
if let Some(service) = singletons.get(&type_id) {
return service.clone().downcast::<T>().map_err(|_| {
GatewayError::Internal(format!(
"Failed to downcast singleton service {}",
std::any::type_name::<T>()
))
});
}
}
{
let services = self.services.read();
if let Some(service) = services.get(&type_id) {
return service.clone().downcast::<T>().map_err(|_| {
GatewayError::Internal(format!(
"Failed to downcast service {}",
std::any::type_name::<T>()
))
});
}
}
Err(GatewayError::Config(format!(
"Service {} is not registered",
std::any::type_name::<T>()
)))
}
pub fn try_get<T>(&self) -> Option<Arc<T>>
where
T: Injectable,
{
self.get().ok()
}
pub fn contains<T>(&self) -> bool
where
T: Injectable,
{
let type_id = TypeId::of::<T>();
let singletons = self.singletons.read();
let services = self.services.read();
singletons.contains_key(&type_id) || services.contains_key(&type_id)
}
pub fn remove<T>(&self) -> Result<()>
where
T: Injectable,
{
let type_id = TypeId::of::<T>();
{
let mut singletons = self.singletons.write();
if singletons.remove(&type_id).is_some() {
return Ok(());
}
}
{
let mut services = self.services.write();
if services.remove(&type_id).is_some() {
return Ok(());
}
}
Err(GatewayError::Config(format!(
"Service {} is not registered",
std::any::type_name::<T>()
)))
}
pub fn clear(&self) {
self.services.write().clear();
self.singletons.write().clear();
}
pub fn service_count(&self) -> usize {
let services = self.services.read();
let singletons = self.singletons.read();
services.len() + singletons.len()
}
}
pub struct ServiceBuilder {
container: ServiceContainer,
}
impl ServiceBuilder {
pub fn new() -> Self {
Self {
container: ServiceContainer::new(),
}
}
pub fn add_service<T>(self, service: T) -> Result<Self>
where
T: Injectable,
{
self.container.register(service)?;
Ok(self)
}
pub fn add_singleton<T>(self, service: T) -> Result<Self>
where
T: Injectable,
{
self.container.register_singleton(service)?;
Ok(self)
}
pub fn add_factory<T, F>(self, factory: F) -> Result<Self>
where
T: Injectable,
F: Fn() -> T + Send + Sync + 'static,
{
self.container.register_factory(factory)?;
Ok(self)
}
pub fn build(self) -> ServiceContainer {
self.container
}
}
impl Default for ServiceBuilder {
fn default() -> Self {
Self::new()
}
}
pub trait WithDependencies {
fn with_dependencies(self, container: &ServiceContainer) -> Result<Self>
where
Self: Sized;
}
use std::sync::LazyLock;
static GLOBAL_CONTAINER: LazyLock<ServiceContainer> = LazyLock::new(ServiceContainer::new);
pub fn global_container() -> &'static ServiceContainer {
&GLOBAL_CONTAINER
}
pub fn register_global<T>(service: T) -> Result<()>
where
T: Injectable,
{
global_container().register(service)
}
pub fn register_global_singleton<T>(service: T) -> Result<()>
where
T: Injectable,
{
global_container().register_singleton(service)
}
pub fn get_global<T>() -> Result<Arc<T>>
where
T: Injectable,
{
global_container().get()
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq)]
struct TestService {
value: String,
}
#[derive(Debug, Clone, PartialEq)]
struct AnotherService {
number: i32,
}
#[derive(Debug, Clone)]
struct CounterService {
count: Arc<RwLock<i32>>,
}
impl CounterService {
fn new() -> Self {
Self {
count: Arc::new(RwLock::new(0)),
}
}
fn increment(&self) {
*self.count.write() += 1;
}
fn get_count(&self) -> i32 {
*self.count.read()
}
}
#[test]
fn test_injectable_type_name() {
let service = TestService {
value: "test".to_string(),
};
let type_name = service.type_name();
assert!(type_name.contains("TestService"));
}
#[test]
fn test_container_new() {
let container = ServiceContainer::new();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_container_default() {
let container = ServiceContainer::default();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_register_service() {
let container = ServiceContainer::new();
let service = TestService {
value: "test".to_string(),
};
let result = container.register(service);
assert!(result.is_ok());
assert_eq!(container.service_count(), 1);
}
#[test]
fn test_register_duplicate_service_fails() {
let container = ServiceContainer::new();
let service1 = TestService {
value: "test1".to_string(),
};
let service2 = TestService {
value: "test2".to_string(),
};
container.register(service1).unwrap();
let result = container.register(service2);
assert!(result.is_err());
if let Err(GatewayError::Config(msg)) = result {
assert!(msg.contains("already registered"));
} else {
panic!("Expected Config error");
}
}
#[test]
fn test_register_different_services() {
let container = ServiceContainer::new();
let service1 = TestService {
value: "test".to_string(),
};
let service2 = AnotherService { number: 42 };
container.register(service1).unwrap();
container.register(service2).unwrap();
assert_eq!(container.service_count(), 2);
}
#[test]
fn test_register_singleton() {
let container = ServiceContainer::new();
let service = TestService {
value: "singleton".to_string(),
};
let result = container.register_singleton(service);
assert!(result.is_ok());
assert_eq!(container.service_count(), 1);
}
#[test]
fn test_register_duplicate_singleton_fails() {
let container = ServiceContainer::new();
let service1 = TestService {
value: "singleton1".to_string(),
};
let service2 = TestService {
value: "singleton2".to_string(),
};
container.register_singleton(service1).unwrap();
let result = container.register_singleton(service2);
assert!(result.is_err());
if let Err(GatewayError::Config(msg)) = result {
assert!(msg.contains("already registered"));
} else {
panic!("Expected Config error");
}
}
#[test]
fn test_singleton_returns_same_instance() {
let container = ServiceContainer::new();
let service = CounterService::new();
container.register_singleton(service).unwrap();
let instance1: Arc<CounterService> = container.get().unwrap();
instance1.increment();
let instance2: Arc<CounterService> = container.get().unwrap();
assert_eq!(instance2.get_count(), 1);
instance2.increment();
assert_eq!(instance1.get_count(), 2);
}
#[test]
fn test_register_factory() {
let container = ServiceContainer::new();
let factory = || TestService {
value: "from_factory".to_string(),
};
let result = container.register_factory(factory);
assert!(result.is_ok());
assert_eq!(container.service_count(), 1);
}
#[test]
fn test_factory_creates_service() {
let container = ServiceContainer::new();
let factory = || TestService {
value: "factory_value".to_string(),
};
container.register_factory(factory).unwrap();
let service: Arc<TestService> = container.get().unwrap();
assert_eq!(service.value, "factory_value");
}
#[test]
fn test_get_service() {
let container = ServiceContainer::new();
let service = TestService {
value: "get_test".to_string(),
};
container.register(service).unwrap();
let retrieved: Arc<TestService> = container.get().unwrap();
assert_eq!(retrieved.value, "get_test");
}
#[test]
fn test_get_singleton() {
let container = ServiceContainer::new();
let service = TestService {
value: "singleton_get".to_string(),
};
container.register_singleton(service).unwrap();
let retrieved: Arc<TestService> = container.get().unwrap();
assert_eq!(retrieved.value, "singleton_get");
}
#[test]
fn test_get_unregistered_service_fails() {
let container = ServiceContainer::new();
let result: Result<Arc<TestService>> = container.get();
assert!(result.is_err());
if let Err(GatewayError::Config(msg)) = result {
assert!(msg.contains("not registered"));
} else {
panic!("Expected Config error");
}
}
#[test]
fn test_get_prefers_singleton_over_service() {
let container = ServiceContainer::new();
let service = TestService {
value: "regular".to_string(),
};
container.register(service).unwrap();
let container2 = ServiceContainer::new();
let singleton = AnotherService { number: 100 };
container2.register_singleton(singleton).unwrap();
let retrieved: Arc<AnotherService> = container2.get().unwrap();
assert_eq!(retrieved.number, 100);
}
#[test]
fn test_try_get_existing_service() {
let container = ServiceContainer::new();
let service = TestService {
value: "try_get_test".to_string(),
};
container.register(service).unwrap();
let retrieved: Option<Arc<TestService>> = container.try_get();
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().value, "try_get_test");
}
#[test]
fn test_try_get_nonexistent_service() {
let container = ServiceContainer::new();
let retrieved: Option<Arc<TestService>> = container.try_get();
assert!(retrieved.is_none());
}
#[test]
fn test_contains_registered_service() {
let container = ServiceContainer::new();
let service = TestService {
value: "contains_test".to_string(),
};
container.register(service).unwrap();
assert!(container.contains::<TestService>());
}
#[test]
fn test_contains_registered_singleton() {
let container = ServiceContainer::new();
let service = TestService {
value: "singleton_contains".to_string(),
};
container.register_singleton(service).unwrap();
assert!(container.contains::<TestService>());
}
#[test]
fn test_contains_unregistered_service() {
let container = ServiceContainer::new();
assert!(!container.contains::<TestService>());
}
#[test]
fn test_remove_service() {
let container = ServiceContainer::new();
let service = TestService {
value: "remove_test".to_string(),
};
container.register(service).unwrap();
assert_eq!(container.service_count(), 1);
let result = container.remove::<TestService>();
assert!(result.is_ok());
assert_eq!(container.service_count(), 0);
assert!(!container.contains::<TestService>());
}
#[test]
fn test_remove_singleton() {
let container = ServiceContainer::new();
let service = TestService {
value: "remove_singleton".to_string(),
};
container.register_singleton(service).unwrap();
assert_eq!(container.service_count(), 1);
let result = container.remove::<TestService>();
assert!(result.is_ok());
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_remove_unregistered_service_fails() {
let container = ServiceContainer::new();
let result = container.remove::<TestService>();
assert!(result.is_err());
if let Err(GatewayError::Config(msg)) = result {
assert!(msg.contains("not registered"));
} else {
panic!("Expected Config error");
}
}
#[test]
fn test_clear_empty_container() {
let container = ServiceContainer::new();
container.clear();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_clear_services() {
let container = ServiceContainer::new();
container
.register(TestService {
value: "test1".to_string(),
})
.unwrap();
container.register(AnotherService { number: 42 }).unwrap();
assert_eq!(container.service_count(), 2);
container.clear();
assert_eq!(container.service_count(), 0);
assert!(!container.contains::<TestService>());
assert!(!container.contains::<AnotherService>());
}
#[test]
fn test_clear_singletons() {
let container = ServiceContainer::new();
container
.register_singleton(TestService {
value: "singleton".to_string(),
})
.unwrap();
container.clear();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_clear_mixed_services() {
let container = ServiceContainer::new();
container
.register(TestService {
value: "regular".to_string(),
})
.unwrap();
container
.register_singleton(AnotherService { number: 100 })
.unwrap();
assert_eq!(container.service_count(), 2);
container.clear();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_service_count_empty() {
let container = ServiceContainer::new();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_service_count_with_services() {
let container = ServiceContainer::new();
container
.register(TestService {
value: "test".to_string(),
})
.unwrap();
assert_eq!(container.service_count(), 1);
container.register(AnotherService { number: 42 }).unwrap();
assert_eq!(container.service_count(), 2);
}
#[test]
fn test_service_count_with_singletons() {
let container = ServiceContainer::new();
container
.register_singleton(TestService {
value: "singleton".to_string(),
})
.unwrap();
assert_eq!(container.service_count(), 1);
}
#[test]
fn test_service_count_mixed() {
let container = ServiceContainer::new();
container
.register(TestService {
value: "regular".to_string(),
})
.unwrap();
container
.register_singleton(AnotherService { number: 100 })
.unwrap();
assert_eq!(container.service_count(), 2);
}
#[test]
fn test_builder_new() {
let builder = ServiceBuilder::new();
let container = builder.build();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_builder_default() {
let builder = ServiceBuilder::default();
let container = builder.build();
assert_eq!(container.service_count(), 0);
}
#[test]
fn test_builder_add_service() {
let service = TestService {
value: "builder_test".to_string(),
};
let container = ServiceBuilder::new().add_service(service).unwrap().build();
assert_eq!(container.service_count(), 1);
assert!(container.contains::<TestService>());
}
#[test]
fn test_builder_add_singleton() {
let service = TestService {
value: "builder_singleton".to_string(),
};
let container = ServiceBuilder::new()
.add_singleton(service)
.unwrap()
.build();
assert_eq!(container.service_count(), 1);
let retrieved: Arc<TestService> = container.get().unwrap();
assert_eq!(retrieved.value, "builder_singleton");
}
#[test]
fn test_builder_add_factory() {
let factory = || TestService {
value: "builder_factory".to_string(),
};
let container = ServiceBuilder::new().add_factory(factory).unwrap().build();
assert_eq!(container.service_count(), 1);
let retrieved: Arc<TestService> = container.get().unwrap();
assert_eq!(retrieved.value, "builder_factory");
}
#[test]
fn test_builder_chaining() {
let container = ServiceBuilder::new()
.add_service(TestService {
value: "test".to_string(),
})
.unwrap()
.add_singleton(AnotherService { number: 42 })
.unwrap()
.build();
assert_eq!(container.service_count(), 2);
assert!(container.contains::<TestService>());
assert!(container.contains::<AnotherService>());
}
#[test]
fn test_builder_duplicate_service_fails() {
let result = ServiceBuilder::new()
.add_service(TestService {
value: "first".to_string(),
})
.unwrap()
.add_service(TestService {
value: "second".to_string(),
});
assert!(result.is_err());
}
#[test]
fn test_global_container_exists() {
let container = global_container();
let _ = container.service_count();
}
#[test]
fn test_register_and_get_global() {
#[derive(Debug, Clone)]
struct UniqueGlobalService1 {
value: String,
}
let service = UniqueGlobalService1 {
value: "global_test".to_string(),
};
let register_result = register_global(service);
if register_result.is_ok() {
let retrieved: Result<Arc<UniqueGlobalService1>> = get_global();
assert!(retrieved.is_ok());
assert_eq!(retrieved.unwrap().value, "global_test");
}
}
#[test]
fn test_register_global_singleton() {
#[derive(Debug, Clone)]
struct UniqueGlobalService2 {
value: String,
}
let service = UniqueGlobalService2 {
value: "global_singleton".to_string(),
};
let register_result = register_global_singleton(service);
if register_result.is_ok() {
let retrieved: Result<Arc<UniqueGlobalService2>> = get_global();
assert!(retrieved.is_ok());
}
}
#[test]
fn test_concurrent_get() {
use std::thread;
let container = Arc::new(ServiceContainer::new());
container
.register(TestService {
value: "concurrent".to_string(),
})
.unwrap();
let handles: Vec<_> = (0..10)
.map(|_| {
let container = Arc::clone(&container);
thread::spawn(move || {
let service: Arc<TestService> = container.get().unwrap();
assert_eq!(service.value, "concurrent");
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn test_concurrent_singleton_access() {
use std::thread;
let container = Arc::new(ServiceContainer::new());
let counter = CounterService::new();
container.register_singleton(counter).unwrap();
let handles: Vec<_> = (0..10)
.map(|_| {
let container = Arc::clone(&container);
thread::spawn(move || {
let service: Arc<CounterService> = container.get().unwrap();
service.increment();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let final_service: Arc<CounterService> = container.get().unwrap();
assert_eq!(final_service.get_count(), 10);
}
#[test]
fn test_service_with_arc_sharing() {
let container = ServiceContainer::new();
let service = TestService {
value: "shared".to_string(),
};
container.register(service).unwrap();
let instance1: Arc<TestService> = container.get().unwrap();
let instance2: Arc<TestService> = container.get().unwrap();
assert_eq!(instance1.value, instance2.value);
assert_eq!(Arc::strong_count(&instance1), Arc::strong_count(&instance2));
}
#[test]
fn test_multiple_service_types() {
let container = ServiceContainer::new();
container
.register(TestService {
value: "test".to_string(),
})
.unwrap();
container.register(AnotherService { number: 42 }).unwrap();
container.register(CounterService::new()).unwrap();
assert_eq!(container.service_count(), 3);
assert!(container.contains::<TestService>());
assert!(container.contains::<AnotherService>());
assert!(container.contains::<CounterService>());
}
}