use crate::prelude::*;
#[derive(Clone,Serialize,Default,Deserialize,Hash,Eq,Ord,PartialEq,PartialOrd)]
#[serde(transparent)]
pub struct Html(String);
impl Debug for HtmlStr {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
const MAX: usize = 23;
if self.len() < MAX {
write!(f, "<{}>", &self.0)
} else {
let lim = (MAX-3 ..).into_iter()
.find(|&i| self.0.is_char_boundary(i)).unwrap();
write!(f, "<{}>...", &self.0[0..lim])
}
}
}
impl AsRef<HtmlStr> for Html {
fn as_ref(&self) -> &HtmlStr { HtmlStr::from_html_str(&self.0) }
}
impl AsRef<HtmlStr> for HtmlStr {
fn as_ref(&self) -> &HtmlStr { self }
}
impl AsRef<HtmlStr> for HtmlLit {
fn as_ref(&self) -> &HtmlStr { HtmlStr::from_html_str(self.0) }
}
impl Deref for Html {
type Target = HtmlStr;
fn deref(&self) -> &HtmlStr { HtmlStr::from_html_str(&self.0) }
}
impl Deref for HtmlLit {
type Target = HtmlStr;
fn deref(&self) -> &HtmlStr { HtmlStr::from_html_str(self.0) }
}
impl Debug for Html {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self.as_ref(), f)
}
}
#[derive(Hash,Eq,Ord,PartialEq,PartialOrd)]
#[repr(transparent)]
pub struct HtmlStr(str);
#[derive(Hash,Eq,Ord,PartialEq,PartialOrd)]
#[derive(Serialize,Deserialize)]
#[serde(transparent)]
pub struct HtmlLit(&'static str);
impl Default for &'static HtmlStr {
fn default() -> Self { HtmlStr::from_html_str("") }
}
impl From<HtmlLit> for &'static HtmlStr {
fn from(l: HtmlLit) -> &'static HtmlStr { HtmlStr::from_html_str(l.0) }
}
pub trait HtmlFormat<'e> {
type Encoded: Display;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded;
}
impl From<HtmlLit> for Html {
fn from(l: HtmlLit) -> Html { Html(l.0.into()) }
}
impl From<&HtmlStr> for Html {
fn from(l: &HtmlStr) -> Html { Html(l.0.into()) }
}
impl<'e, T> HtmlFormat<'e> for &'e T where T: HtmlFormat<'e> + ?Sized {
type Encoded = T::Encoded;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded {
<T as HtmlFormat>::html_format(self)
}
}
#[derive(Debug,Copy,Clone,Ord,PartialOrd,Eq,PartialEq,Hash)]
pub struct IsHtmlFormatted<T:Display>(pub T);
impl<'e, T:Display+'e> HtmlFormat<'e> for IsHtmlFormatted<T> {
type Encoded = &'e T;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded { &self.0 }
}
impl Html {
pub fn new() -> Self { default() }
pub fn from_txt(s: &str) -> Self {
Html(htmlescape::encode_minimal(s))
}
pub fn from_html_string(s: String) -> Self { Html(s) }
pub fn as_html_string_mut(&mut self) -> &mut String { &mut self.0 }
pub fn into_html_string(self) -> String { self.0 }
pub const fn lit(s: &'static str) -> HtmlLit { HtmlLit(s) }
}
impl HtmlStr {
pub fn from_html_str<'s>(s: &'s str) -> &'s Self {
let s = unsafe { mem::transmute::<&'s str, &'s HtmlStr>(s) };
s
}
pub fn len(&self) -> usize { self.0.len() }
pub fn as_html_str(&self) -> &str { &self.0 }
}
#[ext(pub, name=HtmlIteratorExt, supertraits=Iterator)]
impl<T:Iterator> T {
fn hjoin<'i,'j, I,J>(self, j: &'j J) -> Html
where
Self: Iterator<Item=&'i I>,
I: AsRef<HtmlStr> + 'i,
J: AsRef<HtmlStr>,
{
let j: &HtmlStr = j.as_ref();
Html::from_html_string(
izip!(
iter::once("").chain(iter::repeat(j.as_html_str())),
self.map(|h| h.as_ref().as_html_str()),
)
.map(|(a,b)| iter::once(a).chain(iter::once(b)))
.flatten()
.collect::<String>()
)
}
}
impl Borrow<HtmlStr> for Html {
fn borrow<'b>(&'b self) -> &'b HtmlStr {
HtmlStr::from_html_str(&self.0)
}
}
impl Borrow<HtmlStr> for HtmlLit {
fn borrow<'b>(&'b self) -> &'static HtmlStr {
HtmlStr::from_html_str(self.0)
}
}
impl ToOwned for HtmlStr {
type Owned = Html;
fn to_owned(&self) -> Html { Html(self.0.to_owned()) }
}
#[ext(pub, name=HtmlFormatRef)]
impl<'e, T: HtmlFormat<'e>> T {
fn to_html(&'e self) -> Html { hformat!("{}", *self) }
}
impl<'e> HtmlFormat<'e> for Html {
type Encoded = &'e str;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded { &self.0 }
}
impl<'e> HtmlFormat<'e> for HtmlStr {
type Encoded = &'e str;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded { &self.0 }
}
impl<'e> HtmlFormat<'e> for HtmlLit {
type Encoded = &'static str;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded { self.0 }
}
impl<'e> HtmlFormat<'e> for str {
type Encoded = String;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded {
htmlescape::encode_minimal(self)
}
}
impl<'e> HtmlFormat<'e> for String {
type Encoded = String;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded {
htmlescape::encode_minimal(self)
}
}
hformat_as_display!{ usize u8 u16 u32 u64
isize i8 i16 i32 i64
f32 f64 }
#[macro_export]
macro_rules! hformat_as_display {
( $( $t:ty )* ) => {
$(
impl<'e> $crate::html::HtmlFormat<'e> for $t {
type Encoded = &'e $t;
fn html_format<'f: 'e>(&'f self) -> Self::Encoded { self }
}
)*
}
}
#[macro_export]
macro_rules! hformat {
( $f:tt $(,$( $v:expr )?)* ) => {
Html::from_html_string(
format!(
$f $(,$(
$crate::html::HtmlFormat::html_format(&$v)
)?)*
)
)
}
}
#[macro_export]
macro_rules! hwrite {
( $o:expr, $f:tt $(,$( $v:expr )?)* ) => {
write!(
$crate::html::Html::as_html_string_mut($o),
$f $(,$(
$crate::html::HtmlFormat::html_format(&$v)
)?)*
)
}
}