use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Default)]
pub struct Registry {
shared_storage: HashMap<String, Arc<dyn Any + Send + Sync>>, unique_storage: HashMap<String, Box<dyn Any + Send + Sync>>, }
impl Registry {
pub fn new() -> Self {
Registry {
shared_storage: HashMap::new(),
unique_storage: HashMap::new(),
}
}
pub fn contains_shared(&self, key: &str) -> bool {
self.shared_storage.contains_key(key)
}
pub fn insert_shared<K: ToString, U: Send + Sync + 'static>(&mut self, key: K, value: U) {
self.shared_storage.insert(
key.to_string(),
Arc::new(value) as Arc<dyn Any + Send + Sync>,
);
}
pub fn get_shared<V: Send + Sync + 'static>(&self, key: &str) -> Result<Arc<V>, String> {
match self.shared_storage.get(key) {
Some(boxed) => boxed.clone().downcast::<V>().map_err(|_| {
format!(
"Failed to downcast to the requested type for shared key: {}",
key
)
}),
None => Err(format!("Shared key not found: {}", key)),
}
}
pub fn contains_unique(&self, key: &str) -> bool {
self.unique_storage.contains_key(key)
}
pub fn insert_unique<K: ToString, U: Send + Sync + 'static>(&mut self, key: K, value: U) {
self.unique_storage.insert(
key.to_string(),
Box::new(value) as Box<dyn Any + Send + Sync>,
);
}
pub fn take_unique<V: Send + Sync + 'static>(&mut self, key: &str) -> Result<V, String> {
match self.unique_storage.remove(key) {
Some(boxed) => boxed.downcast::<V>().map(|b| *b).map_err(|_| {
format!(
"Failed to downcast to the requested type for unique key: {}",
key
)
}),
None => Err(format!("Takable key not found: {}", key)),
}
}
pub fn clone_unique<V: Clone + Send + Sync + 'static>(&self, key: &str) -> Result<V, String> {
match self.unique_storage.get(key) {
Some(boxed) => boxed.downcast_ref::<V>().cloned().ok_or_else(|| {
format!(
"Failed to downcast to the requested type for unique key: {}",
key
)
}),
None => Err(format!("Takable key not found: {}", key)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert_and_get_shared() {
let mut registry = Registry::new();
registry.insert_shared("shared1", 42);
assert_eq!(*registry.get_shared::<i32>("shared1").unwrap(), 42);
assert!(registry.get_shared::<f64>("shared1").is_err()); }
#[test]
fn test_insert_and_take_unique() {
let mut registry = Registry::new();
registry.insert_unique("unique1", "Hello".to_string());
assert_eq!(registry.take_unique::<String>("unique1").unwrap(), "Hello");
assert!(registry.take_unique::<String>("unique1").is_err()); }
#[test]
fn test_insert_and_clone_then_take_unique() {
let mut registry = Registry::new();
registry.insert_unique("unique2", "World".to_string());
assert_eq!(registry.clone_unique::<String>("unique2").unwrap(), "World");
assert!(registry.take_unique::<String>("unique2").is_ok());
}
#[test]
fn test_failed_take_after_cloning() {
let mut registry = Registry::new();
registry.insert_unique("unique3", "Another".to_string());
assert_eq!(
registry.clone_unique::<String>("unique3").unwrap(),
"Another"
);
assert_eq!(
registry.take_unique::<String>("unique3").unwrap(),
"Another"
);
assert!(registry.take_unique::<String>("unique3").is_err());
}
}