cargo_metadata/
messages.rs

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)]
32#[non_exhaustive]
33pub 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
58impl Default for ArtifactDebuginfo {
59    fn default() -> Self {
60        ArtifactDebuginfo::None
61    }
62}
63
64impl 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) => n.serialize(serializer),
76            Self::UnknownString(s) => s.serialize(serializer),
77        }
78    }
79}
80
81impl<'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
142impl 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("line-directives-only"),
149            ArtifactDebuginfo::LineTablesOnly => f.write_str("line-tables-only"),
150            ArtifactDebuginfo::UnknownInt(n) => write!(f, "{}", n),
151            ArtifactDebuginfo::UnknownString(s) => f.write_str(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)))]
161pub 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)))]
188pub 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)))]
202pub 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)))]
225pub 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")]
234pub 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
252impl 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
260impl 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.
267pub struct MessageIter<R> {
268    input: R,
269}
270
271impl<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::new();
275        self.input
276            .read_line(&mut line)
277            .map(|n| {
278                if n == 0 {
279                    None
280                } else {
281                    if line.ends_with('\n') {
282                        line.truncate(line.len() - 1);
283                    }
284                    let mut 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.
294type 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")]
300pub fn parse_messages<R: Read>(input: R) -> MessageIterator<R> {
301    serde_json::Deserializer::from_reader(input).into_iter::<Message>()
302}