#![feature(specialization)]
#![doc(html_root_url = "https://docs.rs/maud/0.20.0")]
#[cfg(feature = "actix-web")] extern crate actix_web;
#[cfg(feature = "iron")] extern crate iron;
#[cfg(feature = "rocket")] extern crate rocket;
extern crate maud_htmlescape;
extern crate maud_macros;
use std::fmt::{self, Write};
pub use maud_macros::{html, html_debug};
pub trait Render {
fn render(&self) -> Markup {
let mut buffer = String::new();
self.render_to(&mut buffer);
PreEscaped(buffer)
}
fn render_to(&self, buffer: &mut String) {
buffer.push_str(&self.render().into_string());
}
}
impl<T: fmt::Display + ?Sized> Render for T {
default fn render_to(&self, w: &mut String) {
let _ = write!(Escaper::new(w), "{}", self);
}
}
impl Render for String {
fn render_to(&self, w: &mut String) {
let _ = Escaper::new(w).write_str(self);
}
}
impl Render for str {
fn render_to(&self, w: &mut String) {
let _ = Escaper::new(w).write_str(self);
}
}
#[derive(Debug, Clone, Copy)]
pub struct PreEscaped<T: AsRef<str>>(pub T);
impl<T: AsRef<str>> Render for PreEscaped<T> {
fn render_to(&self, w: &mut String) {
w.push_str(self.0.as_ref());
}
}
pub type Markup = PreEscaped<String>;
impl<T: AsRef<str> + Into<String>> PreEscaped<T> {
pub fn into_string(self) -> String {
self.0.into()
}
}
impl<T: AsRef<str> + Into<String>> Into<String> for PreEscaped<T> {
fn into(self) -> String {
self.into_string()
}
}
pub use maud_htmlescape::Escaper;
pub const DOCTYPE: PreEscaped<&'static str> = PreEscaped("<!DOCTYPE html>");
#[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, 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 io::Write) -> io::Result<()> {
self.0.write_body(body)
}
}
}
#[cfg(feature = "rocket")]
mod rocket_support {
use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response::{Responder, Response};
use std::io::Cursor;
use PreEscaped;
impl Responder<'static> for PreEscaped<String> {
fn respond_to(self, _: &Request) -> Result<Response<'static>, Status> {
Response::build()
.header(ContentType::HTML)
.sized_body(Cursor::new(self.0))
.ok()
}
}
}
#[cfg(feature = "actix-web")]
mod actix_support {
use PreEscaped;
use actix_web::{Responder, HttpResponse, HttpRequest, Error};
impl Responder for PreEscaped<String> {
type Item = HttpResponse;
type Error = Error;
fn respond_to<S>(self, _req: &HttpRequest<S>) -> Result<Self::Item, Self::Error> {
Ok(HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(self.0))
}
}
}