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, 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) => n.serialize(serializer),
71            Self::UnknownString(s) => 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("line-directives-only"),
144            ArtifactDebuginfo::LineTablesOnly => f.write_str("line-tables-only"),
145            ArtifactDebuginfo::UnknownInt(n) => write!(f, "{}", n),
146            ArtifactDebuginfo::UnknownString(s) => f.write_str(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::new();
270        self.input
271            .read_line(&mut line)
272            .map(|n| {
273                if n == 0 {
274                    None
275                } else {
276                    if line.ends_with('\n') {
277                        line.truncate(line.len() - 1);
278                    }
279                    let mut 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}