boluo_core/response/
into_response.rs

1use std::borrow::Cow;
2use std::convert::Infallible;
3
4use http::{Extensions, HeaderMap, HeaderName, HeaderValue, StatusCode, Version, header};
5
6use crate::BoxError;
7use crate::body::{Body, Bytes, HttpBody};
8use crate::response::{Response, ResponseParts};
9
10/// 用于生成 [`Response`] 的特征。
11///
12/// # 例子
13///
14/// ```
15/// use boluo_core::http::{header, HeaderValue};
16/// use boluo_core::response::{IntoResponse, Response};
17///
18/// #[derive(Debug, Clone, Copy)]
19/// pub struct Html<T>(pub T);
20///
21/// impl<T> IntoResponse for Html<T>
22/// where
23///     T: IntoResponse,
24/// {
25///     type Error = T::Error;
26///
27///     fn into_response(self) -> Result<Response, Self::Error> {
28///         let mut res = self.0.into_response()?;
29///         res.headers_mut().insert(
30///             header::CONTENT_TYPE,
31///             HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()),
32///         );
33///         Ok(res)
34///     }
35/// }
36///
37/// // 在处理程序中使用 `Html` 响应页面。
38/// async fn response_html() -> impl IntoResponse {
39///     Html("<html><body>Hello, World!</body></html>")
40/// }
41/// ```
42pub trait IntoResponse {
43    /// 发生错误时返回的类型。
44    type Error: Into<BoxError>;
45
46    /// 得到一个 [`Response`] 实例。
47    fn into_response(self) -> Result<Response, Self::Error>;
48}
49
50/// 用于向响应添加头部组件的特征。
51pub trait IntoResponseParts {
52    /// 发生错误时返回的类型。
53    type Error: Into<BoxError>;
54
55    /// 向响应添加头部组件。
56    fn into_response_parts(self, parts: ResponseParts) -> Result<ResponseParts, Self::Error>;
57}
58
59impl IntoResponse for Infallible {
60    type Error = Infallible;
61
62    fn into_response(self) -> Result<Response, Self::Error> {
63        match self {}
64    }
65}
66
67impl IntoResponse for () {
68    type Error = Infallible;
69
70    fn into_response(self) -> Result<Response, Self::Error> {
71        Ok(Response::new(Body::empty()))
72    }
73}
74
75impl IntoResponse for &'static str {
76    type Error = Infallible;
77
78    fn into_response(self) -> Result<Response, Self::Error> {
79        Cow::Borrowed(self).into_response()
80    }
81}
82
83impl IntoResponse for String {
84    type Error = Infallible;
85
86    fn into_response(self) -> Result<Response, Self::Error> {
87        Cow::<'static, str>::Owned(self).into_response()
88    }
89}
90
91impl IntoResponse for Cow<'static, str> {
92    type Error = Infallible;
93
94    fn into_response(self) -> Result<Response, Self::Error> {
95        let mut res = Response::new(Body::from(self));
96        res.headers_mut().insert(
97            header::CONTENT_TYPE,
98            HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
99        );
100        Ok(res)
101    }
102}
103
104impl IntoResponse for &'static [u8] {
105    type Error = Infallible;
106
107    fn into_response(self) -> Result<Response, Self::Error> {
108        Cow::Borrowed(self).into_response()
109    }
110}
111
112impl IntoResponse for Vec<u8> {
113    type Error = Infallible;
114
115    fn into_response(self) -> Result<Response, Self::Error> {
116        Cow::<'static, [u8]>::Owned(self).into_response()
117    }
118}
119
120impl IntoResponse for Cow<'static, [u8]> {
121    type Error = Infallible;
122
123    fn into_response(self) -> Result<Response, Self::Error> {
124        let mut res = Response::new(Body::from(self));
125        res.headers_mut().insert(
126            header::CONTENT_TYPE,
127            HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
128        );
129        Ok(res)
130    }
131}
132
133impl IntoResponse for Bytes {
134    type Error = Infallible;
135
136    fn into_response(self) -> Result<Response, Self::Error> {
137        let mut res = Response::new(Body::from(self));
138        res.headers_mut().insert(
139            header::CONTENT_TYPE,
140            HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
141        );
142        Ok(res)
143    }
144}
145
146impl IntoResponse for Body {
147    type Error = Infallible;
148
149    fn into_response(self) -> Result<Response, Self::Error> {
150        Ok(Response::new(self))
151    }
152}
153
154impl<B> IntoResponse for Response<B>
155where
156    B: HttpBody<Data = Bytes> + Send + 'static,
157    B::Error: Into<BoxError>,
158{
159    type Error = Infallible;
160
161    fn into_response(self) -> Result<Response, Self::Error> {
162        Ok(self.map(Body::new))
163    }
164}
165
166impl<R, E> IntoResponse for Result<R, E>
167where
168    R: IntoResponse,
169    E: Into<BoxError>,
170{
171    type Error = BoxError;
172
173    fn into_response(self) -> Result<Response, Self::Error> {
174        self.map_or_else(|e| Err(e.into()), |r| r.into_response().map_err(Into::into))
175    }
176}
177
178impl<P> IntoResponse for P
179where
180    P: IntoResponseParts,
181{
182    type Error = P::Error;
183
184    fn into_response(self) -> Result<Response, Self::Error> {
185        let parts = Response::new(()).into_parts();
186        self.into_response_parts(parts)
187            .map(|parts| Response::from_parts(parts, Body::empty()))
188    }
189}
190
191macro_rules! into_response_tuples {
192    ($($ty:ident),* @ $($tyr:ident),* $(,)?) => {
193        #[allow(non_snake_case)]
194        impl<R, $($ty,)*> IntoResponse for ($($ty),*, R)
195        where
196            $($ty: IntoResponseParts,)*
197            R: IntoResponse,
198        {
199            type Error = BoxError;
200
201            fn into_response(self) -> Result<Response, Self::Error> {
202                let ($($ty),*, res) = self;
203
204                let res = res.into_response().map_err(Into::into)?;
205                let (parts, body) = res.into_inner();
206                $(
207                    let parts = $tyr.into_response_parts(parts).map_err(Into::into)?;
208                )*
209                Ok(Response::from_parts(parts, body))
210            }
211        }
212    }
213}
214
215into_response_tuples!(
216    T1 @
217    T1
218);
219into_response_tuples!(
220    T1, T2 @
221    T2, T1
222);
223into_response_tuples!(
224    T1, T2, T3 @
225    T3, T2, T1
226);
227into_response_tuples!(
228    T1, T2, T3, T4 @
229    T4, T3, T2, T1
230);
231into_response_tuples!(
232    T1, T2, T3, T4, T5 @
233    T5, T4, T3, T2, T1
234);
235into_response_tuples!(
236    T1, T2, T3, T4, T5, T6 @
237    T6, T5, T4, T3, T2, T1
238);
239into_response_tuples!(
240    T1, T2, T3, T4, T5, T6, T7 @
241    T7, T6, T5, T4, T3, T2, T1
242);
243into_response_tuples!(
244    T1, T2, T3, T4, T5, T6, T7, T8 @
245    T8, T7, T6, T5, T4, T3, T2, T1
246);
247into_response_tuples!(
248    T1, T2, T3, T4, T5, T6, T7, T8, T9 @
249    T9, T8, T7, T6, T5, T4, T3, T2, T1
250);
251into_response_tuples!(
252    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 @
253    T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
254);
255into_response_tuples!(
256    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 @
257    T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
258);
259into_response_tuples!(
260    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 @
261    T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
262);
263into_response_tuples!(
264    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 @
265    T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
266);
267into_response_tuples!(
268    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 @
269    T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
270);
271into_response_tuples!(
272    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 @
273    T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
274);
275into_response_tuples!(
276    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 @
277    T16, T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1
278);
279
280impl<T> IntoResponseParts for Option<T>
281where
282    T: IntoResponseParts,
283{
284    type Error = T::Error;
285
286    fn into_response_parts(self, parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
287        match self {
288            Some(this) => this.into_response_parts(parts),
289            None => Ok(parts),
290        }
291    }
292}
293
294impl IntoResponseParts for StatusCode {
295    type Error = Infallible;
296
297    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
298        parts.status = self;
299        Ok(parts)
300    }
301}
302
303impl IntoResponseParts for Version {
304    type Error = Infallible;
305
306    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
307        parts.version = self;
308        Ok(parts)
309    }
310}
311
312impl IntoResponseParts for HeaderMap {
313    type Error = Infallible;
314
315    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
316        parts.headers.extend(self);
317        Ok(parts)
318    }
319}
320
321impl IntoResponseParts for Extensions {
322    type Error = Infallible;
323
324    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
325        parts.extensions.extend(self);
326        Ok(parts)
327    }
328}
329
330impl IntoResponseParts for ResponseParts {
331    type Error = Infallible;
332
333    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
334        parts = self.extensions.into_response_parts(parts)?;
335        parts = self.headers.into_response_parts(parts)?;
336        parts = self.version.into_response_parts(parts)?;
337        parts = self.status.into_response_parts(parts)?;
338        Ok(parts)
339    }
340}
341
342impl<K, V, const N: usize> IntoResponseParts for [(K, V); N]
343where
344    K: TryInto<HeaderName>,
345    K::Error: std::fmt::Display,
346    V: TryInto<HeaderValue>,
347    V::Error: std::fmt::Display,
348{
349    type Error = HeaderResponseError;
350
351    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
352        for (k, v) in self {
353            let k = k
354                .try_into()
355                .map_err(|e| HeaderResponseError::InvalidHeaderName(e.to_string()))?;
356            let v = v
357                .try_into()
358                .map_err(|e| HeaderResponseError::InvalidHeaderValue(e.to_string()))?;
359            parts.headers.insert(k, v);
360        }
361        Ok(parts)
362    }
363}
364
365impl<K, V> IntoResponseParts for Vec<(K, V)>
366where
367    K: TryInto<HeaderName>,
368    K::Error: std::fmt::Display,
369    V: TryInto<HeaderValue>,
370    V::Error: std::fmt::Display,
371{
372    type Error = HeaderResponseError;
373
374    fn into_response_parts(self, mut parts: ResponseParts) -> Result<ResponseParts, Self::Error> {
375        for (k, v) in self {
376            let k = k
377                .try_into()
378                .map_err(|e| HeaderResponseError::InvalidHeaderName(e.to_string()))?;
379            let v = v
380                .try_into()
381                .map_err(|e| HeaderResponseError::InvalidHeaderValue(e.to_string()))?;
382            parts.headers.insert(k, v);
383        }
384        Ok(parts)
385    }
386}
387
388/// 标头响应错误。
389#[derive(Debug, Clone)]
390pub enum HeaderResponseError {
391    /// 无效的标头名。
392    InvalidHeaderName(String),
393    /// 无效的标头值。
394    InvalidHeaderValue(String),
395}
396
397impl std::fmt::Display for HeaderResponseError {
398    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399        match self {
400            HeaderResponseError::InvalidHeaderName(e) => {
401                write!(f, "invalid response header name ({e})")
402            }
403            HeaderResponseError::InvalidHeaderValue(e) => {
404                write!(f, "invalid response header value ({e})")
405            }
406        }
407    }
408}
409
410impl std::error::Error for HeaderResponseError {}