use std::fmt;
pub use hers_macro::hers;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HtmlString(String);
impl HtmlString {
pub fn new(s: String) -> Self {
Self(s)
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
}
impl fmt::Display for HtmlString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<String> for HtmlString {
fn from(s: String) -> Self {
Self::new(s)
}
}
impl From<&str> for HtmlString {
fn from(s: &str) -> Self {
Self::new(s.to_string())
}
}
pub trait ToHtml {
fn to_html(&self) -> HtmlString;
}
impl ToHtml for String {
fn to_html(&self) -> HtmlString {
HtmlString::new(escape_html(self))
}
}
impl ToHtml for &str {
fn to_html(&self) -> HtmlString {
HtmlString::new(escape_html(self))
}
}
impl ToHtml for i32 {
fn to_html(&self) -> HtmlString {
HtmlString::new(self.to_string())
}
}
impl ToHtml for f64 {
fn to_html(&self) -> HtmlString {
HtmlString::new(self.to_string())
}
}
impl ToHtml for bool {
fn to_html(&self) -> HtmlString {
HtmlString::new(self.to_string())
}
}
impl ToHtml for usize {
fn to_html(&self) -> HtmlString {
HtmlString::new(self.to_string())
}
}
pub fn escape_html(input: &str) -> String {
input
.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
.replace('\'', "'")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_html_string_creation() {
let html = HtmlString::new("Hello".to_string());
assert_eq!(html.as_str(), "Hello");
assert_eq!(html.to_string(), "Hello");
}
#[test]
fn test_html_string_from_str() {
let html: HtmlString = "Hello".into();
assert_eq!(html.as_str(), "Hello");
}
#[test]
fn test_escape_html() {
assert_eq!(escape_html("Hello"), "Hello");
assert_eq!(escape_html("<script>"), "<script>");
assert_eq!(escape_html("&"), "&");
assert_eq!(escape_html("\""), """);
assert_eq!(escape_html("'"), "'");
assert_eq!(
escape_html("<script>alert('xss')</script>"),
"<script>alert('xss')</script>"
);
}
#[test]
fn test_to_html_string() {
let s = "Hello <world>".to_string();
let html = s.to_html();
assert_eq!(html.as_str(), "Hello <world>");
}
#[test]
fn test_to_html_str() {
let html = "Hello <world>".to_html();
assert_eq!(html.as_str(), "Hello <world>");
}
#[test]
fn test_to_html_numbers() {
assert_eq!(42.to_html().as_str(), "42");
assert_eq!(7.99.to_html().as_str(), "7.99");
assert_eq!(true.to_html().as_str(), "true");
assert_eq!(false.to_html().as_str(), "false");
}
}