use swh_graph::collections::{AdaptiveNodeSet, NodeSet};
use swh_graph::graph::*;
use swh_graph::SWHType;
#[derive(Debug, PartialEq, Eq)]
pub struct EarliestRevision {
pub node: usize,
pub ts: i64,
pub rev_occurrences: u64,
}
pub fn find_earliest_revision<G>(graph: &G, src: usize) -> Option<EarliestRevision>
where
G: SwhBackwardGraph + SwhGraphWithProperties,
<G as SwhGraphWithProperties>::Maps: swh_graph::properties::Maps,
<G as SwhGraphWithProperties>::Timestamps: swh_graph::properties::Timestamps,
{
let mut stack = Vec::new();
let mut visited = AdaptiveNodeSet::new(graph.num_nodes());
stack.push(src);
visited.insert(src);
let mut visited_revisions = 0u64;
let mut earliest_rev: Option<(usize, i64)> = None;
while let Some(node) = stack.pop() {
let node_type = graph.properties().node_type(node);
if node_type == SWHType::Revision {
visited_revisions += 1;
let Some(committer_ts) = graph.properties().committer_timestamp(node) else {
continue;
};
if committer_ts != i64::MIN && committer_ts != 0 {
match earliest_rev {
None => earliest_rev = Some((node, committer_ts)),
Some((_, earliest_ts)) if committer_ts < earliest_ts => {
earliest_rev = Some((node, committer_ts))
}
_ => (),
}
}
} else {
for pred in graph.predecessors(node) {
use swh_graph::SWHType::*;
if visited.contains(pred) {
continue;
}
let pred_type = graph.properties().node_type(pred);
match (node_type, pred_type) {
(Content, Directory) | (Directory, Directory) | (Directory, Revision) => {
stack.push(pred);
visited.insert(pred);
}
_ => {}
}
}
}
}
earliest_rev.map(|(earliest_rev_id, earliest_ts)| EarliestRevision {
node: earliest_rev_id,
ts: earliest_ts,
rev_occurrences: visited_revisions,
})
}