viz_core/
into_response.rs

1use http_body_util::Full;
2
3use crate::{
4    header::{CONTENT_LENGTH, CONTENT_TYPE},
5    Error, Response, Result, StatusCode,
6};
7
8/// Trait implemented by types that can be converted to an HTTP [`Response`].
9pub trait IntoResponse: Sized {
10    /// Convert self to HTTP [`Response`].
11    #[must_use]
12    fn into_response(self) -> Response;
13
14    /// Convert self to the [`Error`].
15    fn into_error(self) -> Error {
16        Error::Responder(self.into_response())
17    }
18}
19
20impl IntoResponse for Response {
21    fn into_response(self) -> Response {
22        self
23    }
24}
25
26impl IntoResponse for Error {
27    fn into_response(self) -> Response {
28        match self {
29            Self::Boxed(error) => {
30                let body = error.to_string();
31                Response::builder()
32                    .status(StatusCode::INTERNAL_SERVER_ERROR)
33                    .header(CONTENT_LENGTH, body.len())
34                    .body(Full::from(body).into())
35                    .unwrap()
36            }
37            Self::Responder(resp) | Self::Report(_, resp) => resp,
38        }
39    }
40}
41
42impl IntoResponse for std::io::Error {
43    fn into_response(self) -> Response {
44        let body = self.to_string();
45        Response::builder()
46            .status(StatusCode::INTERNAL_SERVER_ERROR)
47            .header(CONTENT_LENGTH, body.len())
48            .body(Full::from(body).into())
49            .unwrap()
50    }
51}
52
53impl IntoResponse for std::convert::Infallible {
54    fn into_response(self) -> Response {
55        Response::new(().into())
56    }
57}
58
59impl IntoResponse for String {
60    fn into_response(self) -> Response {
61        Response::builder()
62            .header(CONTENT_TYPE, mime::TEXT_PLAIN_UTF_8.as_ref())
63            .header(CONTENT_LENGTH, self.len())
64            .body(Full::from(self).into())
65            .unwrap()
66    }
67}
68
69impl IntoResponse for &'static str {
70    fn into_response(self) -> Response {
71        Response::builder()
72            .header(CONTENT_TYPE, mime::TEXT_PLAIN_UTF_8.as_ref())
73            .header(CONTENT_LENGTH, self.len())
74            .body(Full::from(self).into())
75            .unwrap()
76    }
77}
78
79impl IntoResponse for &'static [u8] {
80    fn into_response(self) -> Response {
81        bytes::Bytes::into_response(self.into())
82    }
83}
84
85impl IntoResponse for Vec<u8> {
86    fn into_response(self) -> Response {
87        bytes::Bytes::into_response(self.into())
88    }
89}
90
91impl IntoResponse for bytes::Bytes {
92    fn into_response(self) -> Response {
93        Response::builder()
94            .header(CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM.as_ref())
95            .header(CONTENT_LENGTH, self.len())
96            .body(Full::from(self).into())
97            .unwrap()
98    }
99}
100
101impl IntoResponse for StatusCode {
102    fn into_response(self) -> Response {
103        Response::builder().status(self).body(().into()).unwrap()
104    }
105}
106
107impl<T> IntoResponse for Option<T>
108where
109    T: IntoResponse,
110{
111    fn into_response(self) -> Response {
112        self.map_or_else(
113            || StatusCode::NOT_FOUND.into_response(),
114            IntoResponse::into_response,
115        )
116    }
117}
118
119impl<T, E> IntoResponse for Result<T, E>
120where
121    T: IntoResponse,
122    E: IntoResponse,
123{
124    fn into_response(self) -> Response {
125        match self {
126            Ok(r) => r.into_response(),
127            Err(e) => e.into_response(),
128        }
129    }
130}
131
132impl IntoResponse for () {
133    fn into_response(self) -> Response {
134        Response::new(self.into())
135    }
136}
137
138impl<T> IntoResponse for (StatusCode, T)
139where
140    T: IntoResponse,
141{
142    fn into_response(self) -> Response {
143        let mut res = self.1.into_response();
144        *res.status_mut() = self.0;
145        res
146    }
147}