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 indexmap::IndexMap;
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: IndexMap::new(),
out_salvo_conditions: IndexMap::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: IndexMap::new(),
out_salvo_conditions: IndexMap::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 134)
122fn create_linear_graph() -> Graph {
123 let nodes = vec![
124 create_node("A", vec![], vec!["out"]),
125 create_node("B", vec!["in"], vec!["out"]),
126 create_node("C", vec!["in"], vec![]),
127 ];
128
129 let edges = vec![
130 create_edge("A", "out", "B", "in"),
131 create_edge("B", "out", "C", "in"),
132 ];
133
134 let graph = Graph::new(nodes, edges);
135 assert!(graph.validate().is_empty(), "Graph validation failed");
136 graph
137}More examples
examples/diamond_flow.rs (line 204)
122fn create_diamond_graph() -> Graph {
123 // Node A: source with two outputs
124 let node_a = Node {
125 name: "A".to_string(),
126 in_ports: HashMap::new(),
127 out_ports: [
128 (
129 "out1".to_string(),
130 Port {
131 slots_spec: PortSlotSpec::Infinite,
132 },
133 ),
134 (
135 "out2".to_string(),
136 Port {
137 slots_spec: PortSlotSpec::Infinite,
138 },
139 ),
140 ]
141 .into(),
142 in_salvo_conditions: IndexMap::new(),
143 out_salvo_conditions: IndexMap::new(),
144 };
145
146 // Node B: one input, one output
147 let node_b = create_simple_node("B");
148
149 // Node C: one input, one output
150 let node_c = create_simple_node("C");
151
152 // Node D: TWO inputs (requires both), no outputs
153 let node_d = Node {
154 name: "D".to_string(),
155 in_ports: [
156 (
157 "in1".to_string(),
158 Port {
159 slots_spec: PortSlotSpec::Infinite,
160 },
161 ),
162 (
163 "in2".to_string(),
164 Port {
165 slots_spec: PortSlotSpec::Infinite,
166 },
167 ),
168 ]
169 .into(),
170 out_ports: HashMap::new(),
171 in_salvo_conditions: IndexMap::from([(
172 "default".to_string(),
173 SalvoCondition {
174 max_salvos: MaxSalvos::Finite(1),
175 ports: [
176 ("in1".to_string(), PacketCount::All),
177 ("in2".to_string(), PacketCount::All),
178 ]
179 .into_iter()
180 .collect(),
181 // Require BOTH inputs to be non-empty
182 term: SalvoConditionTerm::And(vec![
183 SalvoConditionTerm::Port {
184 port_name: "in1".to_string(),
185 state: PortState::NonEmpty,
186 },
187 SalvoConditionTerm::Port {
188 port_name: "in2".to_string(),
189 state: PortState::NonEmpty,
190 },
191 ]),
192 },
193 )]),
194 out_salvo_conditions: IndexMap::new(),
195 };
196
197 let edges = vec![
198 create_edge("A", "out1", "B", "in"),
199 create_edge("A", "out2", "C", "in"),
200 create_edge("B", "out", "D", "in1"),
201 create_edge("C", "out", "D", "in2"),
202 ];
203
204 let graph = Graph::new(vec![node_a, node_b, node_c, node_d], edges);
205 assert!(graph.validate().is_empty(), "Graph validation failed");
206 graph
207}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 23)
20fn main() {
21 // Create a linear graph: A -> B -> C
22 let graph = create_linear_graph();
23 println!("Created graph with {} nodes", graph.nodes().len());
24
25 // Create a network from the graph
26 let mut net = NetSim::new(graph);
27
28 // Create a packet outside the network
29 let packet_id = match net.do_action(&NetAction::CreatePacket(None)) {
30 NetActionResponse::Success(NetActionResponseData::Packet(id), _) => {
31 println!("Created packet: {}", id);
32 id
33 }
34 _ => panic!("Failed to create packet"),
35 };
36
37 // Transport packet to the edge A -> B
38 let edge_a_b = PacketLocation::Edge(Edge {
39 source: PortRef {
40 node_name: "A".to_string(),
41 port_type: PortType::Output,
42 port_name: "out".to_string(),
43 },
44 target: PortRef {
45 node_name: "B".to_string(),
46 port_type: PortType::Input,
47 port_name: "in".to_string(),
48 },
49 });
50 net.do_action(&NetAction::TransportPacketToLocation(
51 packet_id.clone(),
52 edge_a_b,
53 ));
54 println!("Placed packet on edge A -> B");
55
56 // Run the network - packet moves to B's input port and triggers an epoch
57 net.run_until_blocked();
58 println!("Ran network until blocked");
59
60 // Check for startable epochs
61 let startable = net.get_startable_epochs();
62 println!("Startable epochs: {}", startable.len());
63
64 if let Some(epoch_id) = startable.first() {
65 // Start the epoch
66 match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
67 NetActionResponse::Success(NetActionResponseData::StartedEpoch(epoch), _) => {
68 println!("Started epoch {} on node {}", epoch.id, epoch.node_name);
69
70 // In a real scenario, external code would process the packet here
71 // For this example, we'll just consume it and create an output
72
73 // Consume the input packet
74 net.do_action(&NetAction::ConsumePacket(packet_id));
75 println!("Consumed input packet");
76
77 // Create an output packet
78 let output_packet =
79 match net.do_action(&NetAction::CreatePacket(Some(epoch.id.clone()))) {
80 NetActionResponse::Success(NetActionResponseData::Packet(id), _) => id,
81 _ => panic!("Failed to create output packet"),
82 };
83 println!("Created output packet: {}", output_packet);
84
85 // Load it into the output port
86 net.do_action(&NetAction::LoadPacketIntoOutputPort(
87 output_packet.clone(),
88 "out".to_string(),
89 ));
90 println!("Loaded packet into output port");
91
92 // Send the output salvo
93 net.do_action(&NetAction::SendOutputSalvo(
94 epoch.id.clone(),
95 "default".to_string(),
96 ));
97 println!("Sent output salvo - packet is now on edge B -> C");
98
99 // Finish the epoch
100 net.do_action(&NetAction::FinishEpoch(epoch.id));
101 println!("Finished epoch");
102
103 // Run the network again - packet moves to C
104 net.run_until_blocked();
105 println!("Ran network until blocked again");
106
107 // Check for new startable epochs at C
108 let startable_c = net.get_startable_epochs();
109 println!(
110 "New startable epochs (should be at C): {}",
111 startable_c.len()
112 );
113 }
114 _ => panic!("Failed to start epoch"),
115 }
116 }
117
118 println!("\nLinear flow example complete!");
119}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_edges_by_head(&self, input_port_ref: &PortRef) -> &[Edge]
pub fn get_edges_by_head(&self, input_port_ref: &PortRef) -> &[Edge]
Returns all edges that have the given input port as their target (head). Fan-in is allowed, so multiple edges can connect to the same input port.
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 135)
122fn create_linear_graph() -> Graph {
123 let nodes = vec![
124 create_node("A", vec![], vec!["out"]),
125 create_node("B", vec!["in"], vec!["out"]),
126 create_node("C", vec!["in"], vec![]),
127 ];
128
129 let edges = vec![
130 create_edge("A", "out", "B", "in"),
131 create_edge("B", "out", "C", "in"),
132 ];
133
134 let graph = Graph::new(nodes, edges);
135 assert!(graph.validate().is_empty(), "Graph validation failed");
136 graph
137}More examples
examples/diamond_flow.rs (line 205)
122fn create_diamond_graph() -> Graph {
123 // Node A: source with two outputs
124 let node_a = Node {
125 name: "A".to_string(),
126 in_ports: HashMap::new(),
127 out_ports: [
128 (
129 "out1".to_string(),
130 Port {
131 slots_spec: PortSlotSpec::Infinite,
132 },
133 ),
134 (
135 "out2".to_string(),
136 Port {
137 slots_spec: PortSlotSpec::Infinite,
138 },
139 ),
140 ]
141 .into(),
142 in_salvo_conditions: IndexMap::new(),
143 out_salvo_conditions: IndexMap::new(),
144 };
145
146 // Node B: one input, one output
147 let node_b = create_simple_node("B");
148
149 // Node C: one input, one output
150 let node_c = create_simple_node("C");
151
152 // Node D: TWO inputs (requires both), no outputs
153 let node_d = Node {
154 name: "D".to_string(),
155 in_ports: [
156 (
157 "in1".to_string(),
158 Port {
159 slots_spec: PortSlotSpec::Infinite,
160 },
161 ),
162 (
163 "in2".to_string(),
164 Port {
165 slots_spec: PortSlotSpec::Infinite,
166 },
167 ),
168 ]
169 .into(),
170 out_ports: HashMap::new(),
171 in_salvo_conditions: IndexMap::from([(
172 "default".to_string(),
173 SalvoCondition {
174 max_salvos: MaxSalvos::Finite(1),
175 ports: [
176 ("in1".to_string(), PacketCount::All),
177 ("in2".to_string(), PacketCount::All),
178 ]
179 .into_iter()
180 .collect(),
181 // Require BOTH inputs to be non-empty
182 term: SalvoConditionTerm::And(vec![
183 SalvoConditionTerm::Port {
184 port_name: "in1".to_string(),
185 state: PortState::NonEmpty,
186 },
187 SalvoConditionTerm::Port {
188 port_name: "in2".to_string(),
189 state: PortState::NonEmpty,
190 },
191 ]),
192 },
193 )]),
194 out_salvo_conditions: IndexMap::new(),
195 };
196
197 let edges = vec![
198 create_edge("A", "out1", "B", "in"),
199 create_edge("A", "out2", "C", "in"),
200 create_edge("B", "out", "D", "in1"),
201 create_edge("C", "out", "D", "in2"),
202 ];
203
204 let graph = Graph::new(vec![node_a, node_b, node_c, node_d], edges);
205 assert!(graph.validate().is_empty(), "Graph validation failed");
206 graph
207}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