1 | use super::{Diagnostic, PackageId, Target}; |
2 | use camino::Utf8PathBuf; |
3 | #[cfg (feature = "builder" )] |
4 | use derive_builder::Builder; |
5 | use serde::{de, ser, Deserialize, Serialize}; |
6 | use std::fmt::{self, Write}; |
7 | use std::io::{self, BufRead, Read}; |
8 | |
9 | /// Profile settings used to determine which compiler flags to use for a |
10 | /// target. |
11 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
12 | #[cfg_attr (feature = "builder" , derive(Builder))] |
13 | #[non_exhaustive ] |
14 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
15 | pub struct ArtifactProfile { |
16 | /// Optimization level. Possible values are 0-3, s or z. |
17 | pub opt_level: String, |
18 | /// The kind of debug information. |
19 | #[serde(default)] |
20 | pub debuginfo: ArtifactDebuginfo, |
21 | /// State of the `cfg(debug_assertions)` directive, enabling macros like |
22 | /// `debug_assert!` |
23 | pub debug_assertions: bool, |
24 | /// State of the overflow checks. |
25 | pub overflow_checks: bool, |
26 | /// Whether this profile is a test |
27 | pub test: bool, |
28 | } |
29 | |
30 | /// The kind of debug information included in the artifact. |
31 | #[derive (Debug, Clone, PartialEq, Eq, Hash)] |
32 | #[non_exhaustive ] |
33 | pub enum ArtifactDebuginfo { |
34 | /// No debug information. |
35 | None, |
36 | /// Line directives only. |
37 | LineDirectivesOnly, |
38 | /// Line tables only. |
39 | LineTablesOnly, |
40 | /// Debug information without type or variable-level information. |
41 | Limited, |
42 | /// Full debug information. |
43 | Full, |
44 | /// An unknown integer level. |
45 | /// |
46 | /// This may be produced by a version of rustc in the future that has |
47 | /// additional levels represented by an integer that are not known by this |
48 | /// version of `cargo_metadata`. |
49 | UnknownInt(i64), |
50 | /// An unknown string level. |
51 | /// |
52 | /// This may be produced by a version of rustc in the future that has |
53 | /// additional levels represented by a string that are not known by this |
54 | /// version of `cargo_metadata`. |
55 | UnknownString(String), |
56 | } |
57 | |
58 | impl Default for ArtifactDebuginfo { |
59 | fn default() -> Self { |
60 | ArtifactDebuginfo::None |
61 | } |
62 | } |
63 | |
64 | impl ser::Serialize for ArtifactDebuginfo { |
65 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
66 | where |
67 | S: ser::Serializer, |
68 | { |
69 | match self { |
70 | Self::None => 0.serialize(serializer), |
71 | Self::LineDirectivesOnly => "line-directives-only" .serialize(serializer), |
72 | Self::LineTablesOnly => "line-tables-only" .serialize(serializer), |
73 | Self::Limited => 1.serialize(serializer), |
74 | Self::Full => 2.serialize(serializer), |
75 | Self::UnknownInt(n: &i64) => n.serialize(serializer), |
76 | Self::UnknownString(s: &String) => s.serialize(serializer), |
77 | } |
78 | } |
79 | } |
80 | |
81 | impl<'de> de::Deserialize<'de> for ArtifactDebuginfo { |
82 | fn deserialize<D>(d: D) -> Result<ArtifactDebuginfo, D::Error> |
83 | where |
84 | D: de::Deserializer<'de>, |
85 | { |
86 | struct Visitor; |
87 | |
88 | impl<'de> de::Visitor<'de> for Visitor { |
89 | type Value = ArtifactDebuginfo; |
90 | |
91 | fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { |
92 | formatter.write_str("an integer or string" ) |
93 | } |
94 | |
95 | fn visit_i64<E>(self, value: i64) -> Result<ArtifactDebuginfo, E> |
96 | where |
97 | E: de::Error, |
98 | { |
99 | let debuginfo = match value { |
100 | 0 => ArtifactDebuginfo::None, |
101 | 1 => ArtifactDebuginfo::Limited, |
102 | 2 => ArtifactDebuginfo::Full, |
103 | n => ArtifactDebuginfo::UnknownInt(n), |
104 | }; |
105 | Ok(debuginfo) |
106 | } |
107 | |
108 | fn visit_u64<E>(self, value: u64) -> Result<ArtifactDebuginfo, E> |
109 | where |
110 | E: de::Error, |
111 | { |
112 | self.visit_i64(value as i64) |
113 | } |
114 | |
115 | fn visit_str<E>(self, value: &str) -> Result<ArtifactDebuginfo, E> |
116 | where |
117 | E: de::Error, |
118 | { |
119 | let debuginfo = match value { |
120 | "none" => ArtifactDebuginfo::None, |
121 | "limited" => ArtifactDebuginfo::Limited, |
122 | "full" => ArtifactDebuginfo::Full, |
123 | "line-directives-only" => ArtifactDebuginfo::LineDirectivesOnly, |
124 | "line-tables-only" => ArtifactDebuginfo::LineTablesOnly, |
125 | s => ArtifactDebuginfo::UnknownString(s.to_string()), |
126 | }; |
127 | Ok(debuginfo) |
128 | } |
129 | |
130 | fn visit_unit<E>(self) -> Result<ArtifactDebuginfo, E> |
131 | where |
132 | E: de::Error, |
133 | { |
134 | Ok(ArtifactDebuginfo::None) |
135 | } |
136 | } |
137 | |
138 | d.deserialize_any(Visitor) |
139 | } |
140 | } |
141 | |
142 | impl fmt::Display for ArtifactDebuginfo { |
143 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
144 | match self { |
145 | ArtifactDebuginfo::None => f.write_char('0' ), |
146 | ArtifactDebuginfo::Limited => f.write_char('1' ), |
147 | ArtifactDebuginfo::Full => f.write_char('2' ), |
148 | ArtifactDebuginfo::LineDirectivesOnly => f.write_str(data:"line-directives-only" ), |
149 | ArtifactDebuginfo::LineTablesOnly => f.write_str(data:"line-tables-only" ), |
150 | ArtifactDebuginfo::UnknownInt(n: &i64) => write!(f, " {}" , n), |
151 | ArtifactDebuginfo::UnknownString(s: &String) => f.write_str(data:s), |
152 | } |
153 | } |
154 | } |
155 | |
156 | /// A compiler-generated file. |
157 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
158 | #[cfg_attr (feature = "builder" , derive(Builder))] |
159 | #[non_exhaustive ] |
160 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
161 | pub struct Artifact { |
162 | /// The package this artifact belongs to |
163 | pub package_id: PackageId, |
164 | /// Path to the `Cargo.toml` file |
165 | #[serde(default)] |
166 | pub manifest_path: Utf8PathBuf, |
167 | /// The target this artifact was compiled for |
168 | pub target: Target, |
169 | /// The profile this artifact was compiled with |
170 | pub profile: ArtifactProfile, |
171 | /// The enabled features for this artifact |
172 | pub features: Vec<String>, |
173 | /// The full paths to the generated artifacts |
174 | /// (e.g. binary file and separate debug info) |
175 | pub filenames: Vec<Utf8PathBuf>, |
176 | /// Path to the executable file |
177 | pub executable: Option<Utf8PathBuf>, |
178 | /// If true, then the files were already generated |
179 | pub fresh: bool, |
180 | } |
181 | |
182 | /// Message left by the compiler |
183 | // TODO: Better name. This one comes from machine_message.rs |
184 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
185 | #[cfg_attr (feature = "builder" , derive(Builder))] |
186 | #[non_exhaustive ] |
187 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
188 | pub struct CompilerMessage { |
189 | /// The package this message belongs to |
190 | pub package_id: PackageId, |
191 | /// The target this message is aimed at |
192 | pub target: Target, |
193 | /// The message the compiler sent. |
194 | pub message: Diagnostic, |
195 | } |
196 | |
197 | /// Output of a build script execution. |
198 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
199 | #[cfg_attr (feature = "builder" , derive(Builder))] |
200 | #[non_exhaustive ] |
201 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
202 | pub struct BuildScript { |
203 | /// The package this build script execution belongs to |
204 | pub package_id: PackageId, |
205 | /// The libs to link |
206 | pub linked_libs: Vec<Utf8PathBuf>, |
207 | /// The paths to search when resolving libs |
208 | pub linked_paths: Vec<Utf8PathBuf>, |
209 | /// Various `--cfg` flags to pass to the compiler |
210 | pub cfgs: Vec<String>, |
211 | /// The environment variables to add to the compilation |
212 | pub env: Vec<(String, String)>, |
213 | /// The `OUT_DIR` environment variable where this script places its output |
214 | /// |
215 | /// Added in Rust 1.41. |
216 | #[serde(default)] |
217 | pub out_dir: Utf8PathBuf, |
218 | } |
219 | |
220 | /// Final result of a build. |
221 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
222 | #[cfg_attr (feature = "builder" , derive(Builder))] |
223 | #[non_exhaustive ] |
224 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
225 | pub struct BuildFinished { |
226 | /// Whether or not the build finished successfully. |
227 | pub success: bool, |
228 | } |
229 | |
230 | /// A cargo message |
231 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
232 | #[non_exhaustive ] |
233 | #[serde(tag = "reason" , rename_all = "kebab-case" )] |
234 | pub enum Message { |
235 | /// The compiler generated an artifact |
236 | CompilerArtifact(Artifact), |
237 | /// The compiler wants to display a message |
238 | CompilerMessage(CompilerMessage), |
239 | /// A build script successfully executed. |
240 | BuildScriptExecuted(BuildScript), |
241 | /// The build has finished. |
242 | /// |
243 | /// This is emitted at the end of the build as the last message. |
244 | /// Added in Rust 1.44. |
245 | BuildFinished(BuildFinished), |
246 | /// A line of text which isn't a cargo or compiler message. |
247 | /// Line separator is not included |
248 | #[serde(skip)] |
249 | TextLine(String), |
250 | } |
251 | |
252 | impl Message { |
253 | /// Creates an iterator of Message from a Read outputting a stream of JSON |
254 | /// messages. For usage information, look at the top-level documentation. |
255 | pub fn parse_stream<R: Read>(input: R) -> MessageIter<R> { |
256 | MessageIter { input } |
257 | } |
258 | } |
259 | |
260 | impl fmt::Display for CompilerMessage { |
261 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
262 | write!(f, " {}" , self.message) |
263 | } |
264 | } |
265 | |
266 | /// An iterator of Messages. |
267 | pub struct MessageIter<R> { |
268 | input: R, |
269 | } |
270 | |
271 | impl<R: BufRead> Iterator for MessageIter<R> { |
272 | type Item = io::Result<Message>; |
273 | fn next(&mut self) -> Option<Self::Item> { |
274 | let mut line: String = String::new(); |
275 | self.input |
276 | .read_line(&mut line) |
277 | .map(|n: usize| { |
278 | if n == 0 { |
279 | None |
280 | } else { |
281 | if line.ends_with(' \n' ) { |
282 | line.truncate(new_len:line.len() - 1); |
283 | } |
284 | let mut deserializer: Deserializer> = serde_json::Deserializer::from_str(&line); |
285 | deserializer.disable_recursion_limit(); |
286 | Some(Message::deserialize(&mut deserializer).unwrap_or(Message::TextLine(line))) |
287 | } |
288 | }) |
289 | .transpose() |
290 | } |
291 | } |
292 | |
293 | /// An iterator of Message. |
294 | type MessageIterator<R> = |
295 | serde_json::StreamDeserializer<'static, serde_json::de::IoRead<R>, Message>; |
296 | |
297 | /// Creates an iterator of Message from a Read outputting a stream of JSON |
298 | /// messages. For usage information, look at the top-level documentation. |
299 | #[deprecated (note = "Use Message::parse_stream instead" )] |
300 | pub fn parse_messages<R: Read>(input: R) -> MessageIterator<R> { |
301 | serde_json::Deserializer::from_reader(input).into_iter::<Message>() |
302 | } |
303 | |