hydro2_network/
network.rs

1// ---------------- [ File: src/network.rs ]
2crate::ix!();
3
4/// The full network containing nodes, edges, and any relevant metadata.
5#[derive(Default,Builder,MutGetters,Setters,Getters,Debug,Clone)]
6#[getset(get="pub",set = "pub", get_mut = "pub")]
7#[builder(setter(into))]
8pub struct Network<NetworkItem> 
9where NetworkItem: Debug + Send + Sync
10{
11    /// All nodes present in this network.
12    nodes: Vec<NetworkNode<NetworkItem>>,
13    /// The directed edges forming the DAG between nodes.
14    edges: Vec<NetworkEdge>,
15}
16
17impl<NetworkItem> Network<NetworkItem> 
18where NetworkItem: Debug + Send + Sync
19{
20    pub fn clear(&mut self) {
21        self.nodes.clear();
22        self.edges.clear();
23    }
24}
25
26#[macro_export]
27macro_rules! network {
28    ($nodes:expr, $edges:expr) => {{
29        let mut net = NetworkBuilder::default()
30            .nodes($nodes)
31            .edges($edges)
32            .build()
33            .unwrap();
34
35        // 4) Possibly do net.validate() => checks cycles, etc.
36        if let Err(e) = net.validate() {
37            panic!("network validation saw an error: {:#?}", e);
38        }
39
40        // 5) Wire up => automatically allocate arcs for each node’s outputs & link them
41        if let Err(e) = wire_up_network(&mut net) {
42            panic!("network wiring saw an error: {:#?}", e);
43        }
44
45        net
46    }};
47}
48
49#[cfg(test)]
50mod network_macro_tests {
51    use super::*;
52
53    #[test]
54    fn test_network_macro_basic() -> Result<(), NetworkError> {
55        // We'll define 2 nodes, 1 edge => build a small network
56        let n0: NetworkNode<TestWireIO<i32>> = node!(0 => ConstantOp::new(100));
57        let n1: NetworkNode<TestWireIO<i32>> = node!(1 => AddOp::new(42));
58        let e0 = edge!(0:0 -> 1:0);
59
60        // Use the macro
61        let net = network!(vec![n0, n1], vec![e0]);
62        // That calls net.validate() + wire_up_network(...) under the hood.
63
64        // Now net is fully wired
65        // Node0 => input_count=0 => output_count=1 => 
66        // Node1 => input_count=1 => output_count=1
67        // Edge => 0:0 -> 1:0 means node1 inputs[0] is the same Arc as node0 outputs[0]
68        assert_eq!(net.nodes().len(), 2);
69        assert_eq!(net.edges().len(), 1);
70
71        // Node0 => outputs[0] must be Some(...)
72        assert!(net.nodes()[0].outputs()[0].is_some());
73        // Node1 => inputs[0] must be Some
74        assert!(net.nodes()[1].inputs()[0].is_some());
75
76        Ok(())
77    }
78
79    #[test]
80    fn test_network_macro_fanout() -> Result<(), NetworkError> {
81        let cst: NetworkNode<TestWireIO<i32>> = node!(0 => ConstantOp::new(10));
82        let aop: NetworkNode<TestWireIO<i32>> = node!(1 => AddOp::new(5));
83        let mop: NetworkNode<TestWireIO<i32>> = node!(2 => MultiplyOp::new(2));
84        let net = network!(
85            vec![cst, aop, mop],
86            vec![
87                edge!(0:0 -> 1:0),
88                edge!(0:0 -> 2:0),
89            ]
90        );
91        // Should be valid, Node1 and Node2 each take the same output from Node0
92        Ok(())
93    }
94
95    #[test]
96    #[should_panic(expected = "Cycle detected")]
97    fn test_network_macro_cycle_panics() {
98        // if we introduce a cycle => net.validate() should fail => triggers panic in the macro
99        let n0: NetworkNode<TestWireIO<i32>> = node!(0 => NoOpOperator::default());
100        let n1: NetworkNode<TestWireIO<i32>> = node!(1 => NoOpOperator::default());
101        // cycle
102        let _ = network!(
103            vec![n0, n1],
104            vec![
105                edge!(0:0 -> 1:0),
106                edge!(1:0 -> 0:0),
107            ]
108        );
109    }
110}