use std::borrow::Cow;
use std::convert::Infallible;
use bytes::Bytes;
use http::HeaderMap;
use http::StatusCode;
use http::header::HeaderName;
use http::header::HeaderValue;
use http_body_util::Full;
use crate::body::TakoBody;
use crate::types::Response;
pub const NOT_FOUND: (StatusCode, &str) = (StatusCode::NOT_FOUND, "Not Found");
#[doc(alias = "response")]
pub trait Responder {
fn into_response(self) -> Response;
}
pub use Responder as IntoResponse;
impl Responder for Response {
fn into_response(self) -> Response {
self
}
}
impl Responder for TakoBody {
fn into_response(self) -> Response {
Response::new(self)
}
}
impl Responder for &'static str {
fn into_response(self) -> Response {
Response::new(TakoBody::full(Full::from(Bytes::from_static(
self.as_bytes(),
))))
}
}
impl Responder for String {
fn into_response(self) -> Response {
Response::new(TakoBody::full(Full::from(Bytes::from(self))))
}
}
impl Responder for () {
fn into_response(self) -> Response {
Response::new(TakoBody::empty())
}
}
impl Responder for Infallible {
fn into_response(self) -> Response {
match self {}
}
}
impl Responder for (StatusCode, &'static str) {
fn into_response(self) -> Response {
let (status, body) = self;
let mut res = Response::new(TakoBody::full(Full::from(Bytes::from_static(
body.as_bytes(),
))));
*res.status_mut() = status;
res
}
}
impl Responder for (StatusCode, String) {
fn into_response(self) -> Response {
let (status, body) = self;
let mut res = Response::new(TakoBody::full(Full::from(Bytes::from(body))));
*res.status_mut() = status;
res
}
}
impl Responder for (StatusCode, Vec<u8>) {
fn into_response(self) -> Response {
let (status, body) = self;
let mut res = Response::new(TakoBody::full(Full::from(Bytes::from(body))));
*res.status_mut() = status;
res
}
}
impl Responder for Bytes {
fn into_response(self) -> Response {
Response::new(TakoBody::full(Full::from(self)))
}
}
impl Responder for Vec<u8> {
fn into_response(self) -> Response {
Response::new(TakoBody::full(Full::from(Bytes::from(self))))
}
}
impl Responder for Cow<'static, str> {
fn into_response(self) -> Response {
match self {
Cow::Borrowed(s) => {
Response::new(TakoBody::full(Full::from(Bytes::from_static(s.as_bytes()))))
}
Cow::Owned(s) => Response::new(TakoBody::full(Full::from(Bytes::from(s)))),
}
}
}
impl Responder for serde_json::Value {
fn into_response(self) -> Response {
match serde_json::to_vec(&self) {
Ok(buf) => {
let mut res = Response::new(TakoBody::full(Full::from(Bytes::from(buf))));
res.headers_mut().insert(
http::header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
);
res
}
Err(err) => {
let mut res = Response::new(TakoBody::from(err.to_string()));
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
res.headers_mut().insert(
http::header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
);
res
}
}
}
}
impl Responder for (StatusCode, HeaderMap, TakoBody) {
fn into_response(self) -> Response {
let (status, headers, body) = self;
let mut res = Response::new(body);
*res.status_mut() = status;
*res.headers_mut() = headers;
res
}
}
impl Responder for (StatusCode, HeaderMap) {
fn into_response(self) -> Response {
let (status, headers) = self;
let mut res = Response::new(TakoBody::empty());
*res.status_mut() = status;
*res.headers_mut() = headers;
res
}
}
impl Responder for HeaderMap {
fn into_response(self) -> Response {
let mut res = Response::new(TakoBody::empty());
*res.headers_mut() = self;
res
}
}
impl Responder for StatusCode {
fn into_response(self) -> Response {
let mut res = Response::new(TakoBody::empty());
*res.status_mut() = self;
res
}
}
pub struct StaticHeaders<const N: usize>(pub [(HeaderName, &'static str); N]);
impl<const N: usize> Responder for (StatusCode, StaticHeaders<N>) {
fn into_response(self) -> Response {
let (status, StaticHeaders(headers)) = self;
let mut res = Response::new(TakoBody::empty());
*res.status_mut() = status;
for (name, value) in headers {
res
.headers_mut()
.append(name, HeaderValue::from_static(value));
}
res
}
}
impl Responder for anyhow::Error {
fn into_response(self) -> Response {
let mut res = Response::new(TakoBody::from(self.to_string()));
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
res.headers_mut().insert(
http::header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
);
res
}
}
impl ResponderError for anyhow::Error {}
impl<T, E> Responder for Result<T, E>
where
T: Responder,
E: ResponderError,
{
fn into_response(self) -> Response {
match self {
Ok(ok) => ok.into_response(),
Err(err) => err.into_response(),
}
}
}
pub trait ResponderError: Responder {}