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