use {Response, NickelError, MiddlewareResult, Halt};
use hyper::status::{StatusCode, StatusClass};
use hyper::header;
use serde_json;
use mimes::MediaType;
use std::io::Write;
pub trait Responder<D> {
fn respond<'a>(self, Response<'a, D>) -> MiddlewareResult<'a, D>;
}
impl<D> Responder<D> for () {
fn respond<'a>(self, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
res.next_middleware()
}
}
impl<D> Responder<D> for serde_json::Value {
fn respond<'a>(self, mut res: Response<'a, D>) -> MiddlewareResult<'a, D> {
maybe_set_type(&mut res, MediaType::Json);
res.send(serde_json::to_string(&self)
.map_err(|e| format!("Failed to parse JSON: {}", e)))
}
}
impl<T, E, D> Responder<D> for Result<T, E>
where T: Responder<D>,
for<'e> NickelError<'e, D>: From<(Response<'e, D>, E)> {
fn respond<'a>(self, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
let data = try_with!(res, self);
res.send(data)
}
}
macro_rules! dual_impl {
($view:ty, $alloc:ty, |$s:ident, $res:ident| $b:block) => (
impl<'a, D> Responder<D> for $view {
#[allow(unused_mut)]
#[inline]
fn respond<'c>($s, mut $res: Response<'c, D>) -> MiddlewareResult<'c, D> $b
}
impl<'a, D> Responder<D> for $alloc {
#[allow(unused_mut)]
#[inline]
fn respond<'c>($s, mut $res: Response<'c, D>) -> MiddlewareResult<'c, D> $b
}
)
}
dual_impl!(&'a [u8],
Vec<u8>,
|self, res| {
maybe_set_type(&mut res, MediaType::Bin);
let mut stream = try!(res.start());
match stream.write_all(&self[..]) {
Ok(()) => Ok(Halt(stream)),
Err(e) => stream.bail(format!("Failed to send: {}", e))
}
});
dual_impl!(&'a str,
String,
|self, res| {
maybe_set_type(&mut res, MediaType::Html);
res.send(self.as_bytes())
});
dual_impl!((StatusCode, &'static str),
(StatusCode, String),
|self, res| {
let (status, message) = self;
match status.class() {
StatusClass::ClientError | StatusClass::ServerError => {
res.error(status, message)
},
_ => {
res.set(status);
res.send(message)
}
}
});
impl<'a, D> Responder<D> for StatusCode {
#[inline]
fn respond<'c>(self, res: Response<'c, D>) -> MiddlewareResult<'c, D> {
res.send((self, ""))
}
}
dual_impl!(&'a [&'a str],
&'a [String],
|self, res| {
maybe_set_type(&mut res, MediaType::Html);
let mut stream = try!(res.start());
for ref s in self.iter() {
if let Err(e) = stream.write_all(s.as_bytes()) {
return stream.bail(format!("Failed to write to stream: {}", e))
}
}
Ok(Halt(stream))
});
dual_impl!((u16, &'static str),
(u16, String),
|self, res| {
let (status, message) = self;
res.send((StatusCode::from_u16(status), message))
});
fn maybe_set_type<D>(res: &mut Response<D>, mime: MediaType) {
res.set_header_fallback(|| header::ContentType(mime.into()));
}