use super::Storage;
use std::collections::HashMap;
use std::io;
use std::sync::{Arc, RwLock};
pub type StorageFactory = Box<dyn Fn() -> Arc<dyn Storage> + Send + Sync>;
pub struct StorageRegistry {
backends: Arc<RwLock<HashMap<String, StorageFactory>>>,
}
impl StorageRegistry {
pub fn new() -> Self {
Self {
backends: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn register(&mut self, name: &str, factory: StorageFactory) -> io::Result<()> {
let mut backends = self
.backends
.write()
.map_err(|e| io::Error::other(e.to_string()))?;
if backends.contains_key(name) {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!("Storage backend '{}' is already registered", name),
));
}
backends.insert(name.to_string(), factory);
Ok(())
}
pub fn unregister(&mut self, name: &str) -> io::Result<()> {
let mut backends = self
.backends
.write()
.map_err(|e| io::Error::other(e.to_string()))?;
if backends.remove(name).is_none() {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Storage backend '{}' not found", name),
));
}
Ok(())
}
pub fn get(&self, name: &str) -> Option<Arc<dyn Storage>> {
let backends = self.backends.read().ok()?;
let factory = backends.get(name)?;
Some(factory())
}
pub fn contains(&self, name: &str) -> bool {
self.backends
.read()
.map(|backends| backends.contains_key(name))
.unwrap_or(false)
}
pub fn list(&self) -> Vec<String> {
self.backends
.read()
.map(|backends| backends.keys().cloned().collect())
.unwrap_or_default()
}
pub fn clear(&mut self) -> io::Result<()> {
let mut backends = self
.backends
.write()
.map_err(|e| io::Error::other(e.to_string()))?;
backends.clear();
Ok(())
}
}
impl Default for StorageRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::staticfiles::{FileSystemStorage, MemoryStorage};
use std::path::PathBuf;
#[test]
fn test_registry_creation() {
let registry = StorageRegistry::new();
assert_eq!(registry.list().len(), 0);
}
#[test]
fn test_register_storage_backend() {
let mut registry = StorageRegistry::new();
let result = registry.register(
"test",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
);
assert!(result.is_ok());
assert!(registry.contains("test"));
}
#[test]
fn test_register_duplicate_fails() {
let mut registry = StorageRegistry::new();
registry
.register(
"test",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
let result = registry.register(
"test",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
);
assert!(result.is_err());
assert_eq!(result.unwrap_err().kind(), io::ErrorKind::AlreadyExists);
}
#[test]
fn test_get_storage_backend() {
let mut registry = StorageRegistry::new();
registry
.register(
"memory",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
let storage = registry.get("memory");
assert!(storage.is_some());
let url = storage.unwrap().url("test.txt");
assert_eq!(url, "/static/test.txt");
}
#[test]
fn test_get_nonexistent_backend() {
let registry = StorageRegistry::new();
let storage = registry.get("nonexistent");
assert!(storage.is_none());
}
#[test]
fn test_unregister_storage_backend() {
let mut registry = StorageRegistry::new();
registry
.register(
"test",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
assert!(registry.contains("test"));
let result = registry.unregister("test");
assert!(result.is_ok());
assert!(!registry.contains("test"));
}
#[test]
fn test_unregister_nonexistent_fails() {
let mut registry = StorageRegistry::new();
let result = registry.unregister("nonexistent");
assert!(result.is_err());
assert_eq!(result.unwrap_err().kind(), io::ErrorKind::NotFound);
}
#[test]
fn test_list_storage_backends() {
let mut registry = StorageRegistry::new();
registry
.register(
"memory",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
registry
.register(
"filesystem",
Box::new(|| {
Arc::new(FileSystemStorage::new(
PathBuf::from("/tmp/static"),
"/static/",
))
}),
)
.unwrap();
let backends = registry.list();
assert_eq!(backends.len(), 2);
assert!(backends.contains(&"memory".to_string()));
assert!(backends.contains(&"filesystem".to_string()));
}
#[test]
fn test_clear_registry() {
let mut registry = StorageRegistry::new();
registry
.register(
"test1",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
registry
.register(
"test2",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
assert_eq!(registry.list().len(), 2);
let result = registry.clear();
assert!(result.is_ok());
assert_eq!(registry.list().len(), 0);
}
#[test]
fn test_multiple_gets_create_different_instances() {
let mut registry = StorageRegistry::new();
registry
.register(
"test",
Box::new(|| Arc::new(MemoryStorage::new("/static/"))),
)
.unwrap();
let storage1 = registry.get("test").unwrap();
let storage2 = registry.get("test").unwrap();
assert_ne!(Arc::as_ptr(&storage1), Arc::as_ptr(&storage2));
}
}