BFS traversal with multi-label filter. Empty labels = all edges. `max_visited` caps the number of nodes visited to prevent supernode fan-out explosion. Pass [`DEFAULT_MAX_VISITED`] for the standard limit.
(
&self,
start_nodes: &[&str],
label_filters: &[&str],
direction: Direction,
max_depth: usize,
max_visited: usize,
)
| 111 | /// `max_visited` caps the number of nodes visited to prevent supernode fan-out |
| 112 | /// explosion. Pass [`DEFAULT_MAX_VISITED`] for the standard limit. |
| 113 | pub fn traverse_bfs_with_depth_multi( |
| 114 | &self, |
| 115 | start_nodes: &[&str], |
| 116 | label_filters: &[&str], |
| 117 | direction: Direction, |
| 118 | max_depth: usize, |
| 119 | max_visited: usize, |
| 120 | ) -> Vec<(String, u8)> { |
| 121 | let label_ids: Vec<u32> = label_filters |
| 122 | .iter() |
| 123 | .filter_map(|l| self.label_id(l)) |
| 124 | .collect(); |
| 125 | let match_label = |lid: u32| label_ids.is_empty() || label_ids.contains(&lid); |
| 126 | let mut visited: HashMap<u32, u8> = HashMap::new(); |
| 127 | let mut queue: VecDeque<(u32, u8)> = VecDeque::new(); |
| 128 | |
| 129 | for &node in start_nodes { |
| 130 | if let Some(&id) = self.node_to_id.get(node) { |
| 131 | visited.insert(id, 0); |
| 132 | queue.push_back((id, 0)); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | while let Some((node_id, depth)) = queue.pop_front() { |
| 137 | if depth as usize >= max_depth || visited.len() >= max_visited { |
| 138 | continue; |
| 139 | } |
| 140 | |
| 141 | let next_depth = depth + 1; |
| 142 | |
| 143 | if matches!(direction, Direction::Out | Direction::Both) { |
| 144 | for (lid, dst) in self.dense_iter_out(node_id) { |
| 145 | if match_label(lid) |
| 146 | && visited.len() < max_visited |
| 147 | && !visited.contains_key(&dst) |
| 148 | { |
| 149 | visited.insert(dst, next_depth); |
| 150 | queue.push_back((dst, next_depth)); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | if matches!(direction, Direction::In | Direction::Both) { |
| 155 | for (lid, src) in self.dense_iter_in(node_id) { |
| 156 | if match_label(lid) |
| 157 | && visited.len() < max_visited |
| 158 | && !visited.contains_key(&src) |
| 159 | { |
| 160 | visited.insert(src, next_depth); |
| 161 | queue.push_back((src, next_depth)); |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | visited |
| 168 | .into_iter() |
| 169 | .map(|(id, depth)| (self.id_to_node[id as usize].clone(), depth)) |
| 170 | .collect() |
no test coverage detected