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