Skip to content

Commit d7e738e

Browse files
committed
Optimize simple literals for Display::fmt
Compiler is unable to generate as efficient code for `write!(f, "text")` as it does for `f.write_str("text")`. This PR checks if the `#[error("text")]` uses a simple string literal without the `{` and `}` characters, and without arguments, and uses `write_str` if so.
1 parent 0717de3 commit d7e738e

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

impl/src/attr.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,23 @@ impl ToTokens for Display<'_> {
196196
fn to_tokens(&self, tokens: &mut TokenStream) {
197197
let fmt = &self.fmt;
198198
let args = &self.args;
199-
tokens.extend(quote! {
200-
::core::write!(__formatter, #fmt #args)
199+
200+
// Currently compiler is unable to generate as efficient code for
201+
// write!(f, "text") as it does for f.write_str("text"),
202+
// so handle it here when the literal string has no braces/no args.
203+
let use_write_str = self.args.is_empty() && {
204+
let value = fmt.value();
205+
!value.contains('{') && !value.contains('}')
206+
};
207+
208+
tokens.extend(if use_write_str {
209+
quote! {
210+
__formatter.write_str(#fmt)
211+
}
212+
} else {
213+
quote! {
214+
::core::write!(__formatter, #fmt #args)
215+
}
201216
});
202217
}
203218
}

tests/test_display.rs

+56
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,59 @@ fn test_keyword() {
301301

302302
assert("error: 1", Error);
303303
}
304+
305+
#[test]
306+
fn test_str_special_chars() {
307+
#[derive(Error, Debug)]
308+
pub enum Error {
309+
#[error("text")]
310+
Text,
311+
#[error("braces {{}}")]
312+
Braces,
313+
#[error("braces2 \x7B\x7B\x7D\x7D")]
314+
Braces2,
315+
#[error("braces3 \u{7B}\u{7B}\u{7D}\u{7D}")]
316+
Braces3,
317+
#[error(
318+
"new_\
319+
line"
320+
)]
321+
NewLine,
322+
#[error("escape24 \u{78}")]
323+
Escape24,
324+
}
325+
326+
assert("text", Error::Text);
327+
assert("braces {}", Error::Braces);
328+
assert("braces2 {}", Error::Braces2);
329+
assert("braces3 {}", Error::Braces3);
330+
assert("new_line", Error::NewLine);
331+
assert("escape24 x", Error::Escape24);
332+
}
333+
334+
#[test]
335+
fn test_raw_str() {
336+
#[derive(Error, Debug)]
337+
pub enum Error {
338+
#[error(r#"raw_text"#)]
339+
Text,
340+
#[error(r#"raw_braces {{}}"#)]
341+
Braces,
342+
#[error(r#"raw_braces2 \x7B\x7D"#)]
343+
Braces2,
344+
#[error(
345+
r#"raw_new_\
346+
line"#
347+
)]
348+
NewLine,
349+
}
350+
351+
assert(r#"raw_text"#, Error::Text);
352+
assert(r#"raw_braces {}"#, Error::Braces);
353+
assert(r#"raw_braces2 \x7B\x7D"#, Error::Braces2);
354+
assert(
355+
r#"raw_new_\
356+
line"#,
357+
Error::NewLine,
358+
);
359+
}

0 commit comments

Comments
 (0)