pub struct Graph { /* private fields */ }Expand description
The static topology of a flow-based network.
A Graph defines the structure of a network: which nodes exist, how they’re connected, and what conditions govern packet flow. The graph is immutable after creation.
§Example
use netrun_sim::graph::{Graph, Node, Edge, PortRef, PortType, Port, PortSlotSpec};
use std::collections::HashMap;
// Create a simple A -> B graph
let node_a = Node {
name: "A".to_string(),
in_ports: HashMap::new(),
out_ports: [("out".to_string(), Port { slots_spec: PortSlotSpec::Infinite })].into(),
in_salvo_conditions: HashMap::new(),
out_salvo_conditions: HashMap::new(),
};
let node_b = Node {
name: "B".to_string(),
in_ports: [("in".to_string(), Port { slots_spec: PortSlotSpec::Infinite })].into(),
out_ports: HashMap::new(),
in_salvo_conditions: HashMap::new(),
out_salvo_conditions: HashMap::new(),
};
let edge = Edge {
source: PortRef { node_name: "A".to_string(), port_type: PortType::Output, port_name: "out".to_string() },
target: PortRef { node_name: "B".to_string(), port_type: PortType::Input, port_name: "in".to_string() },
};
let graph = Graph::new(vec![node_a, node_b], vec![edge]);
assert!(graph.validate().is_empty());Implementations§
Source§impl Graph
impl Graph
Sourcepub fn new(nodes: Vec<Node>, edges: Vec<Edge>) -> Self
pub fn new(nodes: Vec<Node>, edges: Vec<Edge>) -> Self
Creates a new Graph from a list of nodes and edges.
Builds internal indexes for efficient edge lookups by source (tail) and target (head) ports.
Examples found in repository?
examples/linear_flow.rs (line 120)
108fn create_linear_graph() -> Graph {
109 let nodes = vec![
110 create_node("A", vec![], vec!["out"]),
111 create_node("B", vec!["in"], vec!["out"]),
112 create_node("C", vec!["in"], vec![]),
113 ];
114
115 let edges = vec![
116 create_edge("A", "out", "B", "in"),
117 create_edge("B", "out", "C", "in"),
118 ];
119
120 let graph = Graph::new(nodes, edges);
121 assert!(graph.validate().is_empty(), "Graph validation failed");
122 graph
123}More examples
examples/diamond_flow.rs (line 158)
103fn create_diamond_graph() -> Graph {
104 // Node A: source with two outputs
105 let node_a = Node {
106 name: "A".to_string(),
107 in_ports: HashMap::new(),
108 out_ports: [
109 ("out1".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
110 ("out2".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
111 ].into(),
112 in_salvo_conditions: HashMap::new(),
113 out_salvo_conditions: HashMap::new(),
114 };
115
116 // Node B: one input, one output
117 let node_b = create_simple_node("B");
118
119 // Node C: one input, one output
120 let node_c = create_simple_node("C");
121
122 // Node D: TWO inputs (requires both), no outputs
123 let node_d = Node {
124 name: "D".to_string(),
125 in_ports: [
126 ("in1".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
127 ("in2".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
128 ].into(),
129 out_ports: HashMap::new(),
130 in_salvo_conditions: [(
131 "default".to_string(),
132 SalvoCondition {
133 max_salvos: 1,
134 ports: vec!["in1".to_string(), "in2".to_string()],
135 // Require BOTH inputs to be non-empty
136 term: SalvoConditionTerm::And(vec![
137 SalvoConditionTerm::Port {
138 port_name: "in1".to_string(),
139 state: PortState::NonEmpty,
140 },
141 SalvoConditionTerm::Port {
142 port_name: "in2".to_string(),
143 state: PortState::NonEmpty,
144 },
145 ]),
146 },
147 )].into(),
148 out_salvo_conditions: HashMap::new(),
149 };
150
151 let edges = vec![
152 create_edge("A", "out1", "B", "in"),
153 create_edge("A", "out2", "C", "in"),
154 create_edge("B", "out", "D", "in1"),
155 create_edge("C", "out", "D", "in2"),
156 ];
157
158 let graph = Graph::new(vec![node_a, node_b, node_c, node_d], edges);
159 assert!(graph.validate().is_empty(), "Graph validation failed");
160 graph
161}Sourcepub fn nodes(&self) -> &HashMap<NodeName, Node>
pub fn nodes(&self) -> &HashMap<NodeName, Node>
Returns a reference to all nodes in the graph, keyed by name.
Examples found in repository?
examples/linear_flow.rs (line 22)
19fn main() {
20 // Create a linear graph: A -> B -> C
21 let graph = create_linear_graph();
22 println!("Created graph with {} nodes", graph.nodes().len());
23
24 // Create a network from the graph
25 let mut net = Net::new(graph);
26
27 // Create a packet outside the network
28 let packet_id = match net.do_action(&NetAction::CreatePacket(None)) {
29 NetActionResponse::Success(NetActionResponseData::Packet(id), _) => {
30 println!("Created packet: {}", id);
31 id
32 }
33 _ => panic!("Failed to create packet"),
34 };
35
36 // Transport packet to the edge A -> B
37 let edge_a_b = PacketLocation::Edge(Edge {
38 source: PortRef {
39 node_name: "A".to_string(),
40 port_type: PortType::Output,
41 port_name: "out".to_string(),
42 },
43 target: PortRef {
44 node_name: "B".to_string(),
45 port_type: PortType::Input,
46 port_name: "in".to_string(),
47 },
48 });
49 net.do_action(&NetAction::TransportPacketToLocation(packet_id.clone(), edge_a_b));
50 println!("Placed packet on edge A -> B");
51
52 // Run the network - packet moves to B's input port and triggers an epoch
53 net.do_action(&NetAction::RunNetUntilBlocked);
54 println!("Ran network until blocked");
55
56 // Check for startable epochs
57 let startable = net.get_startable_epochs();
58 println!("Startable epochs: {}", startable.len());
59
60 if let Some(epoch_id) = startable.first() {
61 // Start the epoch
62 match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
63 NetActionResponse::Success(NetActionResponseData::StartedEpoch(epoch), _) => {
64 println!("Started epoch {} on node {}", epoch.id, epoch.node_name);
65
66 // In a real scenario, external code would process the packet here
67 // For this example, we'll just consume it and create an output
68
69 // Consume the input packet
70 net.do_action(&NetAction::ConsumePacket(packet_id));
71 println!("Consumed input packet");
72
73 // Create an output packet
74 let output_packet = match net.do_action(&NetAction::CreatePacket(Some(epoch.id.clone()))) {
75 NetActionResponse::Success(NetActionResponseData::Packet(id), _) => id,
76 _ => panic!("Failed to create output packet"),
77 };
78 println!("Created output packet: {}", output_packet);
79
80 // Load it into the output port
81 net.do_action(&NetAction::LoadPacketIntoOutputPort(output_packet.clone(), "out".to_string()));
82 println!("Loaded packet into output port");
83
84 // Send the output salvo
85 net.do_action(&NetAction::SendOutputSalvo(epoch.id.clone(), "default".to_string()));
86 println!("Sent output salvo - packet is now on edge B -> C");
87
88 // Finish the epoch
89 net.do_action(&NetAction::FinishEpoch(epoch.id));
90 println!("Finished epoch");
91
92 // Run the network again - packet moves to C
93 net.do_action(&NetAction::RunNetUntilBlocked);
94 println!("Ran network until blocked again");
95
96 // Check for new startable epochs at C
97 let startable_c = net.get_startable_epochs();
98 println!("New startable epochs (should be at C): {}", startable_c.len());
99 }
100 _ => panic!("Failed to start epoch"),
101 }
102 }
103
104 println!("\nLinear flow example complete!");
105}Sourcepub fn get_edge_by_tail(&self, output_port_ref: &PortRef) -> Option<&Edge>
pub fn get_edge_by_tail(&self, output_port_ref: &PortRef) -> Option<&Edge>
Returns the edge that has the given output port as its source (tail).
Sourcepub fn get_edge_by_head(&self, input_port_ref: &PortRef) -> Option<&Edge>
pub fn get_edge_by_head(&self, input_port_ref: &PortRef) -> Option<&Edge>
Returns the edge that has the given input port as its target (head).
Sourcepub fn validate(&self) -> Vec<GraphValidationError>
pub fn validate(&self) -> Vec<GraphValidationError>
Validates the graph structure.
Returns a list of all validation errors found. An empty list means the graph is valid.
Examples found in repository?
examples/linear_flow.rs (line 121)
108fn create_linear_graph() -> Graph {
109 let nodes = vec![
110 create_node("A", vec![], vec!["out"]),
111 create_node("B", vec!["in"], vec!["out"]),
112 create_node("C", vec!["in"], vec![]),
113 ];
114
115 let edges = vec![
116 create_edge("A", "out", "B", "in"),
117 create_edge("B", "out", "C", "in"),
118 ];
119
120 let graph = Graph::new(nodes, edges);
121 assert!(graph.validate().is_empty(), "Graph validation failed");
122 graph
123}More examples
examples/diamond_flow.rs (line 159)
103fn create_diamond_graph() -> Graph {
104 // Node A: source with two outputs
105 let node_a = Node {
106 name: "A".to_string(),
107 in_ports: HashMap::new(),
108 out_ports: [
109 ("out1".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
110 ("out2".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
111 ].into(),
112 in_salvo_conditions: HashMap::new(),
113 out_salvo_conditions: HashMap::new(),
114 };
115
116 // Node B: one input, one output
117 let node_b = create_simple_node("B");
118
119 // Node C: one input, one output
120 let node_c = create_simple_node("C");
121
122 // Node D: TWO inputs (requires both), no outputs
123 let node_d = Node {
124 name: "D".to_string(),
125 in_ports: [
126 ("in1".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
127 ("in2".to_string(), Port { slots_spec: PortSlotSpec::Infinite }),
128 ].into(),
129 out_ports: HashMap::new(),
130 in_salvo_conditions: [(
131 "default".to_string(),
132 SalvoCondition {
133 max_salvos: 1,
134 ports: vec!["in1".to_string(), "in2".to_string()],
135 // Require BOTH inputs to be non-empty
136 term: SalvoConditionTerm::And(vec![
137 SalvoConditionTerm::Port {
138 port_name: "in1".to_string(),
139 state: PortState::NonEmpty,
140 },
141 SalvoConditionTerm::Port {
142 port_name: "in2".to_string(),
143 state: PortState::NonEmpty,
144 },
145 ]),
146 },
147 )].into(),
148 out_salvo_conditions: HashMap::new(),
149 };
150
151 let edges = vec![
152 create_edge("A", "out1", "B", "in"),
153 create_edge("A", "out2", "C", "in"),
154 create_edge("B", "out", "D", "in1"),
155 create_edge("C", "out", "D", "in2"),
156 ];
157
158 let graph = Graph::new(vec![node_a, node_b, node_c, node_d], edges);
159 assert!(graph.validate().is_empty(), "Graph validation failed");
160 graph
161}Trait Implementations§
Auto Trait Implementations§
impl Freeze for Graph
impl RefUnwindSafe for Graph
impl Send for Graph
impl Sync for Graph
impl Unpin for Graph
impl UnwindSafe for Graph
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more