use super::prelude::*;
use super::units::missing;
use super::{SemanticSnapshotClaim, SemanticSnapshotMismatch};
pub(super) fn check_edges(
context: &SemanticContext,
claim: &SemanticSnapshotClaim,
crates: &[Crate],
) -> Result<(), SemanticSnapshotMismatch> {
check_claimed_edges(context, claim, crates)?;
check_no_extra_edges(context, crates, &claimed_pairs(claim, crates))
}
fn check_claimed_edges(
context: &SemanticContext,
claim: &SemanticSnapshotClaim,
crates: &[Crate],
) -> Result<(), SemanticSnapshotMismatch> {
let db = context.host.raw_database();
for edge in &claim.edges {
let (Some(source), Some(target)) = (crates.get(edge.source), crates.get(edge.target))
else {
return Err(SemanticSnapshotMismatch::UnitGraph {
detail: Box::from("an edge names a unit the snapshot does not hold"),
});
};
let alias = edge.alias.replace('-', "_");
let stated = source
.dependencies(db)
.into_iter()
.any(|found| found.krate == *target && found.name.as_str() == alias);
if !stated {
return Err(missing(edge.conditional, &edge.alias));
}
}
Ok(())
}
fn claimed_pairs(claim: &SemanticSnapshotClaim, crates: &[Crate]) -> BTreeSet<(usize, usize)> {
claim
.edges
.iter()
.filter_map(|edge| {
let target = crates.get(edge.target)?;
Some((edge.source, unit_of(crates, *target)?))
})
.collect()
}
fn unit_of(crates: &[Crate], krate: Crate) -> Option<usize> {
crates.iter().position(|found| *found == krate)
}
fn check_no_extra_edges(
context: &SemanticContext,
crates: &[Crate],
claimed: &BTreeSet<(usize, usize)>,
) -> Result<(), SemanticSnapshotMismatch> {
for (index, krate) in crates.iter().enumerate() {
check_unit_edges(context, crates, claimed, (index, *krate))?;
}
Ok(())
}
fn check_unit_edges(
context: &SemanticContext,
crates: &[Crate],
claimed: &BTreeSet<(usize, usize)>,
unit: (usize, Crate),
) -> Result<(), SemanticSnapshotMismatch> {
let (index, krate) = unit;
let db = context.host.raw_database();
let unclaimed = krate
.dependencies(db)
.into_iter()
.filter_map(|dependency| {
let target = unit_of(crates, dependency.krate)?;
Some((dependency, target))
})
.find(|(_, target)| !claimed.contains(&(index, *target)));
match unclaimed {
Some((dependency, _)) => Err(SemanticSnapshotMismatch::UnitGraph {
detail: format!(
"the database exposes an unclaimed dependency named {}",
dependency.name.as_str()
)
.into_boxed_str(),
}),
None => Ok(()),
}
}