]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | //! HTML escaping. |
1a4d82fc | 2 | //! |
9fa01778 | 3 | //! This module contains one unit struct, which can be used to HTML-escape a |
1a4d82fc JJ |
4 | //! string of text (for use in a format string). |
5 | ||
6 | use std::fmt; | |
7 | ||
8 | /// Wrapper struct which will emit the HTML-escaped version of the contained | |
9 | /// string when passed to a format string. | |
923072b8 | 10 | pub(crate) struct Escape<'a>(pub &'a str); |
1a4d82fc | 11 | |
85aaf69f | 12 | impl<'a> fmt::Display for Escape<'a> { |
9fa01778 | 13 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
1a4d82fc JJ |
14 | // Because the internet is always right, turns out there's not that many |
15 | // characters to escape: http://stackoverflow.com/questions/7381974 | |
16 | let Escape(s) = *self; | |
85aaf69f | 17 | let pile_o_bits = s; |
1a4d82fc | 18 | let mut last = 0; |
5869c6ff XL |
19 | for (i, ch) in s.char_indices() { |
20 | let s = match ch { | |
21 | '>' => ">", | |
22 | '<' => "<", | |
23 | '&' => "&", | |
24 | '\'' => "'", | |
25 | '"' => """, | |
26 | _ => continue, | |
27 | }; | |
28 | fmt.write_str(&pile_o_bits[last..i])?; | |
29 | fmt.write_str(s)?; | |
30 | // NOTE: we only expect single byte characters here - which is fine as long as we | |
31 | // only match single byte characters | |
32 | last = i + 1; | |
1a4d82fc JJ |
33 | } |
34 | ||
35 | if last < s.len() { | |
54a0048b | 36 | fmt.write_str(&pile_o_bits[last..])?; |
1a4d82fc JJ |
37 | } |
38 | Ok(()) | |
39 | } | |
40 | } |