1#[cfg(not(feature = "std"))]
9use alloc::{vec, vec::Vec};
10
11use crate::{HierarchyLevel, NodeId};
12
13use super::topology::MeshTopology;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum RouteDirection {
18 Upward,
20 Downward,
22 Broadcast,
24 Targeted(u32), }
27
28#[derive(Debug, Clone)]
30pub struct RouteDecision {
31 pub next_hops: Vec<NodeId>,
33 pub local_copy: bool,
35 pub routed: bool,
37 pub failure_reason: Option<RouteFailure>,
39}
40
41impl RouteDecision {
42 pub fn success(next_hops: Vec<NodeId>, local_copy: bool) -> Self {
44 Self {
45 next_hops,
46 local_copy,
47 routed: true,
48 failure_reason: None,
49 }
50 }
51
52 pub fn failed(reason: RouteFailure) -> Self {
54 Self {
55 next_hops: Vec::new(),
56 local_copy: false,
57 routed: false,
58 failure_reason: Some(reason),
59 }
60 }
61
62 pub fn local_only() -> Self {
64 Self {
65 next_hops: Vec::new(),
66 local_copy: true,
67 routed: true,
68 failure_reason: None,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum RouteFailure {
76 NoParent,
78 NoChildren,
80 TargetNotFound,
82 NoPeers,
84 TtlExpired,
86 MessageTooLarge,
88}
89
90#[derive(Debug, Clone)]
94pub struct MeshRouter {
95 pub node_id: NodeId,
97 pub my_level: HierarchyLevel,
99}
100
101impl MeshRouter {
102 pub fn new(node_id: NodeId, my_level: HierarchyLevel) -> Self {
104 Self { node_id, my_level }
105 }
106
107 pub fn route(&self, direction: RouteDirection, topology: &MeshTopology) -> RouteDecision {
109 match direction {
110 RouteDirection::Upward => self.route_upward(topology),
111 RouteDirection::Downward => self.route_downward(topology),
112 RouteDirection::Broadcast => self.route_broadcast(topology),
113 RouteDirection::Targeted(target_id) => {
114 self.route_targeted(&NodeId::new(target_id), topology)
115 }
116 }
117 }
118
119 fn route_upward(&self, topology: &MeshTopology) -> RouteDecision {
121 match &topology.parent {
122 Some(parent_id) => RouteDecision::success(vec![*parent_id], true),
123 None => RouteDecision::failed(RouteFailure::NoParent),
124 }
125 }
126
127 fn route_downward(&self, topology: &MeshTopology) -> RouteDecision {
129 if topology.children.is_empty() {
130 RouteDecision::failed(RouteFailure::NoChildren)
131 } else {
132 RouteDecision::success(topology.children.clone(), true)
133 }
134 }
135
136 fn route_broadcast(&self, topology: &MeshTopology) -> RouteDecision {
138 let all = topology.all_connected();
139 if all.is_empty() {
140 RouteDecision::failed(RouteFailure::NoPeers)
141 } else {
142 RouteDecision::success(all, true)
143 }
144 }
145
146 fn route_targeted(&self, target: &NodeId, topology: &MeshTopology) -> RouteDecision {
148 if topology.is_connected(target) {
150 return RouteDecision::success(vec![*target], false);
151 }
152
153 if let Some(ref parent) = topology.parent {
159 RouteDecision::success(vec![*parent], false)
161 } else if !topology.children.is_empty() {
162 RouteDecision::success(topology.children.clone(), false)
164 } else {
165 RouteDecision::failed(RouteFailure::TargetNotFound)
166 }
167 }
168
169 pub fn handle_received(
173 &self,
174 source: &NodeId,
175 destination: Option<&NodeId>,
176 direction: RouteDirection,
177 topology: &MeshTopology,
178 ) -> RouteDecision {
179 if let Some(dest) = destination {
181 if dest == &self.node_id {
182 return RouteDecision::local_only();
183 }
184 }
185
186 let _source_role = topology.get_role(source);
188
189 match direction {
190 RouteDirection::Upward => {
191 self.route_upward(topology)
193 }
194 RouteDirection::Downward => {
195 let mut children = topology.children.clone();
198 children.retain(|c| c != source);
199 if children.is_empty() {
200 RouteDecision::local_only()
201 } else {
202 RouteDecision::success(children, true)
203 }
204 }
205 RouteDirection::Broadcast => {
206 let mut all = topology.all_connected();
208 all.retain(|n| n != source);
209 RouteDecision::success(all, true)
210 }
211 RouteDirection::Targeted(target_id) => {
212 let target = NodeId::new(target_id);
213 if target == self.node_id {
214 RouteDecision::local_only()
215 } else {
216 self.route_targeted(&target, topology)
217 }
218 }
219 }
220 }
221
222 pub fn aggregation_route(&self, topology: &MeshTopology) -> Option<NodeId> {
226 topology.parent
227 }
228
229 pub fn dissemination_routes(&self, topology: &MeshTopology) -> Vec<NodeId> {
233 topology.children.clone()
234 }
235}
236
237#[derive(Debug, Clone)]
239pub struct HopTracker {
240 pub max_hops: u8,
242 pub visited: Vec<NodeId>,
244}
245
246impl HopTracker {
247 pub fn new(max_hops: u8) -> Self {
249 Self {
250 max_hops,
251 visited: Vec::new(),
252 }
253 }
254
255 pub fn visit(&mut self, node_id: NodeId) -> bool {
257 if self.visited.contains(&node_id) {
258 return false; }
260 if self.visited.len() >= self.max_hops as usize {
261 return false; }
263 self.visited.push(node_id);
264 true
265 }
266
267 pub fn has_visited(&self, node_id: &NodeId) -> bool {
269 self.visited.contains(node_id)
270 }
271
272 pub fn remaining_hops(&self) -> u8 {
274 self.max_hops.saturating_sub(self.visited.len() as u8)
275 }
276
277 pub fn is_expired(&self) -> bool {
279 self.visited.len() >= self.max_hops as usize
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 fn create_topology_with_parent() -> MeshTopology {
288 let mut topology = MeshTopology::new(HierarchyLevel::Platform, 3, 7);
289 topology.set_parent(NodeId::new(0x1000));
290 topology.add_child(NodeId::new(0x0001));
291 topology.add_child(NodeId::new(0x0002));
292 topology
293 }
294
295 #[test]
296 fn test_route_upward() {
297 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
298 let topology = create_topology_with_parent();
299
300 let decision = router.route(RouteDirection::Upward, &topology);
301 assert!(decision.routed);
302 assert_eq!(decision.next_hops.len(), 1);
303 assert_eq!(decision.next_hops[0].as_u32(), 0x1000);
304 }
305
306 #[test]
307 fn test_route_upward_no_parent() {
308 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
309 let topology = MeshTopology::new(HierarchyLevel::Platform, 3, 7);
310
311 let decision = router.route(RouteDirection::Upward, &topology);
312 assert!(!decision.routed);
313 assert_eq!(decision.failure_reason, Some(RouteFailure::NoParent));
314 }
315
316 #[test]
317 fn test_route_downward() {
318 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Squad);
319 let topology = create_topology_with_parent();
320
321 let decision = router.route(RouteDirection::Downward, &topology);
322 assert!(decision.routed);
323 assert_eq!(decision.next_hops.len(), 2);
324 }
325
326 #[test]
327 fn test_route_broadcast() {
328 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
329 let topology = create_topology_with_parent();
330
331 let decision = router.route(RouteDirection::Broadcast, &topology);
332 assert!(decision.routed);
333 assert_eq!(decision.next_hops.len(), 3); }
335
336 #[test]
337 fn test_route_targeted_direct() {
338 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
339 let topology = create_topology_with_parent();
340
341 let decision = router.route(RouteDirection::Targeted(0x0001), &topology);
343 assert!(decision.routed);
344 assert_eq!(decision.next_hops.len(), 1);
345 assert_eq!(decision.next_hops[0].as_u32(), 0x0001);
346 }
347
348 #[test]
349 fn test_route_targeted_via_parent() {
350 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
351 let topology = create_topology_with_parent();
352
353 let decision = router.route(RouteDirection::Targeted(0x9999), &topology);
355 assert!(decision.routed);
356 assert_eq!(decision.next_hops.len(), 1);
357 assert_eq!(decision.next_hops[0].as_u32(), 0x1000); }
359
360 #[test]
361 fn test_handle_received_for_us() {
362 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
363 let topology = create_topology_with_parent();
364
365 let decision = router.handle_received(
366 &NodeId::new(0x1000),
367 Some(&NodeId::new(0x1234)), RouteDirection::Downward,
369 &topology,
370 );
371
372 assert!(decision.local_copy);
373 assert!(decision.next_hops.is_empty());
374 }
375
376 #[test]
377 fn test_hop_tracker() {
378 let mut tracker = HopTracker::new(3);
379
380 assert!(tracker.visit(NodeId::new(0x0001)));
381 assert!(tracker.visit(NodeId::new(0x0002)));
382 assert!(tracker.visit(NodeId::new(0x0003)));
383 assert!(!tracker.visit(NodeId::new(0x0004))); assert!(tracker.has_visited(&NodeId::new(0x0001)));
386 assert!(!tracker.has_visited(&NodeId::new(0x0004)));
387 }
388
389 #[test]
390 fn test_hop_tracker_loop_detection() {
391 let mut tracker = HopTracker::new(10);
392
393 assert!(tracker.visit(NodeId::new(0x0001)));
394 assert!(tracker.visit(NodeId::new(0x0002)));
395 assert!(!tracker.visit(NodeId::new(0x0001))); }
397
398 #[test]
399 fn test_aggregation_route() {
400 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
401 let topology = create_topology_with_parent();
402
403 let route = router.aggregation_route(&topology);
404 assert_eq!(route, Some(NodeId::new(0x1000)));
405 }
406
407 #[test]
408 fn test_dissemination_routes() {
409 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Squad);
410 let topology = create_topology_with_parent();
411
412 let routes = router.dissemination_routes(&topology);
413 assert_eq!(routes.len(), 2);
414 }
415}