whisker_css/data_type/
string.rs1use core::fmt;
12
13use crate::to_css::ToCss;
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash)]
17pub struct CssString(pub String);
18
19impl CssString {
20 pub fn new(s: impl Into<String>) -> Self {
22 Self(s.into())
23 }
24
25 pub fn as_str(&self) -> &str {
27 &self.0
28 }
29}
30
31impl From<&str> for CssString {
32 fn from(s: &str) -> Self {
33 Self(s.to_string())
34 }
35}
36
37impl From<String> for CssString {
38 fn from(s: String) -> Self {
39 Self(s)
40 }
41}
42
43impl ToCss for CssString {
44 fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
45 dest.write_char('"')?;
46 for ch in self.0.chars() {
47 match ch {
48 '"' => dest.write_str("\\\"")?,
49 '\\' => dest.write_str("\\\\")?,
50 '\n' => dest.write_str("\\A ")?,
51 '\r' => dest.write_str("\\D ")?,
52 c => dest.write_char(c)?,
53 }
54 }
55 dest.write_char('"')
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn plain_string_is_quoted() {
65 assert_eq!(CssString::new("hello").to_css_string(), "\"hello\"");
66 }
67
68 #[test]
69 fn embedded_quote_is_escaped() {
70 assert_eq!(CssString::new("a\"b").to_css_string(), "\"a\\\"b\"");
71 }
72
73 #[test]
74 fn backslash_is_escaped() {
75 assert_eq!(CssString::new("a\\b").to_css_string(), "\"a\\\\b\"");
76 }
77
78 #[test]
79 fn newline_uses_css_escape() {
80 assert_eq!(CssString::new("a\nb").to_css_string(), "\"a\\A b\"");
81 }
82
83 #[test]
84 fn from_str_and_string() {
85 let from_str: CssString = "x".into();
86 let from_string: CssString = String::from("y").into();
87 assert_eq!(from_str.to_css_string(), "\"x\"");
88 assert_eq!(from_string.to_css_string(), "\"y\"");
89 assert_eq!(from_str.as_str(), "x");
90 }
91}