crap4rust/
source_root_collector.rs1use std::collections::BTreeSet;
6use std::path::{Path, PathBuf};
7
8pub struct SourceRootCollector<'a> {
9 include_test_targets: bool,
10 manifest_dir: &'a Path,
11 source_roots: BTreeSet<PathBuf>,
12}
13
14impl<'a> SourceRootCollector<'a> {
15 pub fn new(include_test_targets: bool, manifest_dir: &'a Path) -> Self {
16 Self {
17 include_test_targets,
18 manifest_dir,
19 source_roots: BTreeSet::new(),
20 }
21 }
22
23 pub fn collect(&mut self, targets: &[cargo_metadata::Target]) {
24 for target in targets {
25 self.process_target(target);
26 }
27 }
28
29 pub fn process_target(&mut self, target: &cargo_metadata::Target) {
30 if !is_selected_target(target, self.include_test_targets) {
31 return;
32 }
33
34 if target
35 .src_path
36 .extension()
37 .is_some_and(|extension| extension == "rs")
38 {
39 let path = target.src_path.clone().into_std_path_buf();
40 if let Some(parent) = path.parent() {
41 self.source_roots.insert(parent.to_path_buf());
42 }
43 }
44 }
45
46 pub fn finalize(mut self) -> Vec<PathBuf> {
47 if self.source_roots.is_empty() {
48 self.source_roots.insert(self.manifest_dir.join("src"));
49 }
50 self.source_roots.into_iter().collect()
51 }
52}
53
54pub(crate) fn is_selected_target(
55 target: &cargo_metadata::Target,
56 include_test_targets: bool,
57) -> bool {
58 let kinds = target
59 .kind
60 .iter()
61 .map(|kind| kind.to_string())
62 .collect::<Vec<_>>();
63
64 if kinds.iter().any(|kind| kind == "custom-build") {
65 return false;
66 }
67
68 if include_test_targets {
69 return kinds.iter().any(|kind| {
70 matches!(
71 kind.as_str(),
72 "lib" | "bin" | "proc-macro" | "rlib" | "dylib" | "cdylib" | "staticlib" | "test"
73 )
74 });
75 }
76
77 if kinds
78 .iter()
79 .any(|kind| matches!(kind.as_str(), "test" | "bench" | "example"))
80 {
81 return false;
82 }
83
84 kinds.iter().any(|kind| {
85 matches!(
86 kind.as_str(),
87 "lib" | "bin" | "proc-macro" | "rlib" | "dylib" | "cdylib" | "staticlib"
88 )
89 })
90}