Skip to content

Commit 9a6a945

Browse files
committed
refactor: zero-copy deserialization when possible
Found this during PR review. We could leverage `#[serde(borrow)]` for zero-copy deserialization for messages from the compiler. We can't use `&str` fields because they may contain escape sequences in the future, which fails the deserialization. See serde-rs/json#742
1 parent b396f2c commit 9a6a945

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

src/cargo/core/compiler/job_queue/job_state.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl<'a, 'gctx> JobState<'a, 'gctx> {
103103
}
104104

105105
/// See [`Message::Diagnostic`] and [`Message::WarningCount`].
106-
pub fn emit_diag(&self, level: String, diag: String, fixable: bool) -> CargoResult<()> {
106+
pub fn emit_diag(&self, level: &str, diag: String, fixable: bool) -> CargoResult<()> {
107107
if let Some(dedupe) = self.output {
108108
let emitted = dedupe.emit_diag(&diag)?;
109109
if level == "warning" {
@@ -116,7 +116,7 @@ impl<'a, 'gctx> JobState<'a, 'gctx> {
116116
} else {
117117
self.messages.push_bounded(Message::Diagnostic {
118118
id: self.id,
119-
level,
119+
level: level.to_string(),
120120
diag,
121121
fixable,
122122
});

src/cargo/core/compiler/mod.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ mod unit;
5454
pub mod unit_dependencies;
5555
pub mod unit_graph;
5656

57+
use std::borrow::Cow;
5758
use std::collections::{HashMap, HashSet};
5859
use std::env;
5960
use std::ffi::{OsStr, OsString};
@@ -1756,10 +1757,15 @@ fn on_stderr_line_inner(
17561757
..
17571758
} => {
17581759
#[derive(serde::Deserialize)]
1759-
struct CompilerMessage {
1760+
struct CompilerMessage<'a> {
1761+
// `rendered` contains escape sequences, which can't be
1762+
// zero-copy deserialized by serde_json.
1763+
// See https://github.com/serde-rs/json/issues/742
17601764
rendered: String,
1761-
message: String,
1762-
level: String,
1765+
#[serde(borrow)]
1766+
message: Cow<'a, str>,
1767+
#[serde(borrow)]
1768+
level: Cow<'a, str>,
17631769
children: Vec<PartialDiagnostic>,
17641770
}
17651771

@@ -1782,7 +1788,8 @@ fn on_stderr_line_inner(
17821788
suggestion_applicability: Option<Applicability>,
17831789
}
17841790

1785-
if let Ok(mut msg) = serde_json::from_str::<CompilerMessage>(compiler_message.get()) {
1791+
if let Ok(mut msg) = serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get())
1792+
{
17861793
if msg.message.starts_with("aborting due to")
17871794
|| msg.message.ends_with("warning emitted")
17881795
|| msg.message.ends_with("warnings emitted")
@@ -1808,7 +1815,7 @@ fn on_stderr_line_inner(
18081815
})
18091816
.any(|b| b);
18101817
count_diagnostic(&msg.level, options);
1811-
state.emit_diag(msg.level, rendered, machine_applicable)?;
1818+
state.emit_diag(&msg.level, rendered, machine_applicable)?;
18121819
}
18131820
return Ok(true);
18141821
}
@@ -1819,12 +1826,14 @@ fn on_stderr_line_inner(
18191826
// cached replay to enable/disable colors without re-invoking rustc.
18201827
MessageFormat::Json { ansi: false, .. } => {
18211828
#[derive(serde::Deserialize, serde::Serialize)]
1822-
struct CompilerMessage {
1829+
struct CompilerMessage<'a> {
18231830
rendered: String,
1824-
#[serde(flatten)]
1825-
other: std::collections::BTreeMap<String, serde_json::Value>,
1831+
#[serde(flatten, borrow)]
1832+
other: std::collections::BTreeMap<Cow<'a, str>, serde_json::Value>,
18261833
}
1827-
if let Ok(mut error) = serde_json::from_str::<CompilerMessage>(compiler_message.get()) {
1834+
if let Ok(mut error) =
1835+
serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get())
1836+
{
18281837
error.rendered = anstream::adapter::strip_str(&error.rendered).to_string();
18291838
let new_line = serde_json::to_string(&error)?;
18301839
let new_msg: Box<serde_json::value::RawValue> = serde_json::from_str(&new_line)?;
@@ -1866,12 +1875,14 @@ fn on_stderr_line_inner(
18661875
}
18671876

18681877
#[derive(serde::Deserialize)]
1869-
struct CompilerMessage {
1870-
message: String,
1871-
level: String,
1878+
struct CompilerMessage<'a> {
1879+
#[serde(borrow)]
1880+
message: Cow<'a, str>,
1881+
#[serde(borrow)]
1882+
level: Cow<'a, str>,
18721883
}
18731884

1874-
if let Ok(msg) = serde_json::from_str::<CompilerMessage>(compiler_message.get()) {
1885+
if let Ok(msg) = serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get()) {
18751886
if msg.message.starts_with("aborting due to")
18761887
|| msg.message.ends_with("warning emitted")
18771888
|| msg.message.ends_with("warnings emitted")

0 commit comments

Comments
 (0)