Skip to main content

mecha10_behavior_runtime/
registry.rs

1//! Node registry for dynamic behavior instantiation
2//!
3//! This module provides the `NodeRegistry` for registering and creating behavior nodes
4
5use crate::BoxedBehavior;
6use anyhow::{anyhow, Context as AnyhowContext, Result};
7use serde_json::Value;
8use std::collections::HashMap;
9use std::sync::{Arc, RwLock};
10
11pub type NodeFactory = Arc<dyn Fn(Value) -> Result<BoxedBehavior> + Send + Sync>;
12
13#[derive(Clone)]
14pub struct NodeRegistry {
15    factories: Arc<RwLock<HashMap<String, NodeFactory>>>,
16}
17
18impl NodeRegistry {
19    /// Create a new empty node registry.
20    pub fn new() -> Self {
21        Self {
22            factories: Arc::new(RwLock::new(HashMap::new())),
23        }
24    }
25
26    /// Register a node type (e.g. "move_to_goal") with a factory function.
27    ///
28    /// The factory is called each time a node of this type is created, receiving the JSON
29    pub fn register<F>(&mut self, node_type: impl Into<String>, factory: F)
30    where
31        F: Fn(Value) -> Result<BoxedBehavior> + Send + Sync + 'static,
32    {
33        let mut factories = self.factories.write().unwrap();
34        factories.insert(node_type.into(), Arc::new(factory));
35    }
36
37    /// Create a node instance from a registered type, looking up its factory and calling it
38    /// with `config`. Errors if the node type isn't registered or the factory fails.
39    pub fn create(&self, node_type: &str, config: Value) -> Result<BoxedBehavior> {
40        let factories = self.factories.read().unwrap();
41
42        let factory = factories
43            .get(node_type)
44            .ok_or_else(|| anyhow!("Node type '{}' not registered", node_type))?;
45
46        factory(config).with_context(|| format!("Failed to create node of type '{}'", node_type))
47    }
48
49    /// Check if a node type is registered.
50    pub fn has_node(&self, node_type: &str) -> bool {
51        self.contains(node_type)
52    }
53
54    /// Check if a node type is registered.
55    ///
56    /// Same check as [`has_node`](Self::has_node) - both names are kept since callers use
57    pub fn contains(&self, node_type: &str) -> bool {
58        let factories = self.factories.read().unwrap();
59        factories.contains_key(node_type)
60    }
61
62    /// Get a list of all registered node types.
63    pub fn registered_types(&self) -> Vec<String> {
64        let factories = self.factories.read().unwrap();
65        factories.keys().cloned().collect()
66    }
67
68    /// Get the number of registered node types.
69    pub fn len(&self) -> usize {
70        let factories = self.factories.read().unwrap();
71        factories.len()
72    }
73
74    /// Check if the registry is empty.
75    pub fn is_empty(&self) -> bool {
76        self.len() == 0
77    }
78}
79
80impl Default for NodeRegistry {
81    fn default() -> Self {
82        Self::new()
83    }
84}
85
86impl std::fmt::Debug for NodeRegistry {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        let factories = self.factories.read().unwrap();
89        f.debug_struct("NodeRegistry")
90            .field("registered_types", &factories.keys().collect::<Vec<_>>())
91            .finish()
92    }
93}