use std::hash::Hash;
use hashbrown::{HashMap, 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() - 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>)> = vec![(start, children)];
let mut index_map: HashMap<G::NodeId, usize> = HashMap::with_capacity(node_count);
index_map.insert(start, 0);
while !stack.is_empty() {
let temp_parent = stack.last().unwrap();
let parent = temp_parent.0;
let children = temp_parent.1.clone();
let count = *index_map.get(&parent).unwrap();
let mut found = false;
let mut index = count;
for child in &children[index..] {
index += 1;
if !visited.contains(child) {
out_vec.push((graph.to_index(parent), graph.to_index(*child)));
visited.insert(*child);
let mut grandchildren: Vec<G::NodeId> = graph.neighbors(*child).collect();
grandchildren.reverse();
stack.push((*child, grandchildren));
index_map.insert(*child, 0);
*index_map.get_mut(&parent).unwrap() = index;
found = true;
break;
}
}
if !found || children.is_empty() {
stack.pop();
}
}
}
out_vec
}