Skip to content

Commit

Permalink
Fix busy-loop when proc-macro prints to stdout
Browse files Browse the repository at this point in the history
  • Loading branch information
matklad committed Apr 4, 2020
1 parent ea84dc3 commit 27bbd83
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 7 deletions.
9 changes: 5 additions & 4 deletions src/lib.rs
Expand Up @@ -56,7 +56,8 @@
//! .spawn()
//! .unwrap();
//!
//! for message in cargo_metadata::parse_messages(command.stdout.take().unwrap()) {
//! let reader = std::io::BufReader::new(command.stdout.take().unwrap());
//! for message in cargo_metadata::Message::parse_stream(reader) {
//! match message.unwrap() {
//! Message::CompilerMessage(msg) => {
//! println!("{:?}", msg);
Expand Down Expand Up @@ -92,9 +93,9 @@ use semver::Version;
pub use dependency::{Dependency, DependencyKind};
use diagnostic::Diagnostic;
pub use errors::{Error, Result};
pub use messages::{
parse_messages, Artifact, ArtifactProfile, BuildScript, CompilerMessage, Message,
};
pub use messages::{Artifact, ArtifactProfile, BuildScript, CompilerMessage, Message, MessageIter};
#[allow(deprecated)]
pub use messages::parse_messages;

mod dependency;
pub mod diagnostic;
Expand Down
27 changes: 26 additions & 1 deletion src/messages.rs
@@ -1,7 +1,7 @@
use super::{Diagnostic, PackageId, Target};
use serde_json;
use std::fmt;
use std::io::Read;
use std::io::{self, BufRead, Lines, Read};
use std::path::PathBuf;

/// Profile settings used to determine which compiler flags to use for a
Expand Down Expand Up @@ -100,18 +100,43 @@ pub enum Message {
Unknown,
}

impl Message {
/// Creates an iterator of Message from a Read outputting a stream of JSON
/// messages. For usage information, look at the top-level documentation.
pub fn parse_stream<R: BufRead>(input: R) -> MessageIter<R> {
MessageIter {
lines: input.lines(),
}
}
}

impl fmt::Display for CompilerMessage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.message)
}
}

/// An iterator of Messages.
pub struct MessageIter<R> {
lines: Lines<R>,
}

impl<R: BufRead> Iterator for MessageIter<R> {
type Item = io::Result<Message>;
fn next(&mut self) -> Option<Self::Item> {
let line = self.lines.next()?;
let message = line.and_then(|it| serde_json::from_str(&it).map_err(io::Error::from));
Some(message)
}
}

/// An iterator of Message.
type MessageIterator<R> =
serde_json::StreamDeserializer<'static, serde_json::de::IoRead<R>, Message>;

/// Creates an iterator of Message from a Read outputting a stream of JSON
/// messages. For usage information, look at the top-level documentation.
#[deprecated(note = "Use Message::parse_stream instead")]
pub fn parse_messages<R: Read>(input: R) -> MessageIterator<R> {
serde_json::Deserializer::from_reader(input).into_iter::<Message>()
}
11 changes: 9 additions & 2 deletions tests/test_samples.rs
Expand Up @@ -483,7 +483,14 @@ fn parse_messages_is_robust() {
Evil proc macro was here!
{"reason":"compiler-artifact","package_id":"chatty-macro 0.1.0 (path+file:///chatty-macro)","target":{"kind":["lib"],"crate_types":["lib"],"name":"chatty-macro","src_path":"/chatty-macro/src/lib.rs","edition":"2018","doctest":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/chatty-macro/target/debug/libchatty_macro.rlib","/chatty-macro/target/debug/deps/libchatty_macro-cb5956ed52a11fb6.rmeta"],"executable":null,"fresh":false}
"##;
for m in cargo_metadata::parse_messages(json_output.as_bytes()) {
eprintln!("m = {:?}", m);
let mut good = 0;
let mut bad = 0;
for m in cargo_metadata::Message::parse_stream(json_output.as_bytes()) {
match m {
Ok(_) => good += 1,
Err(_) => bad += 1,
}
}
assert_eq!(good, 2);
assert_eq!(bad, 1);
}

0 comments on commit 27bbd83

Please sign in to comment.