Skip to main content

pedant_core/resolution/rust/snapshot/
resolution.rs

1//! The multi-unit resolution snapshot: the root target, its Cargo-exposed
2//! same-package library, and every in-repository dependency library its
3//! namespace reaches.
4//!
5//! Cargo edges select units; Rust module edges select sources inside a unit.
6//! One normalized path is read and parsed once and instantiated per unit.
7
8use std::path::Path;
9use std::sync::Arc;
10
11use crate::resolution::rust::identity::{TargetId, index_of, position};
12use crate::resolution::rust::limits::ResolutionLimits;
13use crate::resolution::rust::project::RustProject;
14use crate::resolution::rust::warning::{self, RustResolutionWarning};
15
16use super::authority;
17use super::closure::{self, ClosureEntry};
18use super::error::{RustSnapshotError, SourceClosureFailure};
19use super::selection::{self, EdgeDraft, Selection, UnitDraft};
20use super::source::{self, RustSource};
21use super::store::{SourceStore, refuse};
22use super::unit::{RustResolutionUnit, RustSnapshotEdge, RustSnapshotUnitId};
23
24/// One root target, the dependency library units it resolves against, and the
25/// shared source store all of them read from.
26#[derive(Debug)]
27pub struct RustResolutionSnapshot {
28    root: Box<Path>,
29    root_target: TargetId,
30    limits: ResolutionLimits,
31    root_unit: RustSnapshotUnitId,
32    units: Box<[RustResolutionUnit]>,
33    edges: Box<[RustSnapshotEdge]>,
34    sources: Box<[RustSource]>,
35    warnings: Box<[RustResolutionWarning]>,
36}
37
38impl RustResolutionSnapshot {
39    /// The canonical repository root this snapshot was taken beneath.
40    ///
41    /// Every path a snapshot or a report states is relative to it.
42    pub fn root(&self) -> &Path {
43        &self.root
44    }
45
46    /// The target this snapshot was requested for.
47    pub fn root_target(&self) -> TargetId {
48        self.root_target
49    }
50
51    /// The unit that compiles the requested target.
52    pub fn root_unit(&self) -> RustSnapshotUnitId {
53        self.root_unit
54    }
55
56    /// The ceilings the project this snapshot came from was loaded under.
57    pub fn limits(&self) -> ResolutionLimits {
58        self.limits
59    }
60
61    /// Every selected unit, ordered by manifest path, target kind, then name.
62    pub fn units(&self) -> &[RustResolutionUnit] {
63        &self.units
64    }
65
66    /// The unit one snapshot-local identity selects.
67    pub fn unit(&self, id: RustSnapshotUnitId) -> Option<&RustResolutionUnit> {
68        self.units.get(index_of(id.index()))
69    }
70
71    /// Every selected Cargo edge, ordered by source unit, kind, then name.
72    pub fn edges(&self) -> &[RustSnapshotEdge] {
73        &self.edges
74    }
75
76    /// Every distinct source across all units, sorted by path.
77    pub fn sources(&self) -> &[RustSource] {
78        &self.sources
79    }
80
81    /// Non-fatal project-layout diagnostics discovered while walking this
82    /// snapshot's complete source closures.
83    pub fn warnings(&self) -> &[RustResolutionWarning] {
84        &self.warnings
85    }
86
87    /// The source at one repository-relative path.
88    pub fn source(&self, path: &str) -> Option<&RustSource> {
89        source::find(&self.sources, path)
90    }
91}
92
93/// Validate authority, select the units, then walk each unit's closure.
94pub(in crate::resolution::rust) fn build(
95    project: &RustProject,
96    id: TargetId,
97) -> Result<RustResolutionSnapshot, RustSnapshotError> {
98    let root = authority::validated_target(project, id)?;
99    let selection = selection::select(project, root)?;
100    let mut store = SourceStore::new(project.root(), project.limits());
101    let mut failures = Vec::new();
102    let units = build_units(&selection, &mut store, &mut failures);
103    match failures.is_empty() {
104        false => Err(refuse(&store, failures)),
105        true => {
106            let warnings = warning::shared_sources(&units);
107            Ok(RustResolutionSnapshot {
108                root: Box::from(project.root()),
109                root_target: id,
110                limits: project.limits(),
111                root_unit: RustSnapshotUnitId::new(selection.root),
112                edges: build_edges(&selection.edges),
113                sources: store.finish(),
114                units,
115                warnings,
116            })
117        }
118    }
119}
120
121fn build_units(
122    selection: &Selection,
123    store: &mut SourceStore,
124    failures: &mut Vec<SourceClosureFailure>,
125) -> Box<[RustResolutionUnit]> {
126    let mut units = Vec::new();
127    for (index, draft) in selection.units.iter().enumerate() {
128        let seen = failures.len();
129        units.extend(build_unit((draft, index), store, failures));
130        if failures
131            .iter()
132            .skip(seen)
133            .any(SourceClosureFailure::is_fatal)
134        {
135            break;
136        }
137    }
138    units.into_boxed_slice()
139}
140
141fn build_unit(
142    draft: (&UnitDraft, usize),
143    store: &mut SourceStore,
144    failures: &mut Vec<SourceClosureFailure>,
145) -> Option<RustResolutionUnit> {
146    let (unit, index) = draft;
147    let entry = ClosureEntry {
148        target_name: &unit.target_name,
149        entry_path: &unit.entry,
150        edition: unit.edition,
151    };
152    let closure = closure::walk_unit(store, &entry, failures)?;
153    Some(RustResolutionUnit {
154        id: RustSnapshotUnitId::new(position(index)),
155        package: unit.package,
156        target: unit.target,
157        name: Arc::clone(&unit.target_name),
158        manifest: Arc::clone(&unit.manifest),
159        kind: unit.kind,
160        activation: unit.predicate.activation(),
161        crate_root: Arc::clone(&unit.entry),
162        modules: closure.modules,
163        sources: closure.sources,
164    })
165}
166
167fn build_edges(drafts: &[EdgeDraft]) -> Box<[RustSnapshotEdge]> {
168    drafts
169        .iter()
170        .map(|draft| RustSnapshotEdge {
171            source: RustSnapshotUnitId::new(draft.source),
172            target: RustSnapshotUnitId::new(draft.target),
173            name: Arc::clone(&draft.name),
174            kind: draft.kind,
175            activation: draft.predicate.activation(),
176        })
177        .collect()
178}