#![feature(specialization)]
#[cfg(feature = "iron")] extern crate iron;
use std::fmt::{self, Write};
pub trait Render {
fn render(&self, &mut fmt::Write) -> fmt::Result;
}
impl<T: fmt::Display + ?Sized> Render for T {
default fn render(&self, w: &mut fmt::Write) -> fmt::Result {
write!(Escaper::new(w), "{}", self)
}
}
impl Render for String {
fn render(&self, w: &mut fmt::Write) -> fmt::Result {
Escaper::new(w).write_str(self)
}
}
impl Render for str {
fn render(&self, w: &mut fmt::Write) -> fmt::Result {
Escaper::new(w).write_str(self)
}
}
pub trait RenderOnce {
fn render_once(self, &mut fmt::Write) -> fmt::Result;
}
impl<'a, T: Render + ?Sized> RenderOnce for &'a T {
fn render_once(self, w: &mut fmt::Write) -> fmt::Result {
Render::render(self, w)
}
}
#[derive(Debug)]
pub struct PreEscaped<T>(pub T);
impl<T: fmt::Display> Render for PreEscaped<T> {
default fn render(&self, w: &mut fmt::Write) -> fmt::Result {
write!(w, "{}", self.0)
}
}
impl Render for PreEscaped<String> {
fn render(&self, w: &mut fmt::Write) -> fmt::Result {
w.write_str(&self.0)
}
}
impl<'a> Render for PreEscaped<&'a str> {
fn render(&self, w: &mut fmt::Write) -> fmt::Result {
w.write_str(self.0)
}
}
pub type Markup = PreEscaped<String>;
impl PreEscaped<String> {
pub fn into_string(self) -> String {
self.0
}
}
pub struct Escaper<W> {
inner: W,
}
impl<W> Escaper<W> {
pub fn new(inner: W) -> Escaper<W> {
Escaper { inner: inner }
}
pub fn into_inner(self) -> W {
self.inner
}
}
impl<W: fmt::Write> fmt::Write for Escaper<W> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
try!(match c {
'&' => self.inner.write_str("&"),
'<' => self.inner.write_str("<"),
'>' => self.inner.write_str(">"),
'"' => self.inner.write_str("""),
'\'' => self.inner.write_str("'"),
_ => self.inner.write_char(c),
});
}
Ok(())
}
}
#[cfg(feature = "iron")]
mod iron_support {
use std::io;
use iron::headers::ContentType;
use iron::modifier::{Modifier, Set};
use iron::modifiers::Header;
use iron::response::{Response, ResponseBody, WriteBody};
use PreEscaped;
impl Modifier<Response> for PreEscaped<String> {
fn modify(self, response: &mut Response) {
response
.set_mut(Header(ContentType::html()))
.set_mut(Box::new(self) as Box<WriteBody>);
}
}
impl WriteBody for PreEscaped<String> {
fn write_body(&mut self, body: &mut ResponseBody) -> io::Result<()> {
self.0.write_body(body)
}
}
}