use std::fmt;
use std::path::Path;
use crate::resolution::digest::ClaimDigest;
use super::dependency::{CargoDependencyKind, DependencyActivation};
use super::snapshot::{RustResolutionUnit, RustSnapshotEdge, RustSource};
pub(in crate::resolution::rust) struct UnitClaim<'a> {
pub(in crate::resolution::rust) name: &'a str,
pub(in crate::resolution::rust) manifest: &'a str,
pub(in crate::resolution::rust) kind: &'a str,
pub(in crate::resolution::rust) crate_root: &'a str,
pub(in crate::resolution::rust) predicate: Option<&'a str>,
pub(in crate::resolution::rust) sources: &'a [&'a str],
}
pub(in crate::resolution::rust) struct EdgeClaim<'a> {
pub(in crate::resolution::rust) source: u32,
pub(in crate::resolution::rust) target: u32,
pub(in crate::resolution::rust) alias: &'a str,
pub(in crate::resolution::rust) kind: CargoDependencyKind,
pub(in crate::resolution::rust) predicate: Option<&'a str>,
}
pub(in crate::resolution::rust) struct SourceClaim<'a> {
pub(in crate::resolution::rust) path: &'a str,
pub(in crate::resolution::rust) digest: &'a [u8; 32],
}
pub(in crate::resolution::rust) struct SnapshotClaims<'a> {
pub(in crate::resolution::rust) root: &'a Path,
pub(in crate::resolution::rust) requested: u32,
pub(in crate::resolution::rust) units: &'a [UnitClaim<'a>],
pub(in crate::resolution::rust) edges: &'a [EdgeClaim<'a>],
pub(in crate::resolution::rust) sources: &'a [SourceClaim<'a>],
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RustSnapshotFingerprint {
digest: [u8; 32],
}
impl RustSnapshotFingerprint {
pub(in crate::resolution::rust) fn from_claims(claims: &SnapshotClaims<'_>) -> Self {
let mut digest = ClaimDigest::new();
digest.field(claims.root.as_os_str().as_encoded_bytes());
digest.field(&claims.requested.to_le_bytes());
digest.count(claims.units.len());
claims
.units
.iter()
.for_each(|unit| hash_unit(&mut digest, unit));
digest.count(claims.edges.len());
claims
.edges
.iter()
.for_each(|edge| hash_edge(&mut digest, edge));
digest.count(claims.sources.len());
claims
.sources
.iter()
.for_each(|source| hash_source(&mut digest, source));
Self {
digest: digest.finish(),
}
}
#[cfg(feature = "semantic")]
pub(in crate::resolution::rust) fn bytes(&self) -> &[u8; 32] {
&self.digest
}
}
impl fmt::Debug for RustSnapshotFingerprint {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("RustSnapshotFingerprint(redacted)")
}
}
pub(in crate::resolution::rust) fn of_completed(
root: &Path,
requested: u32,
units: &[RustResolutionUnit],
edges: &[RustSnapshotEdge],
sources: &[RustSource],
) -> RustSnapshotFingerprint {
let memberships: Box<[Box<[&str]>]> = units.iter().map(unit_sources).collect();
let stated: Box<[UnitClaim<'_>]> = units
.iter()
.zip(&memberships)
.map(|(unit, sources)| unit_claim(unit, sources))
.collect();
let selected: Box<[EdgeClaim<'_>]> = edges.iter().map(edge_claim).collect();
let read: Box<[SourceClaim<'_>]> = sources.iter().map(source_claim).collect();
RustSnapshotFingerprint::from_claims(&SnapshotClaims {
root,
requested,
units: &stated,
edges: &selected,
sources: &read,
})
}
fn unit_sources(unit: &RustResolutionUnit) -> Box<[&str]> {
unit.sources().iter().map(|path| &**path).collect()
}
fn unit_claim<'a>(unit: &'a RustResolutionUnit, sources: &'a [&'a str]) -> UnitClaim<'a> {
UnitClaim {
name: unit.name(),
manifest: unit.manifest_path(),
kind: unit.kind().token(),
crate_root: unit.crate_root(),
predicate: predicate(unit.activation()),
sources,
}
}
fn edge_claim(edge: &RustSnapshotEdge) -> EdgeClaim<'_> {
EdgeClaim {
source: edge.source().index(),
target: edge.target().index(),
alias: edge.name(),
kind: edge.kind(),
predicate: predicate(edge.activation()),
}
}
fn source_claim(source: &RustSource) -> SourceClaim<'_> {
SourceClaim {
path: source.path(),
digest: source.digest(),
}
}
fn predicate(activation: &DependencyActivation) -> Option<&str> {
match activation {
DependencyActivation::Always => None,
DependencyActivation::Conditional(predicate) => Some(predicate),
}
}
fn hash_unit(digest: &mut ClaimDigest, unit: &UnitClaim<'_>) {
digest.text(unit.name);
digest.text(unit.manifest);
digest.text(unit.kind);
digest.text(unit.crate_root);
digest.optional_text(unit.predicate);
digest.count(unit.sources.len());
unit.sources.iter().for_each(|path| digest.text(path));
}
fn hash_edge(digest: &mut ClaimDigest, edge: &EdgeClaim<'_>) {
digest.field(&edge.source.to_le_bytes());
digest.field(&edge.target.to_le_bytes());
digest.text(edge.alias);
digest.field(&[kind_tag(edge.kind)]);
digest.optional_text(edge.predicate);
}
fn hash_source(digest: &mut ClaimDigest, source: &SourceClaim<'_>) {
digest.text(source.path);
digest.field(source.digest);
}
fn kind_tag(kind: CargoDependencyKind) -> u8 {
match kind {
CargoDependencyKind::Normal => 0,
CargoDependencyKind::Development => 1,
CargoDependencyKind::Build => 2,
}
}