1#[cfg(not(feature = "std"))]
24use alloc::{vec, vec::Vec};
25
26use crate::{HierarchyLevel, NodeId};
27
28use super::topology::MeshTopology;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum RouteDirection {
33 Upward,
35 Downward,
37 Broadcast,
39 Targeted(u32), }
42
43#[derive(Debug, Clone)]
45pub struct RouteDecision {
46 pub next_hops: Vec<NodeId>,
48 pub local_copy: bool,
50 pub routed: bool,
52 pub failure_reason: Option<RouteFailure>,
54}
55
56impl RouteDecision {
57 pub fn success(next_hops: Vec<NodeId>, local_copy: bool) -> Self {
59 Self {
60 next_hops,
61 local_copy,
62 routed: true,
63 failure_reason: None,
64 }
65 }
66
67 pub fn failed(reason: RouteFailure) -> Self {
69 Self {
70 next_hops: Vec::new(),
71 local_copy: false,
72 routed: false,
73 failure_reason: Some(reason),
74 }
75 }
76
77 pub fn local_only() -> Self {
79 Self {
80 next_hops: Vec::new(),
81 local_copy: true,
82 routed: true,
83 failure_reason: None,
84 }
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum RouteFailure {
91 NoParent,
93 NoChildren,
95 TargetNotFound,
97 NoPeers,
99 TtlExpired,
101 MessageTooLarge,
103}
104
105#[derive(Debug, Clone)]
109pub struct MeshRouter {
110 pub node_id: NodeId,
112 pub my_level: HierarchyLevel,
114}
115
116impl MeshRouter {
117 pub fn new(node_id: NodeId, my_level: HierarchyLevel) -> Self {
119 Self { node_id, my_level }
120 }
121
122 pub fn route(&self, direction: RouteDirection, topology: &MeshTopology) -> RouteDecision {
124 match direction {
125 RouteDirection::Upward => self.route_upward(topology),
126 RouteDirection::Downward => self.route_downward(topology),
127 RouteDirection::Broadcast => self.route_broadcast(topology),
128 RouteDirection::Targeted(target_id) => {
129 self.route_targeted(&NodeId::new(target_id), topology)
130 }
131 }
132 }
133
134 fn route_upward(&self, topology: &MeshTopology) -> RouteDecision {
136 match &topology.parent {
137 Some(parent_id) => RouteDecision::success(vec![*parent_id], true),
138 None => RouteDecision::failed(RouteFailure::NoParent),
139 }
140 }
141
142 fn route_downward(&self, topology: &MeshTopology) -> RouteDecision {
144 if topology.children.is_empty() {
145 RouteDecision::failed(RouteFailure::NoChildren)
146 } else {
147 RouteDecision::success(topology.children.clone(), true)
148 }
149 }
150
151 fn route_broadcast(&self, topology: &MeshTopology) -> RouteDecision {
153 let all = topology.all_connected();
154 if all.is_empty() {
155 RouteDecision::failed(RouteFailure::NoPeers)
156 } else {
157 RouteDecision::success(all, true)
158 }
159 }
160
161 fn route_targeted(&self, target: &NodeId, topology: &MeshTopology) -> RouteDecision {
163 if topology.is_connected(target) {
165 return RouteDecision::success(vec![*target], false);
166 }
167
168 if let Some(ref parent) = topology.parent {
174 RouteDecision::success(vec![*parent], false)
176 } else if !topology.children.is_empty() {
177 RouteDecision::success(topology.children.clone(), false)
179 } else {
180 RouteDecision::failed(RouteFailure::TargetNotFound)
181 }
182 }
183
184 pub fn handle_received(
188 &self,
189 source: &NodeId,
190 destination: Option<&NodeId>,
191 direction: RouteDirection,
192 topology: &MeshTopology,
193 ) -> RouteDecision {
194 if let Some(dest) = destination {
196 if dest == &self.node_id {
197 return RouteDecision::local_only();
198 }
199 }
200
201 let _source_role = topology.get_role(source);
203
204 match direction {
205 RouteDirection::Upward => {
206 self.route_upward(topology)
208 }
209 RouteDirection::Downward => {
210 let mut children = topology.children.clone();
213 children.retain(|c| c != source);
214 if children.is_empty() {
215 RouteDecision::local_only()
216 } else {
217 RouteDecision::success(children, true)
218 }
219 }
220 RouteDirection::Broadcast => {
221 let mut all = topology.all_connected();
223 all.retain(|n| n != source);
224 RouteDecision::success(all, true)
225 }
226 RouteDirection::Targeted(target_id) => {
227 let target = NodeId::new(target_id);
228 if target == self.node_id {
229 RouteDecision::local_only()
230 } else {
231 self.route_targeted(&target, topology)
232 }
233 }
234 }
235 }
236
237 pub fn aggregation_route(&self, topology: &MeshTopology) -> Option<NodeId> {
241 topology.parent
242 }
243
244 pub fn dissemination_routes(&self, topology: &MeshTopology) -> Vec<NodeId> {
248 topology.children.clone()
249 }
250}
251
252#[derive(Debug, Clone)]
254pub struct HopTracker {
255 pub max_hops: u8,
257 pub visited: Vec<NodeId>,
259}
260
261impl HopTracker {
262 pub fn new(max_hops: u8) -> Self {
264 Self {
265 max_hops,
266 visited: Vec::new(),
267 }
268 }
269
270 pub fn visit(&mut self, node_id: NodeId) -> bool {
272 if self.visited.contains(&node_id) {
273 return false; }
275 if self.visited.len() >= self.max_hops as usize {
276 return false; }
278 self.visited.push(node_id);
279 true
280 }
281
282 pub fn has_visited(&self, node_id: &NodeId) -> bool {
284 self.visited.contains(node_id)
285 }
286
287 pub fn remaining_hops(&self) -> u8 {
289 self.max_hops.saturating_sub(self.visited.len() as u8)
290 }
291
292 pub fn is_expired(&self) -> bool {
294 self.visited.len() >= self.max_hops as usize
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301
302 fn create_topology_with_parent() -> MeshTopology {
303 let mut topology = MeshTopology::new(HierarchyLevel::Platform, 3, 7);
304 topology.set_parent(NodeId::new(0x1000));
305 topology.add_child(NodeId::new(0x0001));
306 topology.add_child(NodeId::new(0x0002));
307 topology
308 }
309
310 #[test]
311 fn test_route_upward() {
312 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
313 let topology = create_topology_with_parent();
314
315 let decision = router.route(RouteDirection::Upward, &topology);
316 assert!(decision.routed);
317 assert_eq!(decision.next_hops.len(), 1);
318 assert_eq!(decision.next_hops[0].as_u32(), 0x1000);
319 }
320
321 #[test]
322 fn test_route_upward_no_parent() {
323 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
324 let topology = MeshTopology::new(HierarchyLevel::Platform, 3, 7);
325
326 let decision = router.route(RouteDirection::Upward, &topology);
327 assert!(!decision.routed);
328 assert_eq!(decision.failure_reason, Some(RouteFailure::NoParent));
329 }
330
331 #[test]
332 fn test_route_downward() {
333 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Squad);
334 let topology = create_topology_with_parent();
335
336 let decision = router.route(RouteDirection::Downward, &topology);
337 assert!(decision.routed);
338 assert_eq!(decision.next_hops.len(), 2);
339 }
340
341 #[test]
342 fn test_route_broadcast() {
343 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
344 let topology = create_topology_with_parent();
345
346 let decision = router.route(RouteDirection::Broadcast, &topology);
347 assert!(decision.routed);
348 assert_eq!(decision.next_hops.len(), 3); }
350
351 #[test]
352 fn test_route_targeted_direct() {
353 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
354 let topology = create_topology_with_parent();
355
356 let decision = router.route(RouteDirection::Targeted(0x0001), &topology);
358 assert!(decision.routed);
359 assert_eq!(decision.next_hops.len(), 1);
360 assert_eq!(decision.next_hops[0].as_u32(), 0x0001);
361 }
362
363 #[test]
364 fn test_route_targeted_via_parent() {
365 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
366 let topology = create_topology_with_parent();
367
368 let decision = router.route(RouteDirection::Targeted(0x9999), &topology);
370 assert!(decision.routed);
371 assert_eq!(decision.next_hops.len(), 1);
372 assert_eq!(decision.next_hops[0].as_u32(), 0x1000); }
374
375 #[test]
376 fn test_handle_received_for_us() {
377 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
378 let topology = create_topology_with_parent();
379
380 let decision = router.handle_received(
381 &NodeId::new(0x1000),
382 Some(&NodeId::new(0x1234)), RouteDirection::Downward,
384 &topology,
385 );
386
387 assert!(decision.local_copy);
388 assert!(decision.next_hops.is_empty());
389 }
390
391 #[test]
392 fn test_hop_tracker() {
393 let mut tracker = HopTracker::new(3);
394
395 assert!(tracker.visit(NodeId::new(0x0001)));
396 assert!(tracker.visit(NodeId::new(0x0002)));
397 assert!(tracker.visit(NodeId::new(0x0003)));
398 assert!(!tracker.visit(NodeId::new(0x0004))); assert!(tracker.has_visited(&NodeId::new(0x0001)));
401 assert!(!tracker.has_visited(&NodeId::new(0x0004)));
402 }
403
404 #[test]
405 fn test_hop_tracker_loop_detection() {
406 let mut tracker = HopTracker::new(10);
407
408 assert!(tracker.visit(NodeId::new(0x0001)));
409 assert!(tracker.visit(NodeId::new(0x0002)));
410 assert!(!tracker.visit(NodeId::new(0x0001))); }
412
413 #[test]
414 fn test_aggregation_route() {
415 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Platform);
416 let topology = create_topology_with_parent();
417
418 let route = router.aggregation_route(&topology);
419 assert_eq!(route, Some(NodeId::new(0x1000)));
420 }
421
422 #[test]
423 fn test_dissemination_routes() {
424 let router = MeshRouter::new(NodeId::new(0x1234), HierarchyLevel::Squad);
425 let topology = create_topology_with_parent();
426
427 let routes = router.dissemination_routes(&topology);
428 assert_eq!(routes.len(), 2);
429 }
430}