use core::fmt;
use crate::to_css::ToCss;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CssString(pub String);
impl CssString {
pub fn new(s: impl Into<String>) -> Self {
Self(s.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl From<&str> for CssString {
fn from(s: &str) -> Self {
Self(s.to_string())
}
}
impl From<String> for CssString {
fn from(s: String) -> Self {
Self(s)
}
}
impl ToCss for CssString {
fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
dest.write_char('"')?;
for ch in self.0.chars() {
match ch {
'"' => dest.write_str("\\\"")?,
'\\' => dest.write_str("\\\\")?,
'\n' => dest.write_str("\\A ")?,
'\r' => dest.write_str("\\D ")?,
c => dest.write_char(c)?,
}
}
dest.write_char('"')
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plain_string_is_quoted() {
assert_eq!(CssString::new("hello").to_css_string(), "\"hello\"");
}
#[test]
fn embedded_quote_is_escaped() {
assert_eq!(CssString::new("a\"b").to_css_string(), "\"a\\\"b\"");
}
#[test]
fn backslash_is_escaped() {
assert_eq!(CssString::new("a\\b").to_css_string(), "\"a\\\\b\"");
}
#[test]
fn newline_uses_css_escape() {
assert_eq!(CssString::new("a\nb").to_css_string(), "\"a\\A b\"");
}
#[test]
fn from_str_and_string() {
let from_str: CssString = "x".into();
let from_string: CssString = String::from("y").into();
assert_eq!(from_str.to_css_string(), "\"x\"");
assert_eq!(from_string.to_css_string(), "\"y\"");
assert_eq!(from_str.as_str(), "x");
}
}