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#[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 pub opt_level: String,
18 #[serde(default)]
20 pub debuginfo: ArtifactDebuginfo,
21 pub debug_assertions: bool,
24 pub overflow_checks: bool,
26 pub test: bool,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
32#[non_exhaustive]
33pub enum ArtifactDebuginfo {
34 #[default]
36 None,
37 LineDirectivesOnly,
39 LineTablesOnly,
41 Limited,
43 Full,
45 UnknownInt(i64),
51 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#[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 pub package_id: PackageId,
159 #[serde(default)]
161 pub manifest_path: Utf8PathBuf,
162 pub target: Target,
164 pub profile: ArtifactProfile,
166 pub features: Vec<String>,
168 pub filenames: Vec<Utf8PathBuf>,
171 pub executable: Option<Utf8PathBuf>,
173 pub fresh: bool,
175}
176
177#[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 pub package_id: PackageId,
186 pub target: Target,
188 pub message: Diagnostic,
190}
191
192#[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 pub package_id: PackageId,
200 pub linked_libs: Vec<Utf8PathBuf>,
202 pub linked_paths: Vec<Utf8PathBuf>,
204 pub cfgs: Vec<String>,
206 pub env: Vec<(String, String)>,
208 #[serde(default)]
212 pub out_dir: Utf8PathBuf,
213}
214
215#[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 pub success: bool,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
227#[non_exhaustive]
228#[serde(tag = "reason", rename_all = "kebab-case")]
229pub enum Message {
230 CompilerArtifact(Artifact),
232 CompilerMessage(CompilerMessage),
234 BuildScriptExecuted(BuildScript),
236 BuildFinished(BuildFinished),
241 #[serde(skip)]
244 TextLine(String),
245}
246
247impl Message {
248 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
261pub 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
288type MessageIterator<R> =
290 serde_json::StreamDeserializer<'static, serde_json::de::IoRead<R>, Message>;
291
292#[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}