Skip to content

Commit 4ef4c8b

Browse files
committed
derive: escape strings at compile-time when possible
1 parent f8b0481 commit 4ef4c8b

File tree

2 files changed

+46
-64
lines changed

2 files changed

+46
-64
lines changed

rinja_derive/src/generator.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use quote::quote;
1414

1515
use crate::config::WhitespaceHandling;
1616
use crate::heritage::{Context, Heritage};
17+
use crate::html::write_escaped_str;
1718
use crate::input::{Source, TemplateInput};
1819
use crate::{CompileError, MsgValidEscapers, CRATE};
1920

@@ -1162,8 +1163,42 @@ impl<'a> Generator<'a> {
11621163
}
11631164

11641165
fn write_expr(&mut self, ws: Ws, s: &'a WithSpan<'a, Expr<'a>>) {
1166+
let mut writable = Writable::Expr(s);
1167+
(|| -> Option<()> {
1168+
let input = match &**s {
1169+
Expr::StrLit(input) => {
1170+
let input = format!(r#""{input}""#);
1171+
let input = input.parse().ok()?;
1172+
let input = syn::parse2::<syn::LitStr>(input).ok()?;
1173+
input.value()
1174+
}
1175+
Expr::CharLit(input) => {
1176+
let input = format!(r#"'{input}'"#);
1177+
let input = input.parse().ok()?;
1178+
let input = syn::parse2::<syn::LitChar>(input).ok()?;
1179+
input.value().to_string()
1180+
}
1181+
_ => return None,
1182+
};
1183+
1184+
let is_html = match self.input.escaper.strip_prefix(CRATE)? {
1185+
"::filters::Html" => true,
1186+
"::filters::Text" => false,
1187+
_ => return None,
1188+
};
1189+
if is_html {
1190+
let mut escaped = String::with_capacity(input.len() + 20);
1191+
if write_escaped_str(&mut escaped, &input).is_ok() {
1192+
writable = Writable::Lit(Cow::Owned(escaped));
1193+
}
1194+
} else {
1195+
writable = Writable::Lit(Cow::Owned(input));
1196+
}
1197+
None
1198+
})();
1199+
11651200
self.handle_ws(ws);
1166-
self.buf_writable.push(Writable::Expr(s));
1201+
self.buf_writable.push(writable);
11671202
}
11681203

11691204
// Write expression buffer and empty

rinja_derive/src/tests.rs

+10-63
Original file line numberDiff line numberDiff line change
@@ -440,77 +440,24 @@ fn check_escaping_at_compile_time() {
440440
r#"writer.write_str("The card is")?;
441441
match &self.suit {
442442
Suit::Clubs | Suit::Spades => {
443-
match (
444-
&((&&::rinja::filters::AutoEscaper::new(&(" black"), ::rinja::filters::Text)).rinja_auto_escape()?),
445-
) {
446-
(expr0,) => {
447-
(&&::rinja::filters::Writable(expr0)).rinja_write(writer)?;
448-
}
449-
}
450-
}
451-
Suit::Diamonds | Suit::Hearts => {
452-
match (
453-
&((&&::rinja::filters::AutoEscaper::new(&(" red"), ::rinja::filters::Text)).rinja_auto_escape()?),
454-
) {
455-
(expr0,) => {
456-
(&&::rinja::filters::Writable(expr0)).rinja_write(writer)?;
457-
}
458-
}
443+
writer.write_str(" black")?;
444+
}
445+
Suit::Diamonds | Suit::Hearts => {
446+
writer.write_str(" red")?;
459447
}
460448
}"#,
461449
&[("suit", "Suit")],
462-
14,
450+
16,
463451
);
464452

465453
compare(
466454
r#"{{ '\x41' }}{{ '\n' }}{{ '\r' }}{{ '\t' }}{{ '\\' }}{{ '\u{2665}' }}{{ '\'' }}{{ '\"' }}{{ '"' }}
467455
{{ "\x41\n\r\t\\\u{2665}\'\"'" }}"#,
468-
r#"
469-
match (
470-
&((&&::rinja::filters::AutoEscaper::new(&('\x41'), ::rinja::filters::Text))
471-
.rinja_auto_escape()?),
472-
&((&&::rinja::filters::AutoEscaper::new(&('\n'), ::rinja::filters::Text))
473-
.rinja_auto_escape()?),
474-
&((&&::rinja::filters::AutoEscaper::new(&('\r'), ::rinja::filters::Text))
475-
.rinja_auto_escape()?),
476-
&((&&::rinja::filters::AutoEscaper::new(&('\t'), ::rinja::filters::Text))
477-
.rinja_auto_escape()?),
478-
&((&&::rinja::filters::AutoEscaper::new(&('\\'), ::rinja::filters::Text))
479-
.rinja_auto_escape()?),
480-
&((&&::rinja::filters::AutoEscaper::new(
481-
&('\u{2665}'),
482-
::rinja::filters::Text,
483-
))
484-
.rinja_auto_escape()?),
485-
&((&&::rinja::filters::AutoEscaper::new(&('\''), ::rinja::filters::Text))
486-
.rinja_auto_escape()?),
487-
&((&&::rinja::filters::AutoEscaper::new(&('\"'), ::rinja::filters::Text))
488-
.rinja_auto_escape()?),
489-
&((&&::rinja::filters::AutoEscaper::new(&('"'), ::rinja::filters::Text))
490-
.rinja_auto_escape()?),
491-
&((&&::rinja::filters::AutoEscaper::new(
492-
&("\x41\n\r\t\\\u{2665}\'\"'"),
493-
::rinja::filters::Text,
494-
))
495-
.rinja_auto_escape()?),
496-
) {
497-
(expr0, expr1, expr2, expr3, expr4, expr5, expr6, expr7, expr8, expr10) => {
498-
(&&::rinja::filters::Writable(expr0)).rinja_write(writer)?;
499-
(&&::rinja::filters::Writable(expr1)).rinja_write(writer)?;
500-
(&&::rinja::filters::Writable(expr2)).rinja_write(writer)?;
501-
(&&::rinja::filters::Writable(expr3)).rinja_write(writer)?;
502-
(&&::rinja::filters::Writable(expr4)).rinja_write(writer)?;
503-
(&&::rinja::filters::Writable(expr5)).rinja_write(writer)?;
504-
(&&::rinja::filters::Writable(expr6)).rinja_write(writer)?;
505-
(&&::rinja::filters::Writable(expr7)).rinja_write(writer)?;
506-
(&&::rinja::filters::Writable(expr8)).rinja_write(writer)?;
507-
writer.write_str("
508-
")?;
509-
(&&::rinja::filters::Writable(expr10)).rinja_write(writer)?;
510-
}
511-
}
512-
"#,
456+
r#"writer.write_str("A
457+
\r \\♥'\"\"
458+
A
459+
\r \\♥'\"'")?;"#,
513460
&[],
514-
31,
461+
23,
515462
);
516463
}

0 commit comments

Comments
 (0)