1use crate::graph::Node;
2
3#[derive(Debug, Clone)]
5pub enum ElemNode {
6 Node(Node),
7 Number(f64),
8}
9
10impl From<Node> for ElemNode {
11 fn from(node: Node) -> Self {
12 Self::Node(node)
13 }
14}
15
16impl From<f64> for ElemNode {
17 fn from(value: f64) -> Self {
18 Self::Number(value)
19 }
20}
21
22pub fn create_node(
24 kind: impl Into<String>,
25 props: serde_json::Value,
26 children: impl IntoIterator<Item = ElemNode>,
27) -> Node {
28 Node::new(kind, props, children.into_iter().map(resolve).collect())
29}
30
31pub fn is_node(value: &ElemNode) -> bool {
33 matches!(value, ElemNode::Node(_))
34}
35
36pub fn resolve(value: impl Into<ElemNode>) -> Node {
38 match value.into() {
39 ElemNode::Node(node) => node,
40 ElemNode::Number(value) => {
41 Node::new("const", serde_json::json!({ "value": value }), vec![])
42 }
43 }
44}
45
46pub fn unpack(node: Node, num_channels: usize) -> Vec<Node> {
48 (0..num_channels)
49 .map(|output_channel| node.clone().with_output_channel(output_channel))
50 .collect()
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn resolve_turns_numbers_into_const_nodes() {
59 let node = resolve(220.0);
60
61 assert_eq!(node.kind(), "const");
62 assert_eq!(node.props()["value"], 220.0);
63 assert!(node.children().is_empty());
64 assert_eq!(node.output_channel(), 0);
65 }
66
67 #[test]
68 fn resolve_leaves_nodes_unchanged() {
69 let node = Node::new("sin", serde_json::Value::Null, vec![]).with_output_channel(2);
70
71 match resolve(node.clone()) {
72 resolved if resolved.kind() == node.kind() => {
73 assert_eq!(resolved.output_channel(), 2);
74 }
75 _ => panic!("expected resolve to keep the node as-is"),
76 }
77 }
78
79 #[test]
80 fn is_node_detects_node_values() {
81 assert!(is_node(&ElemNode::Node(Node::new(
82 "sr",
83 serde_json::Value::Null,
84 vec![],
85 ))));
86 assert!(!is_node(&ElemNode::Number(1.0)));
87 }
88
89 #[test]
90 fn create_node_resolves_children() {
91 let node = create_node(
92 "add",
93 serde_json::Value::Null,
94 [ElemNode::from(1.0), ElemNode::from(2.0)],
95 );
96
97 assert_eq!(node.kind(), "add");
98 assert_eq!(node.children().len(), 2);
99 assert_eq!(node.children()[0].kind(), "const");
100 assert_eq!(node.children()[0].props()["value"], 1.0);
101 assert_eq!(node.children()[1].props()["value"], 2.0);
102 assert_eq!(node.output_channel(), 0);
103 }
104
105 #[test]
106 fn unpack_clones_the_node_for_each_channel() {
107 let node = Node::new("meter", serde_json::json!({ "name": "out" }), vec![]);
108
109 let unpacked = unpack(node.clone(), 3);
110
111 assert_eq!(unpacked.len(), 3);
112 for (index, child) in unpacked.into_iter().enumerate() {
113 assert_eq!(child.kind(), node.kind());
114 assert_eq!(child.props(), node.props());
115 assert_eq!(child.output_channel(), index);
116 }
117 }
118}