mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +00:00
Remove unsafe { … }
code from askama_escape
Using only safe code is actually same as fast as the previous "unsafe"
code according to the crate's benchmark.
The code was extracted from [markup]'s escape function in [escape.rs],
written by Utkarsh Kukreti <utkarshkukreti@gmail.com>, licensed as
`MIT OR Apache-2.0`.
[markup]: https://crates.io/crates/markup
[escape.rs]: 8ec4042848/markup/src/escape.rs (L1-L21)
This commit is contained in:
parent
ab39ced64e
commit
fc779e22c3
@ -107,40 +107,31 @@ where
|
|||||||
|
|
||||||
pub struct Html;
|
pub struct Html;
|
||||||
|
|
||||||
macro_rules! escaping_body {
|
|
||||||
($start:ident, $i:ident, $fmt:ident, $bytes:ident, $quote:expr) => {{
|
|
||||||
if $start < $i {
|
|
||||||
$fmt.write_str(unsafe { str::from_utf8_unchecked(&$bytes[$start..$i]) })?;
|
|
||||||
}
|
|
||||||
$fmt.write_str($quote)?;
|
|
||||||
$start = $i + 1;
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Escaper for Html {
|
impl Escaper for Html {
|
||||||
fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
|
fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
let bytes = string.as_bytes();
|
let mut last = 0;
|
||||||
let mut start = 0;
|
for (index, byte) in string.bytes().enumerate() {
|
||||||
for (i, b) in bytes.iter().enumerate() {
|
macro_rules! go {
|
||||||
if b.wrapping_sub(b'"') <= FLAG {
|
($expr:expr) => {{
|
||||||
match *b {
|
fmt.write_str(&string[last..index])?;
|
||||||
b'<' => escaping_body!(start, i, fmt, bytes, "<"),
|
fmt.write_str($expr)?;
|
||||||
b'>' => escaping_body!(start, i, fmt, bytes, ">"),
|
last = index + 1;
|
||||||
b'&' => escaping_body!(start, i, fmt, bytes, "&"),
|
}};
|
||||||
b'"' => escaping_body!(start, i, fmt, bytes, """),
|
}
|
||||||
b'\'' => escaping_body!(start, i, fmt, bytes, "'"),
|
|
||||||
_ => (),
|
match byte {
|
||||||
}
|
b'<' => go!("<"),
|
||||||
|
b'>' => go!(">"),
|
||||||
|
b'&' => go!("&"),
|
||||||
|
b'"' => go!("""),
|
||||||
|
b'\'' => go!("'"),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if start < bytes.len() {
|
fmt.write_str(&string[last..])
|
||||||
fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,8 +161,6 @@ pub trait Escaper {
|
|||||||
W: Write;
|
W: Write;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FLAG: u8 = b'>' - b'"';
|
|
||||||
|
|
||||||
/// Escape chevrons, ampersand and apostrophes for use in JSON
|
/// Escape chevrons, ampersand and apostrophes for use in JSON
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
@ -191,30 +180,25 @@ impl JsonEscapeBuffer {
|
|||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
impl std::io::Write for JsonEscapeBuffer {
|
impl std::io::Write for JsonEscapeBuffer {
|
||||||
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
|
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
|
||||||
macro_rules! push_esc_sequence {
|
let mut last = 0;
|
||||||
($start:ident, $i:ident, $self:ident, $bytes:ident, $quote:expr) => {{
|
for (index, byte) in bytes.iter().enumerate() {
|
||||||
if $start < $i {
|
macro_rules! go {
|
||||||
$self.0.extend_from_slice(&$bytes[$start..$i]);
|
($expr:expr) => {{
|
||||||
}
|
self.0.extend(&bytes[last..index]);
|
||||||
$self.0.extend_from_slice($quote);
|
self.0.extend($expr);
|
||||||
$start = $i + 1;
|
last = index + 1;
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.0.reserve(bytes.len());
|
match byte {
|
||||||
let mut start = 0;
|
b'&' => go!(br#"\u0026"#),
|
||||||
for (i, b) in bytes.iter().enumerate() {
|
b'\'' => go!(br#"\u0027"#),
|
||||||
match *b {
|
b'<' => go!(br#"\u003c"#),
|
||||||
b'&' => push_esc_sequence!(start, i, self, bytes, br#"\u0026"#),
|
b'>' => go!(br#"\u003e"#),
|
||||||
b'\'' => push_esc_sequence!(start, i, self, bytes, br#"\u0027"#),
|
_ => {}
|
||||||
b'<' => push_esc_sequence!(start, i, self, bytes, br#"\u003c"#),
|
|
||||||
b'>' => push_esc_sequence!(start, i, self, bytes, br#"\u003e"#),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if start < bytes.len() {
|
self.0.extend(&bytes[last..]);
|
||||||
self.0.extend_from_slice(&bytes[start..]);
|
|
||||||
}
|
|
||||||
Ok(bytes.len())
|
Ok(bytes.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user