//! Aspect registry — register built-in and custom aspects by name. //! //! The compiler's AOP codegen uses the registry to look up aspect implementations //! by their decorator name (e.g., `"authenticate"` → `AuthenticateAspect`). use crate::Aspect; use std::collections::HashMap; use std::sync::{Arc, RwLock}; type AspectFactory = Box) -> Arc + Send + Sync>; /// Registry of aspect factories, indexed by decorator name. pub struct AspectRegistry { factories: RwLock>, } impl AspectRegistry { pub fn new() -> Self { Self { factories: RwLock::new(HashMap::new()), } } /// Create a registry with all built-in aspects registered. pub fn with_builtins() -> Self { let registry = Self::new(); registry.register_builtins(); registry } /// Register all built-in aspects. pub fn register_builtins(&self) { use crate::aspects::*; self.register("authenticate", |_params| { Arc::new(AuthenticateAspect) }); self.register("authorize", |params| { let role = params .get("role") .cloned() .unwrap_or_else(|| "user".to_string()); Arc::new(AuthorizeAspect::new(role)) }); self.register("cache", |params| { let ttl: u64 = params .get("ttl") .and_then(|s| s.parse().ok()) .unwrap_or(300); Arc::new(CacheAspect::new(ttl)) }); self.register("rate_limit", |params| { let requests: u32 = params .get("requests") .and_then(|s| s.parse().ok()) .unwrap_or(100); let per: u64 = params .get("per") .and_then(|s| s.parse().ok()) .unwrap_or(60); Arc::new(RateLimitAspect::new(requests, per)) }); self.register("log", |params| { let level = params .get("level") .cloned() .unwrap_or_else(|| "info".to_string()); Arc::new(LogAspect::new(level)) }); self.register("validate", |_params| Arc::new(ValidateAspect::new())); self.register("retry", |params| { let attempts: u32 = params .get("attempts") .and_then(|s| s.parse().ok()) .unwrap_or(3); let backoff = params .get("backoff") .map(|s| s.as_str()) .unwrap_or("none"); let aspect = RetryAspect::new(attempts); let aspect = match backoff { "exponential" => aspect.with_exponential_backoff(100), "fixed" => aspect.with_fixed_backoff(500), _ => aspect, }; Arc::new(aspect) }); self.register("trace", |params| { let service = params .get("service") .cloned() .unwrap_or_else(|| "el-ui".to_string()); Arc::new(TraceAspect::new(service)) }); } /// Register a custom aspect factory. pub fn register( &self, name: &str, factory: impl Fn(&HashMap) -> Arc + Send + Sync + 'static, ) { self.factories .write() .expect("registry lock poisoned") .insert(name.to_string(), Box::new(factory)); } /// Instantiate an aspect by decorator name with the given params. pub fn create( &self, name: &str, params: &HashMap, ) -> Option> { let factories = self.factories.read().expect("registry lock poisoned"); factories.get(name).map(|f| f(params)) } /// List all registered aspect names. pub fn aspect_names(&self) -> Vec { self.factories .read() .expect("registry lock poisoned") .keys() .cloned() .collect() } /// Check if an aspect name is registered. pub fn contains(&self, name: &str) -> bool { self.factories .read() .expect("registry lock poisoned") .contains_key(name) } } impl Default for AspectRegistry { fn default() -> Self { Self::new() } }