pub struct NetSim {
pub graph: Graph,
/* private fields */
}Expand description
The runtime state of a flow-based network.
A NetSim is created from a Graph and tracks:
- All packets and their locations
- All epochs and their states
- Which epochs are startable
All mutations must go through NetSim::do_action to ensure proper event tracking.
Fields§
§graph: GraphThe graph topology this network is running on.
Implementations§
Source§impl NetSim
impl NetSim
Sourcepub fn new(graph: Graph) -> Self
pub fn new(graph: Graph) -> Self
Creates a new net simulation from a Graph.
Initializes packet location tracking for all edges and input ports.
Examples found in repository?
25fn main() {
26 // Create a diamond graph
27 let graph = create_diamond_graph();
28 println!("Created diamond graph: A -> B,C -> D");
29 println!("D requires inputs from BOTH B and C\n");
30
31 let mut net = NetSim::new(graph);
32
33 // Create two packets and place them on edges from A
34 let packet1 = create_packet(&mut net);
35 let packet2 = create_packet(&mut net);
36 println!("Created packets: {} and {}", packet1, packet2);
37
38 // Place packet1 on edge A -> B
39 let edge_a_b = edge_location("A", "out1", "B", "in");
40 net.do_action(&NetAction::TransportPacketToLocation(
41 packet1.clone(),
42 edge_a_b,
43 ));
44 println!("Placed packet1 on edge A -> B");
45
46 // Place packet2 on edge A -> C
47 let edge_a_c = edge_location("A", "out2", "C", "in");
48 net.do_action(&NetAction::TransportPacketToLocation(
49 packet2.clone(),
50 edge_a_c,
51 ));
52 println!("Placed packet2 on edge A -> C");
53
54 // Run network - packets move to B and C, triggering epochs
55 net.run_until_blocked();
56
57 let startable = net.get_startable_epochs();
58 println!(
59 "\nAfter first run: {} startable epochs (B and C)",
60 startable.len()
61 );
62
63 // Process B and C, sending outputs to D
64 for epoch_id in startable {
65 let epoch = net.get_epoch(&epoch_id).unwrap();
66 let node_name = epoch.node_name.clone();
67 println!("\nProcessing node {}", node_name);
68
69 // Start the epoch
70 let started = match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
71 NetActionResponse::Success(NetActionResponseData::StartedEpoch(e), _) => e,
72 _ => panic!("Failed to start epoch"),
73 };
74
75 // Find and consume the input packet
76 let input_packet = started.in_salvo.packets[0].1.clone();
77 net.do_action(&NetAction::ConsumePacket(input_packet));
78
79 // Create output packet
80 let output = create_packet_in_epoch(&mut net, &started.id);
81
82 // Load into output port and send
83 net.do_action(&NetAction::LoadPacketIntoOutputPort(
84 output,
85 "out".to_string(),
86 ));
87 net.do_action(&NetAction::SendOutputSalvo(
88 started.id.clone(),
89 "default".to_string(),
90 ));
91
92 // Finish epoch
93 net.do_action(&NetAction::FinishEpoch(started.id));
94 println!(" Finished {} - sent packet to D", node_name);
95 }
96
97 // Run network - packets move from B->D and C->D edges to D's input ports
98 net.run_until_blocked();
99
100 // Check D's input ports
101 let d_in1 = PacketLocation::InputPort("D".to_string(), "in1".to_string());
102 let d_in2 = PacketLocation::InputPort("D".to_string(), "in2".to_string());
103 println!("\nD's input ports:");
104 println!(" in1 (from B): {} packets", net.packet_count_at(&d_in1));
105 println!(" in2 (from C): {} packets", net.packet_count_at(&d_in2));
106
107 // D should now have a startable epoch (both inputs present)
108 let startable_d = net.get_startable_epochs();
109 println!("\nStartable epochs at D: {}", startable_d.len());
110
111 if let Some(d_epoch_id) = startable_d.first() {
112 let d_epoch = net.get_epoch(d_epoch_id).unwrap();
113 println!(
114 "D's epoch received {} packets from both branches!",
115 d_epoch.in_salvo.packets.len()
116 );
117 }
118
119 println!("\nDiamond flow example complete!");
120}More examples
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 do_action(&mut self, action: &NetAction) -> NetActionResponse
pub fn do_action(&mut self, action: &NetAction) -> NetActionResponse
Perform an action on the network.
This is the primary way to mutate the network state. All actions produce a response containing either success data and events, or an error.
§Example
use netrun_sim::net::{NetSim, NetAction, NetActionResponse, NetActionResponseData};
use netrun_sim::graph::{Graph, Node, Port, PortSlotSpec};
use indexmap::IndexMap;
use std::collections::HashMap;
let node = Node {
name: "A".to_string(),
in_ports: HashMap::new(),
out_ports: HashMap::new(),
in_salvo_conditions: IndexMap::new(),
out_salvo_conditions: IndexMap::new(),
dependency_request_config: None,
};
let graph = Graph::new(vec![node], vec![]);
let mut net = NetSim::new(graph);
// Create a packet outside the network
let response = net.do_action(&NetAction::CreatePacket(None));
match response {
NetActionResponse::Success(NetActionResponseData::Packet(id), events) => {
println!("Created packet {}", id);
}
_ => panic!("Expected success"),
}Examples found in repository?
25fn main() {
26 // Create a diamond graph
27 let graph = create_diamond_graph();
28 println!("Created diamond graph: A -> B,C -> D");
29 println!("D requires inputs from BOTH B and C\n");
30
31 let mut net = NetSim::new(graph);
32
33 // Create two packets and place them on edges from A
34 let packet1 = create_packet(&mut net);
35 let packet2 = create_packet(&mut net);
36 println!("Created packets: {} and {}", packet1, packet2);
37
38 // Place packet1 on edge A -> B
39 let edge_a_b = edge_location("A", "out1", "B", "in");
40 net.do_action(&NetAction::TransportPacketToLocation(
41 packet1.clone(),
42 edge_a_b,
43 ));
44 println!("Placed packet1 on edge A -> B");
45
46 // Place packet2 on edge A -> C
47 let edge_a_c = edge_location("A", "out2", "C", "in");
48 net.do_action(&NetAction::TransportPacketToLocation(
49 packet2.clone(),
50 edge_a_c,
51 ));
52 println!("Placed packet2 on edge A -> C");
53
54 // Run network - packets move to B and C, triggering epochs
55 net.run_until_blocked();
56
57 let startable = net.get_startable_epochs();
58 println!(
59 "\nAfter first run: {} startable epochs (B and C)",
60 startable.len()
61 );
62
63 // Process B and C, sending outputs to D
64 for epoch_id in startable {
65 let epoch = net.get_epoch(&epoch_id).unwrap();
66 let node_name = epoch.node_name.clone();
67 println!("\nProcessing node {}", node_name);
68
69 // Start the epoch
70 let started = match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
71 NetActionResponse::Success(NetActionResponseData::StartedEpoch(e), _) => e,
72 _ => panic!("Failed to start epoch"),
73 };
74
75 // Find and consume the input packet
76 let input_packet = started.in_salvo.packets[0].1.clone();
77 net.do_action(&NetAction::ConsumePacket(input_packet));
78
79 // Create output packet
80 let output = create_packet_in_epoch(&mut net, &started.id);
81
82 // Load into output port and send
83 net.do_action(&NetAction::LoadPacketIntoOutputPort(
84 output,
85 "out".to_string(),
86 ));
87 net.do_action(&NetAction::SendOutputSalvo(
88 started.id.clone(),
89 "default".to_string(),
90 ));
91
92 // Finish epoch
93 net.do_action(&NetAction::FinishEpoch(started.id));
94 println!(" Finished {} - sent packet to D", node_name);
95 }
96
97 // Run network - packets move from B->D and C->D edges to D's input ports
98 net.run_until_blocked();
99
100 // Check D's input ports
101 let d_in1 = PacketLocation::InputPort("D".to_string(), "in1".to_string());
102 let d_in2 = PacketLocation::InputPort("D".to_string(), "in2".to_string());
103 println!("\nD's input ports:");
104 println!(" in1 (from B): {} packets", net.packet_count_at(&d_in1));
105 println!(" in2 (from C): {} packets", net.packet_count_at(&d_in2));
106
107 // D should now have a startable epoch (both inputs present)
108 let startable_d = net.get_startable_epochs();
109 println!("\nStartable epochs at D: {}", startable_d.len());
110
111 if let Some(d_epoch_id) = startable_d.first() {
112 let d_epoch = net.get_epoch(d_epoch_id).unwrap();
113 println!(
114 "D's epoch received {} packets from both branches!",
115 d_epoch.in_salvo.packets.len()
116 );
117 }
118
119 println!("\nDiamond flow example complete!");
120}
121
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 dependency_request_config: None,
145 };
146
147 // Node B: one input, one output
148 let node_b = create_simple_node("B");
149
150 // Node C: one input, one output
151 let node_c = create_simple_node("C");
152
153 // Node D: TWO inputs (requires both), no outputs
154 let node_d = Node {
155 name: "D".to_string(),
156 in_ports: [
157 (
158 "in1".to_string(),
159 Port {
160 slots_spec: PortSlotSpec::Infinite,
161 },
162 ),
163 (
164 "in2".to_string(),
165 Port {
166 slots_spec: PortSlotSpec::Infinite,
167 },
168 ),
169 ]
170 .into(),
171 out_ports: HashMap::new(),
172 in_salvo_conditions: IndexMap::from([(
173 "default".to_string(),
174 SalvoCondition {
175 max_salvos: MaxSalvos::Finite(1),
176 ports: [
177 ("in1".to_string(), PacketCount::All),
178 ("in2".to_string(), PacketCount::All),
179 ]
180 .into_iter()
181 .collect(),
182 // Require BOTH inputs to be non-empty
183 term: SalvoConditionTerm::And(vec![
184 SalvoConditionTerm::Port {
185 port_name: "in1".to_string(),
186 state: PortState::NonEmpty,
187 },
188 SalvoConditionTerm::Port {
189 port_name: "in2".to_string(),
190 state: PortState::NonEmpty,
191 },
192 ]),
193 },
194 )]),
195 out_salvo_conditions: IndexMap::new(),
196 dependency_request_config: None,
197 };
198
199 let edges = vec![
200 create_edge("A", "out1", "B", "in"),
201 create_edge("A", "out2", "C", "in"),
202 create_edge("B", "out", "D", "in1"),
203 create_edge("C", "out", "D", "in2"),
204 ];
205
206 let graph = Graph::new(vec![node_a, node_b, node_c, node_d], edges);
207 assert!(graph.validate().is_empty(), "Graph validation failed");
208 graph
209}
210
211fn create_simple_node(name: &str) -> Node {
212 Node {
213 name: name.to_string(),
214 in_ports: [(
215 "in".to_string(),
216 Port {
217 slots_spec: PortSlotSpec::Infinite,
218 },
219 )]
220 .into(),
221 out_ports: [(
222 "out".to_string(),
223 Port {
224 slots_spec: PortSlotSpec::Infinite,
225 },
226 )]
227 .into(),
228 in_salvo_conditions: IndexMap::from([(
229 "default".to_string(),
230 SalvoCondition {
231 max_salvos: MaxSalvos::Finite(1),
232 ports: [("in".to_string(), PacketCount::All)].into_iter().collect(),
233 term: SalvoConditionTerm::Port {
234 port_name: "in".to_string(),
235 state: PortState::NonEmpty,
236 },
237 },
238 )]),
239 out_salvo_conditions: IndexMap::from([(
240 "default".to_string(),
241 SalvoCondition {
242 max_salvos: MaxSalvos::Infinite,
243 ports: [("out".to_string(), PacketCount::All)]
244 .into_iter()
245 .collect(),
246 term: SalvoConditionTerm::Port {
247 port_name: "out".to_string(),
248 state: PortState::NonEmpty,
249 },
250 },
251 )]),
252 dependency_request_config: None,
253 }
254}
255
256fn create_edge(src_node: &str, src_port: &str, tgt_node: &str, tgt_port: &str) -> Edge {
257 Edge {
258 source: PortRef {
259 node_name: src_node.to_string(),
260 port_type: PortType::Output,
261 port_name: src_port.to_string(),
262 },
263 target: PortRef {
264 node_name: tgt_node.to_string(),
265 port_type: PortType::Input,
266 port_name: tgt_port.to_string(),
267 },
268 }
269}
270
271fn edge_location(src_node: &str, src_port: &str, tgt_node: &str, tgt_port: &str) -> PacketLocation {
272 PacketLocation::Edge(Edge {
273 source: PortRef {
274 node_name: src_node.to_string(),
275 port_type: PortType::Output,
276 port_name: src_port.to_string(),
277 },
278 target: PortRef {
279 node_name: tgt_node.to_string(),
280 port_type: PortType::Input,
281 port_name: tgt_port.to_string(),
282 },
283 })
284}
285
286fn create_packet(net: &mut NetSim) -> ulid::Ulid {
287 match net.do_action(&NetAction::CreatePacket(None)) {
288 NetActionResponse::Success(NetActionResponseData::Packet(id), _) => id,
289 _ => panic!("Failed to create packet"),
290 }
291}
292
293fn create_packet_in_epoch(net: &mut NetSim, epoch_id: &ulid::Ulid) -> ulid::Ulid {
294 match net.do_action(&NetAction::CreatePacket(Some(epoch_id.clone()))) {
295 NetActionResponse::Success(NetActionResponseData::Packet(id), _) => id,
296 _ => panic!("Failed to create packet in epoch"),
297 }
298}More examples
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 packet_count_at(&self, location: &PacketLocation) -> usize
pub fn packet_count_at(&self, location: &PacketLocation) -> usize
Get the number of packets at a given location.
Examples found in repository?
25fn main() {
26 // Create a diamond graph
27 let graph = create_diamond_graph();
28 println!("Created diamond graph: A -> B,C -> D");
29 println!("D requires inputs from BOTH B and C\n");
30
31 let mut net = NetSim::new(graph);
32
33 // Create two packets and place them on edges from A
34 let packet1 = create_packet(&mut net);
35 let packet2 = create_packet(&mut net);
36 println!("Created packets: {} and {}", packet1, packet2);
37
38 // Place packet1 on edge A -> B
39 let edge_a_b = edge_location("A", "out1", "B", "in");
40 net.do_action(&NetAction::TransportPacketToLocation(
41 packet1.clone(),
42 edge_a_b,
43 ));
44 println!("Placed packet1 on edge A -> B");
45
46 // Place packet2 on edge A -> C
47 let edge_a_c = edge_location("A", "out2", "C", "in");
48 net.do_action(&NetAction::TransportPacketToLocation(
49 packet2.clone(),
50 edge_a_c,
51 ));
52 println!("Placed packet2 on edge A -> C");
53
54 // Run network - packets move to B and C, triggering epochs
55 net.run_until_blocked();
56
57 let startable = net.get_startable_epochs();
58 println!(
59 "\nAfter first run: {} startable epochs (B and C)",
60 startable.len()
61 );
62
63 // Process B and C, sending outputs to D
64 for epoch_id in startable {
65 let epoch = net.get_epoch(&epoch_id).unwrap();
66 let node_name = epoch.node_name.clone();
67 println!("\nProcessing node {}", node_name);
68
69 // Start the epoch
70 let started = match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
71 NetActionResponse::Success(NetActionResponseData::StartedEpoch(e), _) => e,
72 _ => panic!("Failed to start epoch"),
73 };
74
75 // Find and consume the input packet
76 let input_packet = started.in_salvo.packets[0].1.clone();
77 net.do_action(&NetAction::ConsumePacket(input_packet));
78
79 // Create output packet
80 let output = create_packet_in_epoch(&mut net, &started.id);
81
82 // Load into output port and send
83 net.do_action(&NetAction::LoadPacketIntoOutputPort(
84 output,
85 "out".to_string(),
86 ));
87 net.do_action(&NetAction::SendOutputSalvo(
88 started.id.clone(),
89 "default".to_string(),
90 ));
91
92 // Finish epoch
93 net.do_action(&NetAction::FinishEpoch(started.id));
94 println!(" Finished {} - sent packet to D", node_name);
95 }
96
97 // Run network - packets move from B->D and C->D edges to D's input ports
98 net.run_until_blocked();
99
100 // Check D's input ports
101 let d_in1 = PacketLocation::InputPort("D".to_string(), "in1".to_string());
102 let d_in2 = PacketLocation::InputPort("D".to_string(), "in2".to_string());
103 println!("\nD's input ports:");
104 println!(" in1 (from B): {} packets", net.packet_count_at(&d_in1));
105 println!(" in2 (from C): {} packets", net.packet_count_at(&d_in2));
106
107 // D should now have a startable epoch (both inputs present)
108 let startable_d = net.get_startable_epochs();
109 println!("\nStartable epochs at D: {}", startable_d.len());
110
111 if let Some(d_epoch_id) = startable_d.first() {
112 let d_epoch = net.get_epoch(d_epoch_id).unwrap();
113 println!(
114 "D's epoch received {} packets from both branches!",
115 d_epoch.in_salvo.packets.len()
116 );
117 }
118
119 println!("\nDiamond flow example complete!");
120}Sourcepub fn get_packets_at_location(
&self,
location: &PacketLocation,
) -> Vec<PacketID> ⓘ
pub fn get_packets_at_location( &self, location: &PacketLocation, ) -> Vec<PacketID> ⓘ
Get all packets at a given location.
Sourcepub fn get_epoch(&self, epoch_id: &EpochID) -> Option<&Epoch>
pub fn get_epoch(&self, epoch_id: &EpochID) -> Option<&Epoch>
Get an epoch by ID.
Examples found in repository?
25fn main() {
26 // Create a diamond graph
27 let graph = create_diamond_graph();
28 println!("Created diamond graph: A -> B,C -> D");
29 println!("D requires inputs from BOTH B and C\n");
30
31 let mut net = NetSim::new(graph);
32
33 // Create two packets and place them on edges from A
34 let packet1 = create_packet(&mut net);
35 let packet2 = create_packet(&mut net);
36 println!("Created packets: {} and {}", packet1, packet2);
37
38 // Place packet1 on edge A -> B
39 let edge_a_b = edge_location("A", "out1", "B", "in");
40 net.do_action(&NetAction::TransportPacketToLocation(
41 packet1.clone(),
42 edge_a_b,
43 ));
44 println!("Placed packet1 on edge A -> B");
45
46 // Place packet2 on edge A -> C
47 let edge_a_c = edge_location("A", "out2", "C", "in");
48 net.do_action(&NetAction::TransportPacketToLocation(
49 packet2.clone(),
50 edge_a_c,
51 ));
52 println!("Placed packet2 on edge A -> C");
53
54 // Run network - packets move to B and C, triggering epochs
55 net.run_until_blocked();
56
57 let startable = net.get_startable_epochs();
58 println!(
59 "\nAfter first run: {} startable epochs (B and C)",
60 startable.len()
61 );
62
63 // Process B and C, sending outputs to D
64 for epoch_id in startable {
65 let epoch = net.get_epoch(&epoch_id).unwrap();
66 let node_name = epoch.node_name.clone();
67 println!("\nProcessing node {}", node_name);
68
69 // Start the epoch
70 let started = match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
71 NetActionResponse::Success(NetActionResponseData::StartedEpoch(e), _) => e,
72 _ => panic!("Failed to start epoch"),
73 };
74
75 // Find and consume the input packet
76 let input_packet = started.in_salvo.packets[0].1.clone();
77 net.do_action(&NetAction::ConsumePacket(input_packet));
78
79 // Create output packet
80 let output = create_packet_in_epoch(&mut net, &started.id);
81
82 // Load into output port and send
83 net.do_action(&NetAction::LoadPacketIntoOutputPort(
84 output,
85 "out".to_string(),
86 ));
87 net.do_action(&NetAction::SendOutputSalvo(
88 started.id.clone(),
89 "default".to_string(),
90 ));
91
92 // Finish epoch
93 net.do_action(&NetAction::FinishEpoch(started.id));
94 println!(" Finished {} - sent packet to D", node_name);
95 }
96
97 // Run network - packets move from B->D and C->D edges to D's input ports
98 net.run_until_blocked();
99
100 // Check D's input ports
101 let d_in1 = PacketLocation::InputPort("D".to_string(), "in1".to_string());
102 let d_in2 = PacketLocation::InputPort("D".to_string(), "in2".to_string());
103 println!("\nD's input ports:");
104 println!(" in1 (from B): {} packets", net.packet_count_at(&d_in1));
105 println!(" in2 (from C): {} packets", net.packet_count_at(&d_in2));
106
107 // D should now have a startable epoch (both inputs present)
108 let startable_d = net.get_startable_epochs();
109 println!("\nStartable epochs at D: {}", startable_d.len());
110
111 if let Some(d_epoch_id) = startable_d.first() {
112 let d_epoch = net.get_epoch(d_epoch_id).unwrap();
113 println!(
114 "D's epoch received {} packets from both branches!",
115 d_epoch.in_salvo.packets.len()
116 );
117 }
118
119 println!("\nDiamond flow example complete!");
120}Sourcepub fn get_startable_epochs(&self) -> Vec<EpochID> ⓘ
pub fn get_startable_epochs(&self) -> Vec<EpochID> ⓘ
Get all startable epoch IDs.
Examples found in repository?
25fn main() {
26 // Create a diamond graph
27 let graph = create_diamond_graph();
28 println!("Created diamond graph: A -> B,C -> D");
29 println!("D requires inputs from BOTH B and C\n");
30
31 let mut net = NetSim::new(graph);
32
33 // Create two packets and place them on edges from A
34 let packet1 = create_packet(&mut net);
35 let packet2 = create_packet(&mut net);
36 println!("Created packets: {} and {}", packet1, packet2);
37
38 // Place packet1 on edge A -> B
39 let edge_a_b = edge_location("A", "out1", "B", "in");
40 net.do_action(&NetAction::TransportPacketToLocation(
41 packet1.clone(),
42 edge_a_b,
43 ));
44 println!("Placed packet1 on edge A -> B");
45
46 // Place packet2 on edge A -> C
47 let edge_a_c = edge_location("A", "out2", "C", "in");
48 net.do_action(&NetAction::TransportPacketToLocation(
49 packet2.clone(),
50 edge_a_c,
51 ));
52 println!("Placed packet2 on edge A -> C");
53
54 // Run network - packets move to B and C, triggering epochs
55 net.run_until_blocked();
56
57 let startable = net.get_startable_epochs();
58 println!(
59 "\nAfter first run: {} startable epochs (B and C)",
60 startable.len()
61 );
62
63 // Process B and C, sending outputs to D
64 for epoch_id in startable {
65 let epoch = net.get_epoch(&epoch_id).unwrap();
66 let node_name = epoch.node_name.clone();
67 println!("\nProcessing node {}", node_name);
68
69 // Start the epoch
70 let started = match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
71 NetActionResponse::Success(NetActionResponseData::StartedEpoch(e), _) => e,
72 _ => panic!("Failed to start epoch"),
73 };
74
75 // Find and consume the input packet
76 let input_packet = started.in_salvo.packets[0].1.clone();
77 net.do_action(&NetAction::ConsumePacket(input_packet));
78
79 // Create output packet
80 let output = create_packet_in_epoch(&mut net, &started.id);
81
82 // Load into output port and send
83 net.do_action(&NetAction::LoadPacketIntoOutputPort(
84 output,
85 "out".to_string(),
86 ));
87 net.do_action(&NetAction::SendOutputSalvo(
88 started.id.clone(),
89 "default".to_string(),
90 ));
91
92 // Finish epoch
93 net.do_action(&NetAction::FinishEpoch(started.id));
94 println!(" Finished {} - sent packet to D", node_name);
95 }
96
97 // Run network - packets move from B->D and C->D edges to D's input ports
98 net.run_until_blocked();
99
100 // Check D's input ports
101 let d_in1 = PacketLocation::InputPort("D".to_string(), "in1".to_string());
102 let d_in2 = PacketLocation::InputPort("D".to_string(), "in2".to_string());
103 println!("\nD's input ports:");
104 println!(" in1 (from B): {} packets", net.packet_count_at(&d_in1));
105 println!(" in2 (from C): {} packets", net.packet_count_at(&d_in2));
106
107 // D should now have a startable epoch (both inputs present)
108 let startable_d = net.get_startable_epochs();
109 println!("\nStartable epochs at D: {}", startable_d.len());
110
111 if let Some(d_epoch_id) = startable_d.first() {
112 let d_epoch = net.get_epoch(d_epoch_id).unwrap();
113 println!(
114 "D's epoch received {} packets from both branches!",
115 d_epoch.in_salvo.packets.len()
116 );
117 }
118
119 println!("\nDiamond flow example complete!");
120}More examples
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_packet(&self, packet_id: &PacketID) -> Option<&Packet>
pub fn get_packet(&self, packet_id: &PacketID) -> Option<&Packet>
Get a packet by ID.
Sourcepub fn run_until_blocked(&mut self) -> Vec<NetEvent>
pub fn run_until_blocked(&mut self) -> Vec<NetEvent>
Run the network until blocked, returning all events that occurred.
This is a convenience method that repeatedly calls RunStep until no more
progress can be made. Equivalent to:
while !net.is_blocked() {
net.do_action(&NetAction::RunStep);
}Examples found in repository?
25fn main() {
26 // Create a diamond graph
27 let graph = create_diamond_graph();
28 println!("Created diamond graph: A -> B,C -> D");
29 println!("D requires inputs from BOTH B and C\n");
30
31 let mut net = NetSim::new(graph);
32
33 // Create two packets and place them on edges from A
34 let packet1 = create_packet(&mut net);
35 let packet2 = create_packet(&mut net);
36 println!("Created packets: {} and {}", packet1, packet2);
37
38 // Place packet1 on edge A -> B
39 let edge_a_b = edge_location("A", "out1", "B", "in");
40 net.do_action(&NetAction::TransportPacketToLocation(
41 packet1.clone(),
42 edge_a_b,
43 ));
44 println!("Placed packet1 on edge A -> B");
45
46 // Place packet2 on edge A -> C
47 let edge_a_c = edge_location("A", "out2", "C", "in");
48 net.do_action(&NetAction::TransportPacketToLocation(
49 packet2.clone(),
50 edge_a_c,
51 ));
52 println!("Placed packet2 on edge A -> C");
53
54 // Run network - packets move to B and C, triggering epochs
55 net.run_until_blocked();
56
57 let startable = net.get_startable_epochs();
58 println!(
59 "\nAfter first run: {} startable epochs (B and C)",
60 startable.len()
61 );
62
63 // Process B and C, sending outputs to D
64 for epoch_id in startable {
65 let epoch = net.get_epoch(&epoch_id).unwrap();
66 let node_name = epoch.node_name.clone();
67 println!("\nProcessing node {}", node_name);
68
69 // Start the epoch
70 let started = match net.do_action(&NetAction::StartEpoch(epoch_id.clone())) {
71 NetActionResponse::Success(NetActionResponseData::StartedEpoch(e), _) => e,
72 _ => panic!("Failed to start epoch"),
73 };
74
75 // Find and consume the input packet
76 let input_packet = started.in_salvo.packets[0].1.clone();
77 net.do_action(&NetAction::ConsumePacket(input_packet));
78
79 // Create output packet
80 let output = create_packet_in_epoch(&mut net, &started.id);
81
82 // Load into output port and send
83 net.do_action(&NetAction::LoadPacketIntoOutputPort(
84 output,
85 "out".to_string(),
86 ));
87 net.do_action(&NetAction::SendOutputSalvo(
88 started.id.clone(),
89 "default".to_string(),
90 ));
91
92 // Finish epoch
93 net.do_action(&NetAction::FinishEpoch(started.id));
94 println!(" Finished {} - sent packet to D", node_name);
95 }
96
97 // Run network - packets move from B->D and C->D edges to D's input ports
98 net.run_until_blocked();
99
100 // Check D's input ports
101 let d_in1 = PacketLocation::InputPort("D".to_string(), "in1".to_string());
102 let d_in2 = PacketLocation::InputPort("D".to_string(), "in2".to_string());
103 println!("\nD's input ports:");
104 println!(" in1 (from B): {} packets", net.packet_count_at(&d_in1));
105 println!(" in2 (from C): {} packets", net.packet_count_at(&d_in2));
106
107 // D should now have a startable epoch (both inputs present)
108 let startable_d = net.get_startable_epochs();
109 println!("\nStartable epochs at D: {}", startable_d.len());
110
111 if let Some(d_epoch_id) = startable_d.first() {
112 let d_epoch = net.get_epoch(d_epoch_id).unwrap();
113 println!(
114 "D's epoch received {} packets from both branches!",
115 d_epoch.in_salvo.packets.len()
116 );
117 }
118
119 println!("\nDiamond flow example complete!");
120}More examples
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 is_blocked(&self) -> bool
pub fn is_blocked(&self) -> bool
Check if the network is blocked (no progress can be made by RunStep).
Returns true if:
- No packets can move from edges to input ports (all destinations full or no packets on edges)
- No input salvo conditions can be triggered
Sourcepub fn undo_action(
&mut self,
action: &NetAction,
events: &[NetEvent],
) -> Result<(), UndoError>
pub fn undo_action( &mut self, action: &NetAction, events: &[NetEvent], ) -> Result<(), UndoError>
Undo a previously executed action.
Takes the original action and the events it produced.
Returns Ok(()) on success, or an error if undo is not possible.
§Restrictions
- Actions must be undone in reverse order (LIFO)
- State may have changed since the action (undo may fail)
§Example
let action = NetAction::CreatePacket(None);
let response = net.do_action(&action);
if let NetActionResponse::Success(_, events) = response {
// Later, to undo:
net.undo_action(&action, &events)?;
}