use mime::TEXT_HTML_UTF_8;
use std::error::Error;
use std::io;
use warp::http::{header::CONTENT_TYPE, response};
use warp::{reject::Reject, reply::Response, Reply};
pub trait RenderRucte {
fn html<F>(self, f: F) -> Result<Response, RenderError>
where
F: FnOnce(&mut Vec<u8>) -> io::Result<()>;
}
impl RenderRucte for response::Builder {
fn html<F>(self, f: F) -> Result<Response, RenderError>
where
F: FnOnce(&mut Vec<u8>) -> io::Result<()>,
{
let mut buf = Vec::new();
f(&mut buf).map_err(RenderError::write)?;
self.header(CONTENT_TYPE, TEXT_HTML_UTF_8.as_ref())
.body(buf.into())
.map_err(RenderError::build)
}
}
#[derive(Debug)]
pub struct RenderError {
im: RenderErrorImpl,
}
impl RenderError {
fn build(e: warp::http::Error) -> Self {
RenderError { im: RenderErrorImpl::Build(e) }
}
fn write(e: std::io::Error) -> Self {
RenderError { im: RenderErrorImpl::Write(e) }
}
}
#[derive(Debug)]
enum RenderErrorImpl {
Write(std::io::Error),
Build(warp::http::Error),
}
impl Error for RenderError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.im {
RenderErrorImpl::Write(e) => Some(e),
RenderErrorImpl::Build(e) => Some(e),
}
}
}
impl std::fmt::Display for RenderError {
fn fmt(&self, out: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.im {
RenderErrorImpl::Write(_) => "Failed to write template",
RenderErrorImpl::Build(_) => "Failed to build response",
}.fmt(out)
}
}
impl Reject for RenderError {}
impl Reply for RenderError {
fn into_response(self) -> Response {
Response::new(self.to_string().into())
}
}