boluo_core/
extract.rs

1//! 从请求中提取数据的类型和特征。
2
3use std::convert::Infallible;
4
5use http::{Extensions, HeaderMap, Method, Uri, Version};
6
7use crate::BoxError;
8use crate::body::{Body, Bytes};
9use crate::request::{Request, RequestParts};
10
11/// 可以根据 [`Request`] 创建的类型,用于实现提取器。
12///
13/// # 例子
14///
15/// ```
16/// use std::convert::Infallible;
17///
18/// use boluo_core::extract::FromRequest;
19/// use boluo_core::http::{header, HeaderValue};
20/// use boluo_core::request::Request;
21///
22/// // 从请求头中提取 HOST 的提取器。
23/// struct Host(Option<HeaderValue>);
24///
25/// // 为提取器实现 `FromRequest` 特征。
26/// impl FromRequest for Host {
27///     type Error = Infallible;
28///
29///     async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
30///         let value = req.headers().get(header::HOST).map(|v| v.to_owned());
31///         Ok(Host(value))
32///     }
33/// }
34///
35/// // 在处理程序中使用提取器从请求中提取数据。
36/// async fn using_extractor(Host(host): Host) {
37///     println!("{host:?}")
38/// }
39/// ```
40pub trait FromRequest: Sized {
41    /// 提取器的错误类型。
42    type Error;
43
44    /// 根据 [`Request`] 创建提取器实例。
45    fn from_request(req: &mut Request) -> impl Future<Output = Result<Self, Self::Error>> + Send;
46}
47
48/// 可以根据 [`Request`] 创建的类型,用于实现提取器。
49///
50/// 与 [`FromRequest`] 不同的是,如果提取的数据不存在,则返回 `Ok(None)`。
51///
52/// # 例子
53///
54/// ```
55/// use std::convert::Infallible;
56///
57/// use boluo_core::extract::OptionalFromRequest;
58/// use boluo_core::http::{header, HeaderValue};
59/// use boluo_core::request::Request;
60///
61/// // 从请求头中提取 HOST 的提取器。
62/// struct Host(HeaderValue);
63///
64/// // 为提取器实现 `OptionalFromRequest` 特征。
65/// impl OptionalFromRequest for Host {
66///     type Error = Infallible;
67///
68///     async fn from_request(req: &mut Request) -> Result<Option<Self>, Self::Error> {
69///         Ok(req.headers().get(header::HOST).map(|v| Host(v.to_owned())))
70///     }
71/// }
72///
73/// // 在处理程序中使用提取器从请求中提取数据。
74/// async fn using_extractor(host: Option<Host>) {
75///     if let Some(Host(host)) = host {
76///         println!("{host:?}")
77///     }
78/// }
79/// ```
80pub trait OptionalFromRequest: Sized {
81    /// 提取器的错误类型。
82    type Error;
83
84    /// 根据 [`Request`] 创建提取器实例。
85    fn from_request(
86        req: &mut Request,
87    ) -> impl Future<Output = Result<Option<Self>, Self::Error>> + Send;
88}
89
90impl<T> FromRequest for Option<T>
91where
92    T: OptionalFromRequest,
93{
94    type Error = T::Error;
95
96    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
97        T::from_request(req).await
98    }
99}
100
101impl<T> FromRequest for Result<T, T::Error>
102where
103    T: FromRequest,
104{
105    type Error = Infallible;
106
107    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
108        Ok(T::from_request(req).await)
109    }
110}
111
112macro_rules! from_request_tuples {
113    ($($ty:ident),*) => {
114        #[allow(non_snake_case)]
115        impl<$($ty,)*> FromRequest for ($($ty,)*)
116        where
117            $($ty: FromRequest + Send,)*
118            $(<$ty as FromRequest>::Error: Into<BoxError>,)*
119        {
120            type Error = BoxError;
121
122            async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
123                $(
124                    let $ty = $ty::from_request(req).await.map_err(Into::into)?;
125                )*
126                Ok(($($ty,)*))
127            }
128        }
129    };
130}
131
132from_request_tuples!(T1);
133from_request_tuples!(T1, T2);
134from_request_tuples!(T1, T2, T3);
135from_request_tuples!(T1, T2, T3, T4);
136from_request_tuples!(T1, T2, T3, T4, T5);
137from_request_tuples!(T1, T2, T3, T4, T5, T6);
138from_request_tuples!(T1, T2, T3, T4, T5, T6, T7);
139from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8);
140from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
141from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
142from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
143from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
144from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
145from_request_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
146from_request_tuples!(
147    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
148);
149from_request_tuples!(
150    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
151);
152
153impl FromRequest for Body {
154    type Error = Infallible;
155
156    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
157        Ok(std::mem::take(req.body_mut()))
158    }
159}
160
161impl FromRequest for Bytes {
162    type Error = BoxError;
163
164    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
165        std::mem::take(req.body_mut()).to_bytes().await
166    }
167}
168
169impl FromRequest for String {
170    type Error = BoxError;
171
172    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
173        let bytes = Bytes::from_request(req).await?;
174        Ok(std::str::from_utf8(&bytes)?.to_owned())
175    }
176}
177
178impl FromRequest for Method {
179    type Error = Infallible;
180
181    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
182        Ok(req.method().clone())
183    }
184}
185
186impl FromRequest for Uri {
187    type Error = Infallible;
188
189    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
190        Ok(req.uri().clone())
191    }
192}
193
194impl FromRequest for Version {
195    type Error = Infallible;
196
197    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
198        Ok(req.version())
199    }
200}
201
202impl FromRequest for HeaderMap {
203    type Error = Infallible;
204
205    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
206        Ok(req.headers().clone())
207    }
208}
209
210impl FromRequest for Extensions {
211    type Error = Infallible;
212
213    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
214        Ok(req.extensions().clone())
215    }
216}
217
218impl FromRequest for RequestParts {
219    type Error = Infallible;
220
221    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
222        Ok(req.parts().clone())
223    }
224}
225
226/// 简化 [`Result`] 提取器的书写。
227pub type ExtractResult<T> = std::result::Result<T, <T as FromRequest>::Error>;