mincat_core/
response.rs

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);