tela 0.1.3

Web framework that focuses on ease of use and simplicity
Documentation
mod file;
mod html;
mod json;
mod redirect;

pub mod template;

use bytes::Bytes;
use http_body_util::Full;

pub use file::File;
pub use html::HTML;
use hyper::{Method, Uri};
pub use json::{Raw, JSON};
pub use redirect::Redirect;
pub use template::Template;

use crate::StatusCode;

pub type Result<T> = std::result::Result<T, (u16, String)>;

pub trait ToResponse {
    fn to_response(
        self,
        method: &Method,
        uri: &Uri,
        body: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>>;
}

pub trait ToErrorResponse {
    fn to_error_response(
        self,
        code: u16,
        reason: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>>;
}

impl<T: ToResponse> ToResponse for (u16, T) {
    fn to_response(
        self,
        method: &Method,
        uri: &Uri,
        body: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        let code = self.0;
        self.1.to_response(method, uri, body).map(|result| {
            let mut response = hyper::Response::builder()
                .status(code)
                .body(result.body().clone())
                .unwrap();

            // Copy over all headers
            response.headers_mut().extend(result.headers().clone());

            response
        })
    }
}

impl<T: ToResponse> ToResponse for (StatusCode, T) {
    fn to_response(
        self,
        method: &Method,
        uri: &Uri,
        body: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        let code: u16 = self.0 as u16;
        self.1.to_response(method, uri, body).map(|result| {
            let mut response = hyper::Response::builder()
                .status(code)
                .body(result.body().clone())
                .unwrap();

            // Copy over all headers
            response.headers_mut().extend(result.headers().clone());

            response
        })
    }
}

impl<T: ToResponse> ToResponse for Result<T> {
    fn to_response(
        self,
        method: &Method,
        uri: &Uri,
        body: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        match self {
            Ok(response) => response.to_response(method, uri, body),
            Err(error) => Err(error),
        }
    }
}

impl ToResponse for String {
    fn to_response(
        self,
        _method: &Method,
        _uri: &Uri,
        _body: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        Ok(hyper::Response::builder()
            .status(200)
            .header("Content-Type", "text/plain")
            .body(Full::new(Bytes::from(self)))
            .unwrap())
    }
}

impl ToErrorResponse for String {
    fn to_error_response(
        self,
        code: u16,
        reason: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        Ok(hyper::Response::builder()
            .status(code)
            .header("Content-Type", "text/plain")
            .header("Wayfinder-Reason", reason)
            .body(Full::new(Bytes::from(self)))
            .unwrap())
    }
}

impl ToResponse for &str {
    fn to_response(
        self,
        _method: &Method,
        _uri: &Uri,
        _body: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        Ok(hyper::Response::builder()
            .status(200)
            .header("Content-Type", "text/plain")
            .body(Full::new(Bytes::from(self.to_string())))
            .unwrap())
    }
}

impl ToErrorResponse for &str {
    fn to_error_response(
        self,
        code: u16,
        reason: String,
    ) -> Result<hyper::Response<http_body_util::Full<bytes::Bytes>>> {
        Ok(hyper::Response::builder()
            .status(code)
            .header("Content-Type", "text/plain")
            .header("Wayfinder-Reason", reason)
            .body(Full::new(Bytes::from(self.to_string())))
            .unwrap())
    }
}