use std::sync::Arc;
use sim_kernel::{Cx, Error, Expr, Result, Symbol, Value};
mod builtin;
pub fn resolve_target(cx: &mut Cx, target: &Expr) -> Result<Value> {
if let Expr::Symbol(symbol) = target
&& let Ok(codec) = cx.resolve_codec(symbol)
{
return Ok(codec);
}
cx.eval_expr(target.clone())
}
pub fn call_target_expr(cx: &mut Cx, target: Value, input: Expr) -> Result<Expr> {
TopologyAdapterRegistry::core().call(cx, &target, input, None)
}
pub trait TopologyAdapter: Send + Sync {
fn name(&self) -> Symbol;
fn accepts(&self, cx: &mut Cx, target: &Value) -> bool;
fn call(&self, cx: &mut Cx, target: &Value, input: Expr, role: Option<&Symbol>)
-> Result<Expr>;
}
#[derive(Clone, Default)]
pub struct TopologyAdapterRegistry {
adapters: Vec<Arc<dyn TopologyAdapter>>,
}
impl TopologyAdapterRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn core() -> Self {
let mut registry = Self::new();
for adapter in builtin::core_adapters() {
registry.register(adapter).unwrap();
}
registry
}
pub fn register(&mut self, adapter: Arc<dyn TopologyAdapter>) -> Result<()> {
let name = adapter.name();
if self.adapters.iter().any(|existing| existing.name() == name) {
return Err(Error::Eval(format!(
"topology adapter {name} is already registered"
)));
}
self.adapters.push(adapter);
Ok(())
}
pub fn names(&self) -> Vec<Symbol> {
self.adapters.iter().map(|adapter| adapter.name()).collect()
}
pub fn resolve(&self, cx: &mut Cx, target: &Value) -> Option<&dyn TopologyAdapter> {
self.adapters
.iter()
.map(Arc::as_ref)
.find(|adapter| adapter.accepts(cx, target))
}
pub fn call(
&self,
cx: &mut Cx,
target: &Value,
input: Expr,
role: Option<&Symbol>,
) -> Result<Expr> {
let Some(adapter) = self.resolve(cx, target) else {
return Err(Error::TypeMismatch {
expected: "topology adapter target",
found: "unsupported target",
});
};
adapter.call(cx, target, input, role)
}
}