diff options
author | René Kijewski <kijewski@library.vetmed.fu-berlin.de> | 2022-04-13 11:50:10 +0200 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2022-04-13 13:18:27 +0200 |
commit | fc779e22c3bfa0e94df208a88a361b99e28a9129 (patch) | |
tree | 3a09dfd2352be5d217317f03561170e3baaf4f0c /askama_escape/src | |
parent | ab39ced64e4a56b741ee32487d3340e008c7e4fb (diff) | |
download | askama-fc779e22c3bfa0e94df208a88a361b99e28a9129.tar.gz askama-fc779e22c3bfa0e94df208a88a361b99e28a9129.tar.bz2 askama-fc779e22c3bfa0e94df208a88a361b99e28a9129.zip |
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]: https://github.com/utkarshkukreti/markup.rs/blob/8ec40428483790b2c296e907e7be4147b157fe8f/markup/src/escape.rs#L1-L21
Diffstat (limited to 'askama_escape/src')
-rw-r--r-- | askama_escape/src/lib.rs | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/askama_escape/src/lib.rs b/askama_escape/src/lib.rs index 1788843..8e57906 100644 --- a/askama_escape/src/lib.rs +++ b/askama_escape/src/lib.rs @@ -107,40 +107,31 @@ where 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 { fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result where W: Write, { - let bytes = string.as_bytes(); - let mut start = 0; - for (i, b) in bytes.iter().enumerate() { - if b.wrapping_sub(b'"') <= FLAG { - match *b { - b'<' => escaping_body!(start, i, fmt, bytes, "<"), - b'>' => escaping_body!(start, i, fmt, bytes, ">"), - b'&' => escaping_body!(start, i, fmt, bytes, "&"), - b'"' => escaping_body!(start, i, fmt, bytes, """), - b'\'' => escaping_body!(start, i, fmt, bytes, "'"), - _ => (), - } + let mut last = 0; + for (index, byte) in string.bytes().enumerate() { + macro_rules! go { + ($expr:expr) => {{ + fmt.write_str(&string[last..index])?; + fmt.write_str($expr)?; + last = index + 1; + }}; + } + + match byte { + b'<' => go!("<"), + b'>' => go!(">"), + b'&' => go!("&"), + b'"' => go!("""), + b'\'' => go!("'"), + _ => {} } } - if start < bytes.len() { - fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) }) - } else { - Ok(()) - } + fmt.write_str(&string[last..]) } } @@ -170,8 +161,6 @@ pub trait Escaper { W: Write; } -const FLAG: u8 = b'>' - b'"'; - /// Escape chevrons, ampersand and apostrophes for use in JSON #[cfg(feature = "json")] #[derive(Debug, Clone, Default)] @@ -191,30 +180,25 @@ impl JsonEscapeBuffer { #[cfg(feature = "json")] impl std::io::Write for JsonEscapeBuffer { fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> { - macro_rules! push_esc_sequence { - ($start:ident, $i:ident, $self:ident, $bytes:ident, $quote:expr) => {{ - if $start < $i { - $self.0.extend_from_slice(&$bytes[$start..$i]); - } - $self.0.extend_from_slice($quote); - $start = $i + 1; - }}; - } + let mut last = 0; + for (index, byte) in bytes.iter().enumerate() { + macro_rules! go { + ($expr:expr) => {{ + self.0.extend(&bytes[last..index]); + self.0.extend($expr); + last = index + 1; + }}; + } - self.0.reserve(bytes.len()); - let mut start = 0; - for (i, b) in bytes.iter().enumerate() { - match *b { - b'&' => push_esc_sequence!(start, i, self, bytes, br#"\u0026"#), - 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"#), - _ => (), + match byte { + b'&' => go!(br#"\u0026"#), + b'\'' => go!(br#"\u0027"#), + b'<' => go!(br#"\u003c"#), + b'>' => go!(br#"\u003e"#), + _ => {} } } - if start < bytes.len() { - self.0.extend_from_slice(&bytes[start..]); - } + self.0.extend(&bytes[last..]); Ok(bytes.len()) } |