From cd79876fe8f2eead51a1d9efa0b0f42467b9bef8 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 8 Feb 2024 23:56:26 -0500 Subject: [PATCH] optimize by avoiding second fmt.value() call --- impl/src/attr.rs | 16 ++++++------ impl/src/fmt.rs | 5 ++++ tests/test_display.rs | 61 +++++++++++++++++++++---------------------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/impl/src/attr.rs b/impl/src/attr.rs index 743c146..7bba4ad 100644 --- a/impl/src/attr.rs +++ b/impl/src/attr.rs @@ -18,6 +18,7 @@ pub struct Attrs<'a> { #[derive(Clone)] pub struct Display<'a> { pub original: &'a Attribute, + pub use_write_str: bool, pub fmt: LitStr, pub args: TokenStream, pub has_bonus_display: bool, @@ -103,10 +104,14 @@ fn parse_error_attribute<'a>(attrs: &mut Attrs<'a>, attr: &'a Attribute) -> Resu return Ok(()); } + let fmt = input.parse()?; + let args = parse_token_expr(input, false)?; let display = Display { original: attr, - fmt: input.parse()?, - args: parse_token_expr(input, false)?, + // This will be updated later if format_args are still required (i.e. has braces) + use_write_str: args.is_empty(), + fmt, + args, has_bonus_display: false, implied_bounds: Set::new(), }; @@ -200,12 +205,7 @@ impl ToTokens for Display<'_> { // Currently compiler is unable to generate as efficient code for // write!(f, "text") as it does for f.write_str("text"), // so handle it here when the literal string has no braces/no args. - let use_write_str = self.args.is_empty() && { - let value = fmt.value(); - !value.contains('{') && !value.contains('}') - }; - - tokens.extend(if use_write_str { + tokens.extend(if self.use_write_str { quote! { __formatter.write_str(#fmt) } diff --git a/impl/src/fmt.rs b/impl/src/fmt.rs index 807dfb9..a5b44ce 100644 --- a/impl/src/fmt.rs +++ b/impl/src/fmt.rs @@ -32,7 +32,12 @@ impl Display<'_> { } } + if self.use_write_str && fmt.contains('}') { + self.use_write_str = false; + } + while let Some(brace) = read.find('{') { + self.use_write_str = false; out += &read[..brace + 1]; read = &read[brace + 1..]; if read.starts_with('{') { diff --git a/tests/test_display.rs b/tests/test_display.rs index faa8968..95c1a86 100644 --- a/tests/test_display.rs +++ b/tests/test_display.rs @@ -306,14 +306,18 @@ fn test_keyword() { fn test_str_special_chars() { #[derive(Error, Debug)] pub enum Error { - #[error("text")] - Text, - #[error("braces {{}}")] - Braces, - #[error("braces2 \x7B\x7B\x7D\x7D")] - Braces2, - #[error("braces3 \u{7B}\u{7B}\u{7D}\u{7D}")] - Braces3, + #[error("brace left {{")] + BraceLeft, + #[error("brace left 2 \x7B\x7B")] + BraceLeft2, + #[error("brace left 3 \u{7B}\u{7B}")] + BraceLeft3, + #[error("brace right }}")] + BraceRight, + #[error("brace right 2 \x7D\x7D")] + BraceRight2, + #[error("brace right 3 \u{7D}\u{7D}")] + BraceRight3, #[error( "new_\ line" @@ -323,10 +327,12 @@ line" Escape24, } - assert("text", Error::Text); - assert("braces {}", Error::Braces); - assert("braces2 {}", Error::Braces2); - assert("braces3 {}", Error::Braces3); + assert("brace left {", Error::BraceLeft); + assert("brace left 2 {", Error::BraceLeft2); + assert("brace left 3 {", Error::BraceLeft3); + assert("brace right }", Error::BraceRight); + assert("brace right 2 }", Error::BraceRight2); + assert("brace right 3 }", Error::BraceRight3); assert("new_line", Error::NewLine); assert("escape24 x", Error::Escape24); } @@ -335,25 +341,18 @@ line" fn test_raw_str() { #[derive(Error, Debug)] pub enum Error { - #[error(r#"raw_text"#)] - Text, - #[error(r#"raw_braces {{}}"#)] - Braces, - #[error(r#"raw_braces2 \x7B\x7D"#)] - Braces2, - #[error( - r#"raw_new_\ -line"# - )] - NewLine, + #[error(r#"raw brace left {{"#)] + BraceLeft, + #[error(r#"raw brace left 2 \x7B"#)] + BraceLeft2, + #[error(r#"raw brace right }}"#)] + BraceRight, + #[error(r#"raw brace right 2 \x7D"#)] + BraceRight2, } - assert(r#"raw_text"#, Error::Text); - assert(r#"raw_braces {}"#, Error::Braces); - assert(r#"raw_braces2 \x7B\x7D"#, Error::Braces2); - assert( - r#"raw_new_\ -line"#, - Error::NewLine, - ); + assert(r#"raw brace left {"#, Error::BraceLeft); + assert(r#"raw brace left 2 \x7B"#, Error::BraceLeft2); + assert(r#"raw brace right }"#, Error::BraceRight); + assert(r#"raw brace right 2 \x7D"#, Error::BraceRight2); }