1use netrun_sim::graph::{
11 Edge, Graph, MaxSalvos, Node, PacketCount, Port, PortRef, PortSlotSpec, PortState, PortType,
12 SalvoCondition, SalvoConditionTerm,
13};
14use netrun_sim::net::{
15 NetAction, NetActionResponse, NetActionResponseData, NetSim, PacketLocation,
16};
17use indexmap::IndexMap;
18use std::collections::HashMap;
19
20fn main() {
21 let graph = create_linear_graph();
23 println!("Created graph with {} nodes", graph.nodes().len());
24
25 let mut net = NetSim::new(graph);
27
28 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 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 net.run_until_blocked();
58 println!("Ran network until blocked");
59
60 let startable = net.get_startable_epochs();
62 println!("Startable epochs: {}", startable.len());
63
64 if let Some(epoch_id) = startable.first() {
65 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 net.do_action(&NetAction::ConsumePacket(packet_id));
75 println!("Consumed input packet");
76
77 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 net.do_action(&NetAction::LoadPacketIntoOutputPort(
87 output_packet.clone(),
88 "out".to_string(),
89 ));
90 println!("Loaded packet into output port");
91
92 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 net.do_action(&NetAction::FinishEpoch(epoch.id));
101 println!("Finished epoch");
102
103 net.run_until_blocked();
105 println!("Ran network until blocked again");
106
107 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}
120
121fn 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}
138
139fn create_node(name: &str, in_ports: Vec<&str>, out_ports: Vec<&str>) -> Node {
140 let in_ports_map: HashMap<String, Port> = in_ports
141 .iter()
142 .map(|p| {
143 (
144 p.to_string(),
145 Port {
146 slots_spec: PortSlotSpec::Infinite,
147 },
148 )
149 })
150 .collect();
151
152 let out_ports_map: HashMap<String, Port> = out_ports
153 .iter()
154 .map(|p| {
155 (
156 p.to_string(),
157 Port {
158 slots_spec: PortSlotSpec::Infinite,
159 },
160 )
161 })
162 .collect();
163
164 let mut in_salvo_conditions = IndexMap::new();
166 if !in_ports.is_empty() {
167 in_salvo_conditions.insert(
168 "default".to_string(),
169 SalvoCondition {
170 max_salvos: MaxSalvos::Finite(1),
171 ports: in_ports
172 .iter()
173 .map(|s| (s.to_string(), PacketCount::All))
174 .collect(),
175 term: SalvoConditionTerm::Port {
176 port_name: in_ports[0].to_string(),
177 state: PortState::NonEmpty,
178 },
179 },
180 );
181 }
182
183 let mut out_salvo_conditions = IndexMap::new();
185 if !out_ports.is_empty() {
186 out_salvo_conditions.insert(
187 "default".to_string(),
188 SalvoCondition {
189 max_salvos: MaxSalvos::Infinite,
190 ports: out_ports
191 .iter()
192 .map(|s| (s.to_string(), PacketCount::All))
193 .collect(),
194 term: SalvoConditionTerm::Port {
195 port_name: out_ports[0].to_string(),
196 state: PortState::NonEmpty,
197 },
198 },
199 );
200 }
201
202 Node {
203 name: name.to_string(),
204 in_ports: in_ports_map,
205 out_ports: out_ports_map,
206 in_salvo_conditions,
207 out_salvo_conditions,
208 }
209}
210
211fn create_edge(src_node: &str, src_port: &str, tgt_node: &str, tgt_port: &str) -> Edge {
212 Edge {
213 source: PortRef {
214 node_name: src_node.to_string(),
215 port_type: PortType::Output,
216 port_name: src_port.to_string(),
217 },
218 target: PortRef {
219 node_name: tgt_node.to_string(),
220 port_type: PortType::Input,
221 port_name: tgt_port.to_string(),
222 },
223 }
224}