]> git.proxmox.com Git - cargo.git/blob - src/cargo/core/compiler/unit_graph.rs
Move string interning to util
[cargo.git] / src / cargo / core / compiler / unit_graph.rs
1 use crate::core::compiler::Unit;
2 use crate::core::compiler::{CompileKind, CompileMode};
3 use crate::core::profiles::{Profile, UnitFor};
4 use crate::core::{nightly_features_allowed, PackageId, Target};
5 use crate::util::interning::InternedString;
6 use crate::util::CargoResult;
7 use std::collections::HashMap;
8 use std::io::Write;
9
10 /// The dependency graph of Units.
11 pub type UnitGraph = HashMap<Unit, Vec<UnitDep>>;
12
13 /// A unit dependency.
14 #[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
15 pub struct UnitDep {
16 /// The dependency unit.
17 pub unit: Unit,
18 /// The purpose of this dependency (a dependency for a test, or a build
19 /// script, etc.).
20 pub unit_for: UnitFor,
21 /// The name the parent uses to refer to this dependency.
22 pub extern_crate_name: InternedString,
23 /// Whether or not this is a public dependency.
24 pub public: bool,
25 /// If `true`, the dependency should not be added to Rust's prelude.
26 pub noprelude: bool,
27 }
28
29 const VERSION: u32 = 1;
30
31 #[derive(serde::Serialize)]
32 struct SerializedUnitGraph<'a> {
33 version: u32,
34 units: Vec<SerializedUnit<'a>>,
35 roots: Vec<usize>,
36 }
37
38 #[derive(serde::Serialize)]
39 struct SerializedUnit<'a> {
40 pkg_id: PackageId,
41 target: &'a Target,
42 profile: &'a Profile,
43 platform: CompileKind,
44 mode: CompileMode,
45 features: &'a Vec<InternedString>,
46 #[serde(skip_serializing_if = "std::ops::Not::not")] // hide for unstable build-std
47 is_std: bool,
48 dependencies: Vec<SerializedUnitDep>,
49 }
50
51 #[derive(serde::Serialize)]
52 struct SerializedUnitDep {
53 index: usize,
54 extern_crate_name: InternedString,
55 // This is only set on nightly since it is unstable.
56 #[serde(skip_serializing_if = "Option::is_none")]
57 public: Option<bool>,
58 // This is only set on nightly since it is unstable.
59 #[serde(skip_serializing_if = "Option::is_none")]
60 noprelude: Option<bool>,
61 // Intentionally not including `unit_for` because it is a low-level
62 // internal detail that is mostly used for building the graph.
63 }
64
65 pub fn emit_serialized_unit_graph(root_units: &[Unit], unit_graph: &UnitGraph) -> CargoResult<()> {
66 let is_nightly = nightly_features_allowed();
67 let mut units: Vec<(&Unit, &Vec<UnitDep>)> = unit_graph.iter().collect();
68 units.sort_unstable();
69 // Create a map for quick lookup for dependencies.
70 let indices: HashMap<&Unit, usize> = units
71 .iter()
72 .enumerate()
73 .map(|(i, val)| (val.0, i))
74 .collect();
75 let roots = root_units.iter().map(|root| indices[root]).collect();
76 let ser_units = units
77 .iter()
78 .map(|(unit, unit_deps)| {
79 let dependencies = unit_deps
80 .iter()
81 .map(|unit_dep| {
82 // https://github.com/rust-lang/rust/issues/64260 when stabilized.
83 let (public, noprelude) = if is_nightly {
84 (Some(unit_dep.public), Some(unit_dep.noprelude))
85 } else {
86 (None, None)
87 };
88 SerializedUnitDep {
89 index: indices[&unit_dep.unit],
90 extern_crate_name: unit_dep.extern_crate_name,
91 public,
92 noprelude,
93 }
94 })
95 .collect();
96 SerializedUnit {
97 pkg_id: unit.pkg.package_id(),
98 target: &unit.target,
99 profile: &unit.profile,
100 platform: unit.kind,
101 mode: unit.mode,
102 features: &unit.features,
103 is_std: unit.is_std,
104 dependencies,
105 }
106 })
107 .collect();
108 let s = SerializedUnitGraph {
109 version: VERSION,
110 units: ser_units,
111 roots,
112 };
113
114 let stdout = std::io::stdout();
115 let mut lock = stdout.lock();
116 serde_json::to_writer(&mut lock, &s)?;
117 drop(writeln!(lock));
118 Ok(())
119 }