|
|
@ -5,8 +5,19 @@ use std::{
|
|
|
|
self,
|
|
|
|
self,
|
|
|
|
Display,
|
|
|
|
Display,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
io,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct HtmlTokenStream<W: io::Write>(W);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<W: io::Write> HtmlTokenStream<W>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fn push<T: DisplayHtml>(&mut self, token: T) -> io::Result<()>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
write!(&mut self.0, "{}", display_html(&token)) //TODO: How to do async version of this?
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Coerce a `DisplayHtml` value into an opaque implementor of `fmt::Display`.
|
|
|
|
/// Coerce a `DisplayHtml` value into an opaque implementor of `fmt::Display`.
|
|
|
|
#[inline] pub fn display_html<'a, T: DisplayHtml+?Sized>(from: &'a T) -> impl fmt::Display +'a
|
|
|
|
#[inline] pub fn display_html<'a, T: DisplayHtml+?Sized>(from: &'a T) -> impl fmt::Display +'a
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -15,7 +26,7 @@ use std::{
|
|
|
|
impl<'a,T> fmt::Display for Wrap<'a,T>
|
|
|
|
impl<'a,T> fmt::Display for Wrap<'a,T>
|
|
|
|
where T: DisplayHtml+?Sized
|
|
|
|
where T: DisplayHtml+?Sized
|
|
|
|
{
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
{
|
|
|
|
{
|
|
|
|
DisplayHtml::fmt(self.0, f)
|
|
|
|
DisplayHtml::fmt(self.0, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -31,12 +42,53 @@ use std::{
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct Wrap<'a, T: Display+?Sized>(&'a T);
|
|
|
|
struct Wrap<'a, T: Display+?Sized>(&'a T);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct FilterStream<T,F>(T, F)
|
|
|
|
|
|
|
|
where F: FnMut(&mut T, char) -> fmt::Result;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T,F> fmt::Write for FilterStream<T,F>
|
|
|
|
|
|
|
|
where T: fmt::Write,
|
|
|
|
|
|
|
|
F: FnMut(&mut T, char) -> fmt::Result
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fn write_str(&mut self, s: &str) -> fmt::Result
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for c in s.chars()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.1(&mut self.0, c)?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_char(&mut self, c: char) -> fmt::Result
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.1(&mut self.0, c)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a,T> DisplayHtml for Wrap<'a,T>
|
|
|
|
impl<'a,T> DisplayHtml for Wrap<'a,T>
|
|
|
|
where T: Display +?Sized
|
|
|
|
where T: Display +?Sized
|
|
|
|
{
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//TODO: Escape HTML the string
|
|
|
|
use smallmap::Map;
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
|
|
|
|
static ref HTML_EQ_TABLE: Map<char, &'static str> = {
|
|
|
|
|
|
|
|
let mut map = Map::new();
|
|
|
|
|
|
|
|
map.insert('&', "&");
|
|
|
|
|
|
|
|
map.insert('<', "<");
|
|
|
|
|
|
|
|
map.insert('>', ">");
|
|
|
|
|
|
|
|
map.insert('"', """);
|
|
|
|
|
|
|
|
map
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut output = FilterStream(f, |output, c| {
|
|
|
|
|
|
|
|
output.write_str(match HTML_EQ_TABLE.get(&c) {
|
|
|
|
|
|
|
|
Some(s) => s,
|
|
|
|
|
|
|
|
None => {
|
|
|
|
|
|
|
|
return output.write_char(c);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
use fmt::Write;
|
|
|
|
|
|
|
|
write!(&mut output, "{}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|