use std::sync::Arc;
use sha2::{Digest, Sha256};
use crate::ir::semantic::{
SemanticEdgeClaim, SemanticSnapshotClaim, SemanticSourceClaim, SemanticUnitClaim,
};
use crate::resolution::rust::dependency::DependencyActivation;
use crate::resolution::rust::identity::index_of;
use crate::resolution::rust::snapshot::{RustResolutionSnapshot, RustSource};
use super::target::crate_name;
pub(super) fn state(snapshot: &RustResolutionSnapshot) -> SemanticSnapshotClaim {
let units: Box<[SemanticUnitClaim]> = snapshot
.units()
.iter()
.map(|unit| SemanticUnitClaim {
name: crate_name(unit),
crate_root: Arc::from(unit.crate_root()),
sources: unit.sources().iter().map(Arc::clone).collect(),
conditional: is_conditional(unit.activation()),
})
.collect();
let edges: Box<[SemanticEdgeClaim]> = snapshot
.edges()
.iter()
.map(|edge| SemanticEdgeClaim {
source: index_of(edge.source().index()),
target: index_of(edge.target().index()),
alias: Arc::from(edge.name()),
conditional: is_conditional(edge.activation()),
})
.collect();
let sources: Box<[SemanticSourceClaim]> = snapshot.sources().iter().map(source).collect();
let requested = index_of(snapshot.root_unit().index());
SemanticSnapshotClaim {
fingerprint: fingerprint(snapshot, (&units, &edges, &sources), requested),
root: Box::from(snapshot.root()),
requested,
units,
edges,
sources,
}
}
fn source(source: &RustSource) -> SemanticSourceClaim {
SemanticSourceClaim {
path: Arc::from(source.path()),
digest: *source.digest(),
}
}
fn is_conditional(activation: &DependencyActivation) -> bool {
matches!(activation, DependencyActivation::Conditional(_))
}
fn fingerprint(
snapshot: &RustResolutionSnapshot,
stated: (
&[SemanticUnitClaim],
&[SemanticEdgeClaim],
&[SemanticSourceClaim],
),
requested: usize,
) -> [u8; 32] {
let (units, edges, sources) = stated;
let mut hasher = Sha256::new();
field(&mut hasher, snapshot.root().to_string_lossy().as_bytes());
field(&mut hasher, &requested.to_le_bytes());
units.iter().for_each(|unit| hash_unit(&mut hasher, unit));
edges.iter().for_each(|edge| hash_edge(&mut hasher, edge));
sources
.iter()
.for_each(|source| hash_source(&mut hasher, source));
hasher.finalize().into()
}
fn hash_unit(hasher: &mut Sha256, unit: &SemanticUnitClaim) {
field(hasher, unit.name.as_bytes());
field(hasher, unit.crate_root.as_bytes());
field(hasher, &[u8::from(unit.conditional)]);
unit.sources
.iter()
.for_each(|path| field(hasher, path.as_bytes()));
}
fn hash_edge(hasher: &mut Sha256, edge: &SemanticEdgeClaim) {
field(hasher, &edge.source.to_le_bytes());
field(hasher, &edge.target.to_le_bytes());
field(hasher, edge.alias.as_bytes());
field(hasher, &[u8::from(edge.conditional)]);
}
fn hash_source(hasher: &mut Sha256, source: &SemanticSourceClaim) {
field(hasher, source.path.as_bytes());
field(hasher, &source.digest);
}
fn field(hasher: &mut Sha256, bytes: &[u8]) {
hasher.update(bytes.len().to_le_bytes());
hasher.update(bytes);
}