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