Skip to content

Commit f8b0481

Browse files
committed
Make html escaping available to derive
1 parent d3eab21 commit f8b0481

File tree

5 files changed

+80
-62
lines changed

5 files changed

+80
-62
lines changed

rinja/src/filters/escape.rs

+6-62
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::convert::Infallible;
22
use std::fmt::{self, Display, Formatter, Write};
3-
use std::num::NonZeroU8;
43
use std::{borrow, str};
54

65
/// Marks a string (or other `Display` type) as safe
@@ -83,69 +82,14 @@ pub fn e(text: impl fmt::Display, escaper: impl Escaper) -> Result<Safe<impl Dis
8382
pub struct Html;
8483

8584
impl Escaper for Html {
86-
fn write_escaped_str<W: Write>(&self, mut fmt: W, string: &str) -> fmt::Result {
87-
let mut escaped_buf = *b"&#__;";
88-
let mut last = 0;
89-
90-
for (index, byte) in string.bytes().enumerate() {
91-
const MIN_CHAR: u8 = b'"';
92-
const MAX_CHAR: u8 = b'>';
93-
94-
struct Table {
95-
_align: [usize; 0],
96-
lookup: [Option<[NonZeroU8; 2]>; (MAX_CHAR - MIN_CHAR + 1) as usize],
97-
}
98-
99-
const TABLE: Table = {
100-
const fn n(c: u8) -> Option<[NonZeroU8; 2]> {
101-
let n0 = match NonZeroU8::new(c / 10 + b'0') {
102-
Some(n) => n,
103-
None => panic!(),
104-
};
105-
let n1 = match NonZeroU8::new(c % 10 + b'0') {
106-
Some(n) => n,
107-
None => panic!(),
108-
};
109-
Some([n0, n1])
110-
}
111-
112-
let mut table = Table {
113-
_align: [],
114-
lookup: [None; (MAX_CHAR - MIN_CHAR + 1) as usize],
115-
};
116-
117-
table.lookup[(b'"' - MIN_CHAR) as usize] = n(b'"');
118-
table.lookup[(b'&' - MIN_CHAR) as usize] = n(b'&');
119-
table.lookup[(b'\'' - MIN_CHAR) as usize] = n(b'\'');
120-
table.lookup[(b'<' - MIN_CHAR) as usize] = n(b'<');
121-
table.lookup[(b'>' - MIN_CHAR) as usize] = n(b'>');
122-
table
123-
};
124-
125-
let escaped = match byte {
126-
MIN_CHAR..=MAX_CHAR => TABLE.lookup[(byte - MIN_CHAR) as usize],
127-
_ => None,
128-
};
129-
if let Some(escaped) = escaped {
130-
escaped_buf[2] = escaped[0].get();
131-
escaped_buf[3] = escaped[1].get();
132-
fmt.write_str(&string[last..index])?;
133-
fmt.write_str(unsafe { std::str::from_utf8_unchecked(escaped_buf.as_slice()) })?;
134-
last = index + 1;
135-
}
136-
}
137-
fmt.write_str(&string[last..])
85+
#[inline]
86+
fn write_escaped_str<W: Write>(&self, fmt: W, string: &str) -> fmt::Result {
87+
crate::html::write_escaped_str(fmt, string)
13888
}
13989

140-
fn write_escaped_char<W: Write>(&self, mut fmt: W, c: char) -> fmt::Result {
141-
fmt.write_str(match (c.is_ascii(), c as u8) {
142-
(true, b'"') => "&#34;",
143-
(true, b'&') => "&#38;",
144-
(true, b'\'') => "&#39;",
145-
(true, b'<') => "&#60;",
146-
(true, b'>') => "&#62;",
147-
_ => return fmt.write_char(c),
148-
})
90+
#[inline]
91+
fn write_escaped_char<W: Write>(&self, fmt: W, c: char) -> fmt::Result {
92+
crate::html::write_escaped_char(fmt, c)
14993
}
15094
}
15195

rinja/src/html.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use std::fmt;
2+
use std::num::NonZeroU8;
3+
4+
#[allow(unused)]
5+
pub(crate) fn write_escaped_str(mut fmt: impl fmt::Write, string: &str) -> fmt::Result {
6+
let mut escaped_buf = *b"&#__;";
7+
let mut last = 0;
8+
9+
for (index, byte) in string.bytes().enumerate() {
10+
let escaped = match byte {
11+
MIN_CHAR..=MAX_CHAR => TABLE.lookup[(byte - MIN_CHAR) as usize],
12+
_ => None,
13+
};
14+
if let Some(escaped) = escaped {
15+
escaped_buf[2] = escaped[0].get();
16+
escaped_buf[3] = escaped[1].get();
17+
fmt.write_str(&string[last..index])?;
18+
fmt.write_str(unsafe { std::str::from_utf8_unchecked(escaped_buf.as_slice()) })?;
19+
last = index + 1;
20+
}
21+
}
22+
fmt.write_str(&string[last..])
23+
}
24+
25+
#[allow(unused)]
26+
pub(crate) fn write_escaped_char(mut fmt: impl fmt::Write, c: char) -> fmt::Result {
27+
fmt.write_str(match (c.is_ascii(), c as u8) {
28+
(true, b'"') => "&#34;",
29+
(true, b'&') => "&#38;",
30+
(true, b'\'') => "&#39;",
31+
(true, b'<') => "&#60;",
32+
(true, b'>') => "&#62;",
33+
_ => return fmt.write_char(c),
34+
})
35+
}
36+
37+
const MIN_CHAR: u8 = b'"';
38+
const MAX_CHAR: u8 = b'>';
39+
40+
struct Table {
41+
_align: [usize; 0],
42+
lookup: [Option<[NonZeroU8; 2]>; (MAX_CHAR - MIN_CHAR + 1) as usize],
43+
}
44+
45+
const TABLE: Table = {
46+
const fn n(c: u8) -> Option<[NonZeroU8; 2]> {
47+
assert!(MIN_CHAR <= c && c <= MAX_CHAR);
48+
49+
let n0 = match NonZeroU8::new(c / 10 + b'0') {
50+
Some(n) => n,
51+
None => panic!(),
52+
};
53+
let n1 = match NonZeroU8::new(c % 10 + b'0') {
54+
Some(n) => n,
55+
None => panic!(),
56+
};
57+
Some([n0, n1])
58+
}
59+
60+
let mut table = Table {
61+
_align: [],
62+
lookup: [None; (MAX_CHAR - MIN_CHAR + 1) as usize],
63+
};
64+
65+
table.lookup[(b'"' - MIN_CHAR) as usize] = n(b'"');
66+
table.lookup[(b'&' - MIN_CHAR) as usize] = n(b'&');
67+
table.lookup[(b'\'' - MIN_CHAR) as usize] = n(b'\'');
68+
table.lookup[(b'<' - MIN_CHAR) as usize] = n(b'<');
69+
table.lookup[(b'>' - MIN_CHAR) as usize] = n(b'>');
70+
table
71+
};

rinja/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
mod error;
5858
pub mod filters;
5959
pub mod helpers;
60+
mod html;
6061

6162
use std::{fmt, io};
6263

rinja_derive/src/html.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../rinja/src/html.rs

rinja_derive/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
mod config;
55
mod generator;
66
mod heritage;
7+
mod html;
78
mod input;
89
#[cfg(test)]
910
mod tests;

0 commit comments

Comments
 (0)