use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, PoisonError, RwLock};
#[derive(Default)]
pub struct OverrideRegistry {
overrides: RwLock<HashMap<usize, Arc<dyn Any + Send + Sync>>>,
}
impl OverrideRegistry {
pub fn new() -> Self {
Self {
overrides: RwLock::new(HashMap::new()),
}
}
pub fn set<O: Clone + Send + Sync + 'static>(&self, func_ptr: usize, value: O) {
self.overrides
.write()
.unwrap_or_else(PoisonError::into_inner)
.insert(func_ptr, Arc::new(value));
}
pub fn get<O: Clone + 'static>(&self, func_ptr: usize) -> Option<O> {
self.overrides
.read()
.unwrap_or_else(PoisonError::into_inner)
.get(&func_ptr)
.and_then(|arc| arc.downcast_ref::<O>().cloned())
}
pub fn remove(&self, func_ptr: usize) {
self.overrides
.write()
.unwrap_or_else(PoisonError::into_inner)
.remove(&func_ptr);
}
pub fn clear(&self) {
self.overrides
.write()
.unwrap_or_else(PoisonError::into_inner)
.clear();
}
pub fn has(&self, func_ptr: usize) -> bool {
self.overrides
.read()
.unwrap_or_else(PoisonError::into_inner)
.contains_key(&func_ptr)
}
pub fn len(&self) -> usize {
self.overrides
.read()
.unwrap_or_else(PoisonError::into_inner)
.len()
}
pub fn is_empty(&self) -> bool {
self.overrides
.read()
.unwrap_or_else(PoisonError::into_inner)
.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn factory_a() -> String {
"production_a".to_string()
}
fn factory_b() -> String {
"production_b".to_string()
}
#[test]
fn test_set_and_get_override() {
let registry = OverrideRegistry::new();
registry.set(factory_a as *const () as usize, "mock_a".to_string());
let value: Option<String> = registry.get(factory_a as *const () as usize);
assert_eq!(value, Some("mock_a".to_string()));
}
#[test]
fn test_different_functions_same_return_type() {
let registry = OverrideRegistry::new();
registry.set(factory_a as *const () as usize, "mock_a".to_string());
registry.set(factory_b as *const () as usize, "mock_b".to_string());
let value_a: Option<String> = registry.get(factory_a as *const () as usize);
let value_b: Option<String> = registry.get(factory_b as *const () as usize);
assert_eq!(value_a, Some("mock_a".to_string()));
assert_eq!(value_b, Some("mock_b".to_string()));
}
#[test]
fn test_get_nonexistent_returns_none() {
let registry = OverrideRegistry::new();
let value: Option<String> = registry.get(factory_a as *const () as usize);
assert!(value.is_none());
}
#[test]
fn test_remove_override() {
let registry = OverrideRegistry::new();
registry.set(factory_a as *const () as usize, "mock_a".to_string());
assert!(registry.has(factory_a as *const () as usize));
registry.remove(factory_a as *const () as usize);
assert!(!registry.has(factory_a as *const () as usize));
let value: Option<String> = registry.get(factory_a as *const () as usize);
assert!(value.is_none());
}
#[test]
fn test_clear_overrides() {
let registry = OverrideRegistry::new();
registry.set(factory_a as *const () as usize, "mock_a".to_string());
registry.set(factory_b as *const () as usize, "mock_b".to_string());
assert_eq!(registry.len(), 2);
registry.clear();
assert!(registry.is_empty());
}
#[test]
fn test_type_mismatch_returns_none() {
let registry = OverrideRegistry::new();
fn int_factory() -> i32 {
42
}
registry.set(int_factory as *const () as usize, 100i32);
let value: Option<String> = registry.get(int_factory as *const () as usize);
assert!(value.is_none());
let value: Option<i32> = registry.get(int_factory as *const () as usize);
assert_eq!(value, Some(100));
}
}