use std::{
collections::BTreeMap,
sync::{OnceLock, RwLock},
};
use sim_kernel::Symbol;
use sim_lib_numbers_cas::CasExpr;
pub type DiffRule = Box<dyn Fn(&[CasExpr], &Symbol) -> Option<CasExpr> + Send + Sync>;
#[derive(Default)]
pub struct CasDiffRegistry {
pub rules: BTreeMap<Symbol, DiffRule>,
}
impl CasDiffRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register_rule(&mut self, symbol: Symbol, rule: DiffRule) -> Option<DiffRule> {
self.rules.insert(symbol, rule)
}
pub fn apply(&self, symbol: &Symbol, args: &[CasExpr], var: &Symbol) -> Option<CasExpr> {
self.rules.get(symbol).and_then(|rule| rule(args, var))
}
}
static REGISTRY: OnceLock<RwLock<CasDiffRegistry>> = OnceLock::new();
pub fn global_diff_registry() -> &'static RwLock<CasDiffRegistry> {
REGISTRY.get_or_init(|| RwLock::new(CasDiffRegistry::new()))
}
pub fn register_diff_rule(symbol: Symbol, rule: DiffRule) -> Option<DiffRule> {
global_diff_registry()
.write()
.expect("CAS diff registry should not be poisoned")
.register_rule(symbol, rule)
}
pub(crate) fn apply_registered_rule(
symbol: &Symbol,
args: &[CasExpr],
var: &Symbol,
) -> Option<CasExpr> {
global_diff_registry()
.read()
.expect("CAS diff registry should not be poisoned")
.apply(symbol, args, var)
}