use crate::Body; use bytes::Bytes; use http::{header, HeaderMap, HeaderValue, Response, StatusCode}; use serde::Serialize; use std::convert::Infallible; use tower::util::Either; // TODO(david): can we change this to not be generic over the body and just use hyper::Body? pub trait IntoResponse { fn into_response(self) -> Response; } impl IntoResponse for () where B: Default, { fn into_response(self) -> Response { Response::new(B::default()) } } impl IntoResponse for Infallible { fn into_response(self) -> Response { match self {} } } impl IntoResponse for Either where T: IntoResponse, K: IntoResponse, { fn into_response(self) -> Response { match self { Either::A(inner) => inner.into_response(), Either::B(inner) => inner.into_response(), } } } impl IntoResponse for Result where T: IntoResponse, E: IntoResponse, { fn into_response(self) -> Response { match self { Ok(value) => value.into_response(), Err(err) => err.into_response(), } } } impl IntoResponse for Response { fn into_response(self) -> Self { self } } impl IntoResponse for &'static str { fn into_response(self) -> Response { Response::new(Body::from(self)) } } impl IntoResponse for String { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut() .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain")); res } } impl IntoResponse for std::borrow::Cow<'static, str> { fn into_response(self) -> Response { Response::new(Body::from(self)) } } impl IntoResponse for Bytes { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for &'static [u8] { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for Vec { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for std::borrow::Cow<'static, [u8]> { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } pub struct Json(pub T); impl IntoResponse for Json where T: Serialize, { fn into_response(self) -> Response { let bytes = match serde_json::to_vec(&self.0) { Ok(res) => res, Err(err) => { return Response::builder() .header(header::CONTENT_TYPE, "text/plain") .body(Body::from(err.to_string())) .unwrap(); } }; let mut res = Response::new(Body::from(bytes)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/json"), ); res } } pub struct Html(pub T); impl IntoResponse for Html where T: Into, { fn into_response(self) -> Response { let bytes = self.0.into(); let mut res = Response::new(Body::from(bytes)); res.headers_mut() .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html")); res } } impl IntoResponse for StatusCode where B: Default, { fn into_response(self) -> Response { Response::builder().status(self).body(B::default()).unwrap() } } impl IntoResponse for (StatusCode, T) where T: Into, { fn into_response(self) -> Response { Response::builder() .status(self.0) .body(self.1.into()) .unwrap() } } impl IntoResponse for (StatusCode, HeaderMap, T) where T: Into, { fn into_response(self) -> Response { let mut res = Response::new(self.2.into()); *res.status_mut() = self.0; *res.headers_mut() = self.1; res } }