Skip to main content

aether_ndk/
node.rs

1//! Node registration and factory system.
2//!
3//! The `NodeRegistry` maps type name strings → constructor functions,
4//! enabling the manifest system and CLI to instantiate nodes by name.
5
6use std::collections::HashMap;
7use aether_core::node::DspNode;
8use crate::ParamDef;
9
10/// A constructor that produces a boxed DspNode.
11pub type NodeFactory = fn() -> Box<dyn DspNode>;
12
13/// Metadata about a registered node type.
14#[derive(Clone)]
15pub struct NodeEntry {
16    pub type_name: &'static str,
17    pub param_defs: &'static [ParamDef],
18    pub factory: NodeFactory,
19}
20
21/// Global node registry — populated at startup via `register!`.
22pub struct NodeRegistry {
23    entries: HashMap<&'static str, NodeEntry>,
24}
25
26impl NodeRegistry {
27    pub fn new() -> Self {
28        Self { entries: HashMap::new() }
29    }
30
31    /// Register a node type.
32    pub fn register(&mut self, entry: NodeEntry) {
33        self.entries.insert(entry.type_name, entry);
34    }
35
36    /// Instantiate a node by type name. Returns `None` if not registered.
37    pub fn create(&self, type_name: &str) -> Option<Box<dyn DspNode>> {
38        self.entries.get(type_name).map(|e| (e.factory)())
39    }
40
41    /// List all registered node type names.
42    pub fn list(&self) -> Vec<&'static str> {
43        let mut names: Vec<_> = self.entries.keys().copied().collect();
44        names.sort_unstable();
45        names
46    }
47
48    /// Get param defs for a node type.
49    pub fn param_defs(&self, type_name: &str) -> Option<&[ParamDef]> {
50        self.entries.get(type_name).map(|e| e.param_defs)
51    }
52
53    pub fn len(&self) -> usize { self.entries.len() }
54    pub fn is_empty(&self) -> bool { self.entries.is_empty() }
55}
56
57impl Default for NodeRegistry {
58    fn default() -> Self { Self::new() }
59}
60
61/// Register a node type into a `NodeRegistry`.
62///
63/// ```rust
64/// use aether_ndk::{register_node, node::NodeRegistry};
65/// // register_node!(registry, MyFilter);
66/// ```
67#[macro_export]
68macro_rules! register_node {
69    ($registry:expr, $ty:ty) => {{
70        use $crate::{AetherNodeMeta, DspProcess, into_node};
71        $registry.register($crate::node::NodeEntry {
72            type_name: <$ty as AetherNodeMeta>::type_name(),
73            param_defs: <$ty as AetherNodeMeta>::param_defs(),
74            factory: || {
75                let node = <$ty as Default>::default();
76                into_node(node)
77            },
78        });
79    }};
80}