use std::sync::{Arc, OnceLock, RwLock};
use panproto_gat::{EnrichmentKind, LayoutPolicySpec};
use panproto_schema::Schema;
use rustc_hash::FxHashMap;
use crate::error::LensError;
pub trait LayoutEnricher: Send + Sync + 'static {
fn enrich(&self, schema: &Schema, policy: &LayoutPolicySpec) -> Result<Schema, LensError>;
}
#[derive(Default)]
struct Registry {
enrichers: FxHashMap<EnrichmentKind, FxHashMap<String, Arc<dyn LayoutEnricher>>>,
}
static REGISTRY: OnceLock<RwLock<Registry>> = OnceLock::new();
fn registry() -> &'static RwLock<Registry> {
REGISTRY.get_or_init(|| RwLock::new(Registry::default()))
}
pub fn register_enricher(
kind: EnrichmentKind,
enricher_name: impl Into<String>,
driver: Arc<dyn LayoutEnricher>,
) {
let mut g = registry()
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner);
g.enrichers
.entry(kind)
.or_default()
.insert(enricher_name.into(), driver);
}
pub fn lookup_enricher(
kind: EnrichmentKind,
enricher_name: &str,
) -> Result<Arc<dyn LayoutEnricher>, LensError> {
let g = registry()
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
g.enrichers
.get(&kind)
.and_then(|m| m.get(enricher_name).cloned())
.ok_or_else(|| LensError::UnknownEnricher {
kind,
enricher: enricher_name.to_owned(),
})
}
#[must_use]
pub fn has_enricher(kind: EnrichmentKind, enricher_name: &str) -> bool {
let g = registry()
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
g.enrichers
.get(&kind)
.is_some_and(|m| m.contains_key(enricher_name))
}