use crate::{Edge, Node, graph, node};
use petgraph::visit::{Data, IntoEdgesDirected, IntoNodeReferences, NodeIndexable, Visitable};
use std::collections::{BTreeSet, HashSet};
pub fn export<'a, G>(
get_node: node::GetNode<'a>,
reg: &gantz_ca::Registry<G>,
heads: impl IntoIterator<Item = impl std::borrow::Borrow<gantz_ca::Head>>,
) -> gantz_ca::Registry<G>
where
G: Clone,
for<'g> &'g G: Data<EdgeWeight = Edge>
+ IntoEdgesDirected
+ IntoNodeReferences
+ NodeIndexable
+ Visitable,
for<'g> <&'g G as Data>::NodeWeight: Node,
{
let required = required_commits(get_node, reg, heads);
reg.export(&required)
}
pub fn export_heads<'a, G>(
get_node: node::GetNode<'a>,
reg: &gantz_ca::Registry<G>,
heads: impl IntoIterator<Item = impl std::borrow::Borrow<gantz_ca::Head>>,
) -> gantz_ca::Registry<G>
where
G: Clone,
for<'g> &'g G: Data<EdgeWeight = Edge>
+ IntoEdgesDirected
+ IntoNodeReferences
+ NodeIndexable
+ Visitable,
for<'g> <&'g G as Data>::NodeWeight: Node,
{
let required = required_commits_for_heads(get_node, reg, heads);
reg.export(&required)
}
pub fn required_commits<'a, G>(
get_node: node::GetNode<'a>,
reg: &gantz_ca::Registry<G>,
heads: impl IntoIterator<Item = impl std::borrow::Borrow<gantz_ca::Head>>,
) -> HashSet<gantz_ca::CommitAddr>
where
for<'g> &'g G: Data<EdgeWeight = Edge>
+ IntoEdgesDirected
+ IntoNodeReferences
+ NodeIndexable
+ Visitable,
for<'g> <&'g G as Data>::NodeWeight: Node,
{
let mut seeds: Vec<_> = reg
.names()
.values()
.map(|&ca| gantz_ca::ContentAddr::from(ca))
.collect();
for head in heads {
if let Some(&ca) = reg.head_commit_ca(head.borrow()) {
seeds.push(gantz_ca::ContentAddr::from(ca));
}
}
transitive_commits(get_node, reg, seeds)
}
pub fn required_commits_for_heads<'a, G>(
get_node: node::GetNode<'a>,
reg: &gantz_ca::Registry<G>,
heads: impl IntoIterator<Item = impl std::borrow::Borrow<gantz_ca::Head>>,
) -> HashSet<gantz_ca::CommitAddr>
where
for<'g> &'g G: Data<EdgeWeight = Edge>
+ IntoEdgesDirected
+ IntoNodeReferences
+ NodeIndexable
+ Visitable,
for<'g> <&'g G as Data>::NodeWeight: Node,
{
let mut seeds = Vec::new();
for head in heads {
if let Some(&ca) = reg.head_commit_ca(head.borrow()) {
seeds.push(gantz_ca::ContentAddr::from(ca));
}
}
transitive_commits(get_node, reg, seeds)
}
pub fn root_names<'a, G>(get_node: node::GetNode<'a>, reg: &gantz_ca::Registry<G>) -> Vec<String>
where
for<'g> &'g G: Data<EdgeWeight = Edge>
+ IntoEdgesDirected
+ IntoNodeReferences
+ NodeIndexable
+ Visitable,
for<'g> <&'g G as Data>::NodeWeight: Node,
{
let mut referenced = HashSet::new();
for (commit_ca, _) in reg.commits() {
if let Some(graph) = reg.commit_graph_ref(commit_ca) {
for ca in graph::required_addrs(get_node, graph) {
referenced.insert(gantz_ca::CommitAddr::from(ca));
}
}
}
reg.names()
.iter()
.filter(|&(_, &commit_ca)| !referenced.contains(&commit_ca))
.map(|(name, _)| name.clone())
.collect::<BTreeSet<_>>()
.into_iter()
.collect()
}
fn transitive_commits<'a, G>(
get_node: node::GetNode<'a>,
reg: &gantz_ca::Registry<G>,
mut to_visit: Vec<gantz_ca::ContentAddr>,
) -> HashSet<gantz_ca::CommitAddr>
where
for<'g> &'g G: Data<EdgeWeight = Edge>
+ IntoEdgesDirected
+ IntoNodeReferences
+ NodeIndexable
+ Visitable,
for<'g> <&'g G as Data>::NodeWeight: Node,
{
let mut required = HashSet::new();
while let Some(addr) = to_visit.pop() {
let commit_ca = gantz_ca::CommitAddr::from(addr);
if reg.commits().contains_key(&commit_ca) && required.insert(commit_ca) {
if let Some(graph) = reg.commit_graph_ref(&commit_ca) {
to_visit.extend(graph::required_addrs(get_node, graph));
}
}
}
required
}