use std::fmt;
use std::path::Path;
use crate::resolution::digest::ClaimDigest;
use super::snapshot_module::{GoSnapshotEdge, GoSnapshotModule};
use super::source::GoSource;
use super::unit::GoResolutionUnit;
pub(super) struct GoModuleClaim<'a> {
pub(super) path: &'a str,
pub(super) directory: &'a str,
pub(super) manifest: &'a str,
pub(super) depth: u32,
}
pub(super) struct GoUnitClaim<'a> {
pub(super) module: u32,
pub(super) context: &'a str,
pub(super) import_path: &'a str,
pub(super) package_name: &'a str,
pub(super) directory: &'a str,
pub(super) sources: &'a [&'a str],
}
pub(super) struct GoEdgeClaim<'a> {
pub(super) source: u32,
pub(super) target: u32,
pub(super) module_path: &'a str,
pub(super) version: &'a str,
}
pub(super) struct GoSourceClaim<'a> {
pub(super) path: &'a str,
pub(super) digest: &'a [u8; 32],
pub(super) predicates: &'a [&'a str],
}
pub(super) struct GoSnapshotClaims<'a> {
pub(super) root: &'a Path,
pub(super) modules: &'a [GoModuleClaim<'a>],
pub(super) units: &'a [GoUnitClaim<'a>],
pub(super) edges: &'a [GoEdgeClaim<'a>],
pub(super) sources: &'a [GoSourceClaim<'a>],
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GoSnapshotFingerprint {
digest: [u8; 32],
}
impl GoSnapshotFingerprint {
pub(super) fn from_claims(claims: &GoSnapshotClaims<'_>) -> Self {
let mut digest = ClaimDigest::new();
digest.field(claims.root.as_os_str().as_encoded_bytes());
digest.count(claims.modules.len());
claims
.modules
.iter()
.for_each(|module| hash_module(&mut digest, module));
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(),
}
}
}
impl fmt::Debug for GoSnapshotFingerprint {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("GoSnapshotFingerprint(redacted)")
}
}
pub(super) fn of_completed(
root: &Path,
modules: &[GoSnapshotModule],
held: (&[GoResolutionUnit], &[GoSnapshotEdge]),
sources: &[GoSource],
) -> GoSnapshotFingerprint {
let (units, edges) = held;
let stated: Box<[GoModuleClaim<'_>]> = modules.iter().map(module_claim).collect();
let memberships: Box<[Box<[&str]>]> = units.iter().map(unit_sources).collect();
let compiled: Box<[GoUnitClaim<'_>]> = units
.iter()
.zip(&memberships)
.map(|(unit, sources)| unit_claim(unit, sources))
.collect();
let required: Box<[GoEdgeClaim<'_>]> = edges.iter().map(edge_claim).collect();
let tokens: Box<[Box<[Box<str>]>]> = sources.iter().map(source_predicates).collect();
let borrowed: Box<[Box<[&str]>]> = tokens
.iter()
.map(|held| held.iter().map(|token| &**token).collect())
.collect();
let read: Box<[GoSourceClaim<'_>]> = sources
.iter()
.zip(&borrowed)
.map(|(source, predicates)| source_claim(source, predicates))
.collect();
GoSnapshotFingerprint::from_claims(&GoSnapshotClaims {
root,
modules: &stated,
units: &compiled,
edges: &required,
sources: &read,
})
}
fn module_claim(module: &GoSnapshotModule) -> GoModuleClaim<'_> {
GoModuleClaim {
path: module.path(),
directory: module.directory(),
manifest: module.manifest(),
depth: module.depth(),
}
}
fn unit_sources(unit: &GoResolutionUnit) -> Box<[&str]> {
unit.sources().iter().map(|path| &**path).collect()
}
fn unit_claim<'a>(unit: &'a GoResolutionUnit, sources: &'a [&'a str]) -> GoUnitClaim<'a> {
GoUnitClaim {
module: unit.module().index(),
context: unit.context().token(),
import_path: unit.import_path(),
package_name: unit.package_name(),
directory: unit.directory(),
sources,
}
}
fn edge_claim(edge: &GoSnapshotEdge) -> GoEdgeClaim<'_> {
GoEdgeClaim {
source: edge.source().index(),
target: edge.target().index(),
module_path: edge.module_path(),
version: edge.version(),
}
}
fn source_predicates(source: &GoSource) -> Box<[Box<str>]> {
source
.conditions()
.iter()
.map(|condition| condition.token())
.collect()
}
fn source_claim<'a>(source: &'a GoSource, predicates: &'a [&'a str]) -> GoSourceClaim<'a> {
GoSourceClaim {
path: source.path(),
digest: source.digest(),
predicates,
}
}
fn hash_module(digest: &mut ClaimDigest, module: &GoModuleClaim<'_>) {
digest.text(module.path);
digest.text(module.directory);
digest.text(module.manifest);
digest.field(&module.depth.to_le_bytes());
}
fn hash_unit(digest: &mut ClaimDigest, unit: &GoUnitClaim<'_>) {
digest.field(&unit.module.to_le_bytes());
digest.text(unit.context);
digest.text(unit.import_path);
digest.text(unit.package_name);
digest.text(unit.directory);
digest.count(unit.sources.len());
unit.sources.iter().for_each(|path| digest.text(path));
}
fn hash_edge(digest: &mut ClaimDigest, edge: &GoEdgeClaim<'_>) {
digest.field(&edge.source.to_le_bytes());
digest.field(&edge.target.to_le_bytes());
digest.text(edge.module_path);
digest.text(edge.version);
}
fn hash_source(digest: &mut ClaimDigest, source: &GoSourceClaim<'_>) {
digest.text(source.path);
digest.field(source.digest);
digest.count(source.predicates.len());
source
.predicates
.iter()
.for_each(|token| digest.text(token));
}