1use std::convert::Infallible;
2
3use bytes::Bytes;
4use http::{header, HeaderMap, HeaderName, HeaderValue, StatusCode};
5use mincat_macro::repeat_macro_max_generics_param;
6
7use crate::body::Body;
8
9pub type Response<T = Body> = http::Response<T>;
10
11pub trait IntoResponse {
12 fn into_response(self) -> Response;
13}
14
15pub trait IntoResponseParts {
16 fn into_response_parts(self, response: Response) -> Response;
17}
18
19impl IntoResponse for () {
20 fn into_response(self) -> Response {
21 Response::new(Body::empty())
22 }
23}
24
25impl IntoResponseParts for () {
26 fn into_response_parts(self, response: Response) -> Response {
27 response
28 }
29}
30
31impl IntoResponse for Infallible {
32 fn into_response(self) -> Response {
33 Response::new(Body::empty())
34 }
35}
36
37impl IntoResponseParts for Infallible {
38 fn into_response_parts(self, response: Response) -> Response {
39 response
40 }
41}
42
43impl<T, E> IntoResponse for Result<T, E>
44where
45 T: IntoResponse,
46 E: IntoResponse,
47{
48 fn into_response(self) -> Response {
49 match self {
50 Ok(value) => value.into_response(),
51 Err(err) => err.into_response(),
52 }
53 }
54}
55
56impl IntoResponse for Body {
57 fn into_response(self) -> Response {
58 Response::new(self)
59 }
60}
61
62impl IntoResponse for StatusCode {
63 fn into_response(self) -> Response {
64 let mut res = ().into_response();
65 *res.status_mut() = self;
66 res
67 }
68}
69
70impl IntoResponseParts for StatusCode {
71 fn into_response_parts(self, mut response: Response) -> Response {
72 *response.status_mut() = self;
73 response
74 }
75}
76
77impl IntoResponse for &'static str {
78 fn into_response(self) -> Response {
79 let mut res = Response::new(Body::from(self));
80 res.headers_mut().insert(
81 header::CONTENT_TYPE,
82 HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
83 );
84 res
85 }
86}
87
88impl IntoResponse for String {
89 fn into_response(self) -> Response {
90 let mut res = Response::new(Body::from(self));
91 res.headers_mut().insert(
92 header::CONTENT_TYPE,
93 HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
94 );
95 res
96 }
97}
98
99impl IntoResponse for Response {
100 fn into_response(self) -> Response {
101 self
102 }
103}
104
105impl IntoResponse for Bytes {
106 fn into_response(self) -> Response {
107 let mut res = Body::from(self).into_response();
108 res.headers_mut().insert(
109 header::CONTENT_TYPE,
110 HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
111 );
112 res
113 }
114}
115
116impl IntoResponseParts for HeaderMap {
117 fn into_response_parts(self, mut response: Response) -> Response {
118 response.headers_mut().extend(self);
119 response
120 }
121}
122
123fn insert_headers<K, V, const N: usize>(
124 mut res: Response,
125 arr: [(K, V); N],
126) -> Result<Response, String>
127where
128 K: TryInto<HeaderName>,
129 K::Error: std::fmt::Display,
130 V: TryInto<HeaderValue>,
131 V::Error: std::fmt::Display,
132{
133 for (key, value) in arr {
134 let key = key.try_into().map_err(|e| e.to_string())?;
135 let value = value.try_into().map_err(|e| e.to_string())?;
136 res.headers_mut().insert(key, value);
137 }
138 Ok(res)
139}
140
141impl<K, V, const N: usize> IntoResponse for [(K, V); N]
142where
143 K: TryInto<HeaderName>,
144 K::Error: std::fmt::Display,
145 V: TryInto<HeaderValue>,
146 V::Error: std::fmt::Display,
147{
148 fn into_response(self) -> Response {
149 let res = ().into_response();
150 insert_headers(res, self).into_response()
151 }
152}
153
154impl<K, V, const N: usize> IntoResponseParts for [(K, V); N]
155where
156 K: TryInto<HeaderName>,
157 K::Error: std::fmt::Display,
158 V: TryInto<HeaderValue>,
159 V::Error: std::fmt::Display,
160{
161 fn into_response_parts(self, response: Response) -> Response {
162 insert_headers(response, self).into_response()
163 }
164}
165
166macro_rules! impl_into_response_parts_tuple {
167 ( $($ty:ident),* ) => {
168 #[allow(non_snake_case)]
169 impl<$($ty,)*> IntoResponseParts for ($($ty,)*)
170 where
171 $( $ty: IntoResponseParts, )*
172 {
173 fn into_response_parts(self,response: Response) -> Response {
174 let ($($ty,)*) = self;
175 $(
176 let response = $ty.into_response_parts(response);
177 )*
178 response
179 }
180 }
181 }
182}
183
184repeat_macro_max_generics_param!(impl_into_response_parts_tuple, 1, 17, P);
185
186macro_rules! impl_into_response_tuple {
187 ( $($ty:ident),* ) => {
188 #[allow(non_snake_case)]
189 impl<R, $($ty,)*> IntoResponse for ($($ty),*, R)
190 where
191 $( $ty: IntoResponseParts, )*
192 R: IntoResponse,
193 {
194 fn into_response(self) -> Response {
195 let ( $($ty),*, response) = self;
196 let response = response.into_response();
197 $(
198 let response = $ty.into_response_parts(response);
199 )*
200 response
201 }
202 }
203 };
204}
205
206repeat_macro_max_generics_param!(impl_into_response_tuple, 1, 17, P);