volo_http/server/response/
into_response.rs1use std::{convert::Infallible, error::Error};
2
3use http::{
4 header::{HeaderMap, HeaderValue, IntoHeaderName},
5 status::StatusCode,
6};
7
8use crate::{body::Body, response::Response};
9
10pub trait TryIntoResponseHeaders {
12 type Error: Error;
13
14 fn try_into_response_headers(self) -> Result<HeaderMap, Self::Error>;
15}
16
17pub trait IntoResponse {
19 fn into_response(self) -> Response;
21}
22
23impl<K, V> TryIntoResponseHeaders for (K, V)
24where
25 K: IntoHeaderName,
26 V: TryInto<HeaderValue>,
27 V::Error: Error,
28{
29 type Error = V::Error;
30
31 fn try_into_response_headers(self) -> Result<HeaderMap, Self::Error> {
32 let mut headers = HeaderMap::with_capacity(1);
33 headers.insert(self.0, self.1.try_into()?);
34 Ok(headers)
35 }
36}
37
38impl<K, V, const N: usize> TryIntoResponseHeaders for [(K, V); N]
39where
40 K: IntoHeaderName,
41 V: TryInto<HeaderValue>,
42 V::Error: Error,
43{
44 type Error = V::Error;
45
46 fn try_into_response_headers(self) -> Result<HeaderMap, Self::Error> {
47 let mut headers = HeaderMap::with_capacity(N);
48 for (k, v) in self.into_iter() {
49 headers.insert(k, v.try_into()?);
50 }
51 Ok(headers)
52 }
53}
54
55impl IntoResponse for Infallible {
56 fn into_response(self) -> Response {
57 StatusCode::INTERNAL_SERVER_ERROR.into_response()
58 }
59}
60
61impl<T> IntoResponse for T
62where
63 T: TryInto<Body>,
64 T::Error: IntoResponse,
65{
66 fn into_response(self) -> Response {
67 let body = match self.try_into() {
68 Ok(body) => body,
69 Err(e) => {
70 return e.into_response();
71 }
72 };
73 Response::builder()
74 .status(StatusCode::OK)
75 .body(body)
76 .unwrap()
77 }
78}
79
80impl<R, E> IntoResponse for Result<R, E>
81where
82 R: IntoResponse,
83 E: IntoResponse,
84{
85 fn into_response(self) -> Response {
86 match self {
87 Ok(value) => value.into_response(),
88 Err(err) => err.into_response(),
89 }
90 }
91}
92
93impl<T> IntoResponse for (StatusCode, T)
94where
95 T: IntoResponse,
96{
97 fn into_response(self) -> Response {
98 let mut resp = self.1.into_response();
99 *resp.status_mut() = self.0;
100 resp
101 }
102}
103
104impl IntoResponse for StatusCode {
105 fn into_response(self) -> Response {
106 Response::builder()
107 .status(self)
108 .body(String::new().into())
109 .unwrap()
110 }
111}
112
113impl<B> IntoResponse for http::Response<B>
114where
115 B: Into<Body>,
116{
117 fn into_response(self) -> Response {
118 let (parts, body) = self.into_parts();
119 Response::from_parts(parts, body.into())
120 }
121}
122
123impl<H, R> IntoResponse for (H, R)
124where
125 H: TryIntoResponseHeaders,
126 R: IntoResponse,
127{
128 fn into_response(self) -> Response {
129 let mut resp = self.1.into_response();
130 if let Ok(headers) = self.0.try_into_response_headers() {
131 resp.headers_mut().extend(headers);
132 }
133 resp
134 }
135}
136
137#[cfg(feature = "form")]
138impl<T> IntoResponse for crate::server::extract::Form<T>
139where
140 T: serde::Serialize,
141{
142 fn into_response(self) -> Response {
143 let Ok(body) = serde_urlencoded::to_string(&self.0) else {
144 return StatusCode::INTERNAL_SERVER_ERROR.into_response();
145 };
146 let body = Body::from(body);
147
148 Response::builder()
149 .status(StatusCode::OK)
150 .header(
151 http::header::CONTENT_TYPE,
152 mime::APPLICATION_WWW_FORM_URLENCODED.essence_str(),
153 )
154 .body(body)
155 .unwrap_or_else(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response())
156 }
157}
158
159#[cfg(feature = "json")]
160impl<T> IntoResponse for crate::server::extract::Json<T>
161where
162 T: serde::Serialize,
163{
164 fn into_response(self) -> Response {
165 let Ok(body) = crate::utils::json::serialize(&self.0) else {
166 return StatusCode::INTERNAL_SERVER_ERROR.into_response();
167 };
168 let body = Body::from(body);
169
170 Response::builder()
171 .status(StatusCode::OK)
172 .header(
173 http::header::CONTENT_TYPE,
174 mime::APPLICATION_JSON.essence_str(),
175 )
176 .body(body)
177 .unwrap_or_else(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response())
178 }
179}
180
181#[cfg(feature = "json")]
182impl IntoResponse for crate::utils::json::Error {
183 fn into_response(self) -> Response {
184 StatusCode::BAD_REQUEST.into_response()
185 }
186}