diff options
| author | 2022-04-13 11:50:10 +0200 | |
|---|---|---|
| committer | 2022-04-13 13:18:27 +0200 | |
| commit | fc779e22c3bfa0e94df208a88a361b99e28a9129 (patch) | |
| tree | 3a09dfd2352be5d217317f03561170e3baaf4f0c /askama_escape | |
| 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 '')
| -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())      }  | 
