pedant_core/resolution/rust/snapshot/
primary.rs1use std::sync::Arc;
9
10use crate::resolution::rust::identity::{PackageId, TargetId};
11use crate::resolution::rust::project::RustProject;
12use crate::resolution::rust::target::{CargoTargetKind, RustTarget};
13
14use super::authority;
15use super::closure::{self, ClosureEntry, UnitClosure};
16use super::error::RustSnapshotError;
17use super::source::{self, RustSource};
18use super::store::{SourceStore, refuse};
19
20#[derive(Debug)]
22pub struct RustPrimaryTargetSnapshot {
23 target: TargetId,
24 kind: CargoTargetKind,
25 crate_root: Arc<str>,
26 sources: Box<[Arc<str>]>,
27}
28
29impl RustPrimaryTargetSnapshot {
30 pub fn target(&self) -> TargetId {
32 self.target
33 }
34
35 pub fn kind(&self) -> CargoTargetKind {
37 self.kind
38 }
39
40 pub fn crate_root(&self) -> &str {
42 &self.crate_root
43 }
44
45 pub fn sources(&self) -> impl ExactSizeIterator<Item = &str> {
47 self.sources.iter().map(AsRef::as_ref)
48 }
49}
50
51#[derive(Debug)]
53pub struct RustPackageSnapshot {
54 package: PackageId,
55 targets: Box<[RustPrimaryTargetSnapshot]>,
56 sources: Box<[RustSource]>,
57}
58
59impl RustPackageSnapshot {
60 pub fn package(&self) -> PackageId {
62 self.package
63 }
64
65 pub fn targets(&self) -> &[RustPrimaryTargetSnapshot] {
67 &self.targets
68 }
69
70 pub fn sources(&self) -> &[RustSource] {
72 &self.sources
73 }
74
75 pub fn source(&self, path: &str) -> Option<&RustSource> {
77 source::find(&self.sources, path)
78 }
79}
80
81#[derive(Debug, thiserror::Error)]
84#[error("{source}")]
85pub struct RustPackageSnapshotError {
86 target: Option<TargetId>,
87 #[source]
88 source: RustSnapshotError,
89}
90
91impl RustPackageSnapshotError {
92 pub fn target(&self) -> Option<TargetId> {
94 self.target
95 }
96
97 pub fn into_source(self) -> RustSnapshotError {
99 self.source
100 }
101
102 fn package(source: RustSnapshotError) -> Self {
103 Self {
104 target: None,
105 source,
106 }
107 }
108
109 fn for_target(target: TargetId, source: RustSnapshotError) -> Self {
110 Self {
111 target: Some(target),
112 source,
113 }
114 }
115}
116
117pub(in crate::resolution::rust) fn build(
119 project: &RustProject,
120 id: PackageId,
121) -> Result<RustPackageSnapshot, RustPackageSnapshotError> {
122 let package =
123 authority::validated_package(project, id).map_err(RustPackageSnapshotError::package)?;
124 let primary_targets = project
125 .package_targets(package.id())
126 .filter(|target| is_primary(target.kind()));
127 let mut store = SourceStore::new(project.root(), project.limits());
128 let mut targets = Vec::new();
129 for target in primary_targets {
130 targets.push(build_target(&mut store, target)?);
131 }
132 Ok(RustPackageSnapshot {
133 package: id,
134 targets: targets.into_boxed_slice(),
135 sources: store.finish(),
136 })
137}
138
139fn build_target(
140 store: &mut SourceStore,
141 target: &RustTarget,
142) -> Result<RustPrimaryTargetSnapshot, RustPackageSnapshotError> {
143 let entry = ClosureEntry {
144 target_name: target.name(),
145 entry_path: target.entry_path(),
146 edition: target.edition(),
147 };
148 let mut failures = Vec::new();
149 let closure = closure::walk_unit(store, &entry, &mut failures);
150 match (closure, failures.is_empty()) {
151 (Some(closure), true) => Ok(target_snapshot(target, closure)),
152 (None, _) | (Some(_), false) => Err(RustPackageSnapshotError::for_target(
153 target.id(),
154 refuse(store, failures),
155 )),
156 }
157}
158
159fn target_snapshot(target: &RustTarget, closure: UnitClosure) -> RustPrimaryTargetSnapshot {
160 RustPrimaryTargetSnapshot {
161 target: target.id(),
162 kind: target.kind(),
163 crate_root: Arc::clone(&target.entry_path),
164 sources: closure.sources,
165 }
166}
167
168fn is_primary(kind: CargoTargetKind) -> bool {
169 matches!(
170 kind,
171 CargoTargetKind::Library | CargoTargetKind::Binary | CargoTargetKind::BuildScript
172 )
173}