use std::hash::Hash;
use hashbrown::HashSet;
use petgraph::visit::{
EdgeCount, IntoNeighbors, IntoNodeIdentifiers, NodeCount, NodeIndexable, Visitable,
};
pub fn dfs_edges<G>(graph: G, source: Option<G::NodeId>) -> Vec<(usize, usize)>
where
G: IntoNodeIdentifiers + NodeIndexable + IntoNeighbors + NodeCount + EdgeCount + Visitable,
G::NodeId: Eq + Hash,
{
let nodes: Vec<G::NodeId> = match source {
Some(start) => vec![start],
None => graph.node_identifiers().collect(),
};
let node_count = graph.node_count();
let mut visited: HashSet<G::NodeId> = HashSet::with_capacity(node_count);
let mut out_vec: Vec<(usize, usize)> = if source.is_some() {
Vec::new()
} else {
Vec::with_capacity(core::cmp::min(
graph.node_count().saturating_sub(1),
graph.edge_count(),
))
};
for start in nodes {
if visited.contains(&start) {
continue;
}
visited.insert(start);
let mut children: Vec<G::NodeId> = graph.neighbors(start).collect();
children.reverse();
let mut stack: Vec<(G::NodeId, Vec<G::NodeId>, usize)> = vec![(start, children, 0)];
while let Some((parent, children, idx)) = stack.last_mut() {
let mut found = false;
while *idx < children.len() {
let child = children[*idx];
*idx += 1;
if !visited.contains(&child) {
let parent_id = *parent;
out_vec.push((graph.to_index(parent_id), graph.to_index(child)));
visited.insert(child);
let mut grandchildren: Vec<G::NodeId> = graph.neighbors(child).collect();
grandchildren.reverse();
stack.push((child, grandchildren, 0));
found = true;
break;
}
}
if !found {
stack.pop();
}
}
}
out_vec
}