use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Debug, thiserror::Error)]
pub enum RegistryError {
#[error("already registered: {0}")]
AlreadyRegistered(String),
}
pub(crate) struct NamedRegistry<T: ?Sized + Send + Sync + 'static> {
map: Mutex<HashMap<String, Arc<T>>>,
}
impl<T: ?Sized + Send + Sync + 'static> NamedRegistry<T> {
pub fn new() -> Self {
Self {
map: Mutex::new(HashMap::new()),
}
}
pub fn register(&self, name: impl Into<String>, value: Arc<T>) -> Result<(), RegistryError> {
let name = name.into();
let mut map = self
.map
.lock()
.expect("registry mutex poisoned: another thread panicked while holding this lock"); if map.insert(name.clone(), value).is_some() {
return Err(RegistryError::AlreadyRegistered(name));
}
Ok(())
}
pub fn get(&self, name: &str) -> Option<Arc<T>> {
self.map
.lock()
.expect("registry mutex poisoned: another thread panicked while holding this lock") .get(name)
.cloned()
}
}
impl<T: ?Sized + Send + Sync + 'static> Default for NamedRegistry<T> {
fn default() -> Self {
Self::new()
}
}
pub(crate) type IdempotentRegistry = NamedRegistry<dyn camel_api::IdempotentRepository>;
pub(crate) type SharedIdempotentRegistry = Arc<IdempotentRegistry>;
pub(crate) type ClaimCheckRegistry = NamedRegistry<dyn camel_api::ClaimCheckRepository>;
pub(crate) type SharedClaimCheckRegistry = Arc<ClaimCheckRegistry>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn register_then_get() {
let registry: NamedRegistry<str> = NamedRegistry::new();
registry.register("hello", Arc::from("world")).unwrap();
let got = registry.get("hello");
assert!(got.is_some());
assert_eq!(*got.unwrap(), *"world");
}
#[test]
fn get_missing_returns_none() {
let registry: NamedRegistry<str> = NamedRegistry::new();
assert!(registry.get("nonexistent").is_none());
}
#[test]
fn duplicate_register_fails() {
let registry: NamedRegistry<str> = NamedRegistry::new();
registry.register("key1", Arc::from("first")).unwrap();
let err = registry.register("key1", Arc::from("second")).unwrap_err();
assert!(
matches!(&err, RegistryError::AlreadyRegistered(name) if name == "key1"),
"expected AlreadyRegistered('key1'), got {err:?}"
);
let val = registry.get("key1").unwrap();
assert_eq!(*val, *"second");
}
}