use std::{collections::HashMap, sync::Arc};
use super::{
BspContext, condition::ConditionFn, def::NodeDef, error::BspError, merge::Merger,
node::BspNode, value::BspValue,
};
pub type NodeFactory<S> =
Box<dyn Fn(&NodeDef, &BspContext) -> Result<Box<dyn BspNode<S>>, BspError> + Send + Sync>;
pub type ValueFactory = Arc<dyn Fn(&serde_json::Value) -> BspValue + Send + Sync>;
pub fn default_value_factory(value: &serde_json::Value) -> BspValue {
match value {
serde_json::Value::Bool(b) => BspValue::new(*b),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
BspValue::new(i)
} else if let Some(u) = n.as_u64() {
BspValue::new(u)
} else {
BspValue::new(n.as_f64().unwrap_or_default())
}
}
serde_json::Value::String(s) => BspValue::new(s.clone()),
other => BspValue::new(other.clone()),
}
}
pub struct NodeRegistry<S = ()> {
pub(crate) factories: HashMap<String, NodeFactory<S>>,
pub(crate) conditions: HashMap<String, ConditionFn<S>>,
pub(crate) mergers: HashMap<String, Arc<dyn Merger<S>>>,
pub(crate) value_factory: ValueFactory,
}
impl<S> Default for NodeRegistry<S> {
fn default() -> Self {
Self::new()
}
}
impl<S> NodeRegistry<S> {
#[must_use]
pub fn new() -> Self {
Self {
factories: HashMap::new(),
conditions: HashMap::new(),
mergers: HashMap::new(),
value_factory: Arc::new(default_value_factory),
}
}
pub fn register_node(
&mut self,
type_name: impl Into<String>,
factory: impl Fn(&NodeDef, &BspContext) -> Result<Box<dyn BspNode<S>>, BspError>
+ Send
+ Sync
+ 'static,
) {
self.factories.insert(type_name.into(), Box::new(factory));
}
pub fn register_condition(
&mut self,
name: impl Into<String>,
f: impl Fn(&S, &super::run::ValueStore) -> bool + Send + Sync + 'static,
) {
self.conditions.insert(name.into(), Arc::new(f));
}
pub fn register_merger<M: Merger<S> + 'static>(&mut self, name: impl Into<String>, merger: M) {
self.mergers.insert(name.into(), Arc::new(merger));
}
pub fn register_value_factory(
&mut self,
factory: impl Fn(&serde_json::Value) -> BspValue + Send + Sync + 'static,
) {
self.value_factory = Arc::new(factory);
}
#[must_use]
pub fn contains_node(&self, type_name: &str) -> bool {
self.factories.contains_key(type_name)
}
#[must_use]
pub fn contains_condition(&self, name: &str) -> bool {
self.conditions.contains_key(name)
}
#[must_use]
pub fn contains_merger(&self, name: &str) -> bool {
self.mergers.contains_key(name)
}
#[must_use]
pub fn node_type_names(&self) -> Vec<&str> {
self.factories.keys().map(String::as_str).collect()
}
#[must_use]
fn with_mut(mut self, f: impl FnOnce(&mut Self)) -> Self {
f(&mut self);
self
}
#[must_use]
pub fn with_node(
self,
type_name: impl Into<String>,
factory: impl Fn(&NodeDef, &BspContext) -> Result<Box<dyn BspNode<S>>, BspError>
+ Send
+ Sync
+ 'static,
) -> Self {
self.with_mut(|r| r.register_node(type_name, factory))
}
#[must_use]
pub fn with_condition(
self,
name: impl Into<String>,
f: impl Fn(&S, &super::run::ValueStore) -> bool + Send + Sync + 'static,
) -> Self {
self.with_mut(|r| r.register_condition(name, f))
}
#[must_use]
pub fn with_merger<M: Merger<S> + 'static>(self, name: impl Into<String>, merger: M) -> Self {
self.with_mut(|r| r.register_merger(name, merger))
}
#[must_use]
pub fn with_value_factory(
self,
factory: impl Fn(&serde_json::Value) -> BspValue + Send + Sync + 'static,
) -> Self {
self.with_mut(|r| r.register_value_factory(factory))
}
}