1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*!
Provides `StringEscaper` and `HtmlEscaper` to escape strings for use in string literals and HTML elements respectively.
*/

use std::fmt::Write;



/// Escapes a string for the inside of a string literal.
///
/// # Examples
/// ```
/// use std::fmt::Write;
/// use write_html::escapes::StringEscaper;
/// 
/// let mut s = String::new();
/// let mut escaper = StringEscaper::new(&mut s);
/// escaper.write_str("Hello, \"world\"").unwrap();
/// assert_eq!(s, "Hello, \\\"world\\\"");
/// ```
pub struct StringEscaper<'a, W: Write> {
    w: &'a mut W,
}

impl<'a, W: Write> StringEscaper<'a, W> {
    /// Creates a new `StringEscaper` that will write to `w`.
    ///
    /// # Arguments
    /// * `w` - The `Write` to write to.
    pub fn new(w: &'a mut W) -> Self {
        Self { w }
    }
}

impl<'a, W: Write> Write for StringEscaper<'a, W> {
    fn write_str(&mut self, s: &str) -> std::fmt::Result {
        for c in s.chars() {
            match c {
                '"' => write!(self.w, "\\\"")?,
                '\'' => write!(self.w, "\\\'")?,
                '\\' => write!(self.w, "\\\\")?,
                '\r' => write!(self.w, "\\r")?,
                '\n' => write!(self.w, "\\n")?,
                '\t' => write!(self.w, "\\t")?,
                // TODO ...
                _ => write!(self.w, "{}", c)?,
            };
        }

        Ok(())
    }
}

/// Escapes a string for the inside of an HTML element.
///
/// # Examples
/// ```
/// use std::fmt::Write;
/// use write_html::escapes::HtmlEscaper;
/// 
/// let mut s = String::new();
/// let mut escaper = HtmlEscaper::new(&mut s);
/// escaper.write_str("<h1>H1</h1>").unwrap();
/// assert_eq!(s, "&lt;h1&gt;H1&lt;/h1&gt;");
/// ```
pub struct HtmlEscaper<'a, W: Write> {
    w: &'a mut W,
}

impl<'a, W: Write> HtmlEscaper<'a, W> {
    /// Creates a new `HtmlEscaper` that will write to `w`.
    ///
    /// # Arguments
    /// * `w` - The `Write` to write to.
    pub fn new(w: &'a mut W) -> Self {
        Self { w }
    }
}

impl<'a, W: Write> Write for HtmlEscaper<'a, W> {
    fn write_str(&mut self, s: &str) -> std::fmt::Result {
        for c in s.chars() {
            match c {
                '<' => write!(self.w, "&lt;")?,
                '>' => write!(self.w, "&gt;")?,
                '&' => write!(self.w, "&amp;")?,
                '\n' => write!(self.w, "<br>")?,
                // TODO ...
                _ => write!(self.w, "{}", c)?,
            };
        }

        Ok(())
    }
}