capability_skeleton/
build_node_level_map.rs1crate::ix!();
3
4#[instrument(level = "trace", skip(skel))]
6pub fn build_node_level_map(skel: &Skeleton) -> HashMap<u16, u8> {
7 trace!("Building node->level map with BFS for Skeleton.");
8
9 let mut visited = HashSet::new();
10 let mut map = HashMap::<u16, u8>::new();
11 let mut queue = VecDeque::new();
12
13 if let Some(rid) = skel.root_id() {
14 queue.push_back((*rid, 0u8));
16 } else {
17 debug!("No root => empty map");
18 return map;
19 }
20
21 while let Some((nid, lvl)) = queue.pop_front() {
22 if !visited.insert(nid) {
24 continue;
25 }
26 map.insert(nid, lvl);
28
29 if let Some(node) = skel.nodes().iter().find(|n| n.id() == nid) {
31 for &child_id in node.child_ids() {
33 let next_lvl = lvl.saturating_add(1);
34 queue.push_back((child_id, next_lvl));
35 }
36 }
37 }
38
39 trace!("Finished BFS => discovered {} connected nodes", map.len());
40 map
41}
42
43#[cfg(test)]
44mod build_node_level_map_assessment {
45 use super::*;
46
47 fn make_node(id: u16, child_ids: &[u16]) -> SkeletonNode {
48 let k = if child_ids.is_empty() {
49 NodeKind::LeafHolder
50 } else {
51 NodeKind::Dispatch
52 };
53 SkeletonNodeBuilder::default()
54 .id(id)
55 .child_ids(child_ids.to_vec())
56 .name(format!("Node_{id}"))
57 .original_key(format!("Node_{id}"))
58 .build(k)
59 .unwrap()
60 }
61
62 #[traced_test]
63 fn check_empty_skeleton() {
64 let skel = SkeletonBuilder::default().build().unwrap();
65 let map = build_node_level_map(&skel);
66 assert!(map.is_empty());
67 }
68
69 #[traced_test]
70 fn check_single_node() {
71 let node0 = make_node(0, &[]);
72 let skel = SkeletonBuilder::default()
73 .nodes(vec![node0])
74 .root_id(Some(0))
75 .build()
76 .unwrap();
77 let map = build_node_level_map(&skel);
78 assert_eq!(map.len(), 1);
79 assert_eq!(map.get(&0), Some(&0u8));
80 }
81
82 #[traced_test]
83 fn check_linear_chain() {
84 let n0 = make_node(0, &[1]);
85 let n1 = make_node(1, &[2]);
86 let n2 = make_node(2, &[]);
87 let skel = SkeletonBuilder::default()
88 .nodes(vec![n0, n1, n2])
89 .root_id(Some(0))
90 .build()
91 .unwrap();
92 let map = build_node_level_map(&skel);
93 assert_eq!(map.get(&0), Some(&0u8));
94 assert_eq!(map.get(&1), Some(&1u8));
95 assert_eq!(map.get(&2), Some(&2u8));
96 assert_eq!(map.len(), 3);
97 }
98
99 #[traced_test]
100 fn check_branching() {
101 let n0 = make_node(0, &[1,2]);
102 let n1 = make_node(1, &[3]);
103 let n2 = make_node(2, &[]);
104 let n3 = make_node(3, &[]);
105 let skel = SkeletonBuilder::default()
106 .nodes(vec![n0,n1,n2,n3])
107 .root_id(Some(0))
108 .build()
109 .unwrap();
110 let map = build_node_level_map(&skel);
111 assert_eq!(map.get(&0), Some(&0u8));
112 assert_eq!(map.get(&1), Some(&1u8));
113 assert_eq!(map.get(&2), Some(&1u8));
114 assert_eq!(map.get(&3), Some(&2u8));
115 }
116
117 #[traced_test]
118 fn check_unconnected_nodes() {
119 let n0 = make_node(0, &[1]);
121 let n1 = make_node(1, &[]);
122 let n2 = make_node(2, &[3]);
123 let n3 = make_node(3, &[]);
124 let skel = SkeletonBuilder::default()
125 .nodes(vec![n0,n1,n2,n3])
126 .root_id(Some(0))
127 .build()
128 .unwrap();
129
130 let map = build_node_level_map(&skel);
131 assert_eq!(map.len(), 2);
132 assert_eq!(map.get(&0), Some(&0u8));
133 assert_eq!(map.get(&1), Some(&1u8));
134 }
135
136 #[traced_test]
137 fn check_cycle_doesnt_loop() {
138 let n0 = make_node(0, &[1]);
140 let n1 = make_node(1, &[0]);
141 let skel = SkeletonBuilder::default()
142 .nodes(vec![n0,n1])
143 .root_id(Some(0))
144 .build()
145 .unwrap();
146
147 let map = build_node_level_map(&skel);
148 assert_eq!(map.len(), 2);
149 assert_eq!(map.get(&0), Some(&0u8));
150 assert_eq!(map.get(&1), Some(&1u8));
151 }
152}