extern crate horrorshow;
#[doc(no_inline)]
pub use self::horrorshow::Template;
pub use self::imp::{renderer, RenderEndpoint, Renderer};
mod imp {
use super::horrorshow::Template;
use finchers::endpoint::wrapper::Wrapper;
use finchers::endpoint::{ApplyContext, ApplyResult, Endpoint};
use finchers::error;
use finchers::error::Error;
use futures::{Future, Poll};
use http::header;
use http::header::HeaderValue;
use http::Response;
use mime;
use mime::Mime;
pub fn renderer() -> Renderer {
Renderer {
content_type: mime::TEXT_HTML_UTF_8.as_ref().parse().unwrap(),
}
}
#[derive(Debug)]
pub struct Renderer {
content_type: HeaderValue,
}
impl Renderer {
pub fn content_type(self, content_type: Mime) -> Renderer {
let content_type = content_type
.as_ref()
.parse()
.expect("the MIME value should be a valid header value");
Renderer {
content_type,
..self
}
}
fn render_response<T>(&self, ctx: T) -> Result<Response<String>, super::horrorshow::Error>
where
T: Template,
{
let mut response = ctx.into_string().map(Response::new)?;
response
.headers_mut()
.insert(header::CONTENT_TYPE, self.content_type.clone());
Ok(response)
}
}
impl<'a, E, CtxT> Wrapper<'a, E> for Renderer
where
E: Endpoint<'a, Output = (CtxT,)>,
CtxT: Template,
{
type Output = (Response<String>,);
type Endpoint = RenderEndpoint<E>;
fn wrap(self, endpoint: E) -> Self::Endpoint {
RenderEndpoint {
endpoint,
renderer: self,
}
}
}
#[derive(Debug)]
pub struct RenderEndpoint<E> {
endpoint: E,
renderer: Renderer,
}
impl<'a, E, CtxT> Endpoint<'a> for RenderEndpoint<E>
where
E: Endpoint<'a, Output = (CtxT,)>,
CtxT: Template,
{
type Output = (Response<String>,);
type Future = RenderFuture<'a, E>;
fn apply(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
Ok(RenderFuture {
future: self.endpoint.apply(cx)?,
endpoint: self,
})
}
}
#[derive(Debug)]
pub struct RenderFuture<'a, E: Endpoint<'a>> {
future: E::Future,
endpoint: &'a RenderEndpoint<E>,
}
impl<'a, E, CtxT> Future for RenderFuture<'a, E>
where
E: Endpoint<'a, Output = (CtxT,)>,
CtxT: Template,
{
type Item = (Response<String>,);
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let (ctx,) = try_ready!(self.future.poll());
self.endpoint
.renderer
.render_response(ctx)
.map(|response| (response,).into())
.map_err(error::fail)
}
}
}