axum_core/extract/
tuple.rs

1use super::{FromRequest, FromRequestParts, Request};
2use crate::response::{IntoResponse, Response};
3use async_trait::async_trait;
4use http::request::Parts;
5use std::convert::Infallible;
6
7#[async_trait]
8impl<S> FromRequestParts<S> for ()
9where
10    S: Send + Sync,
11{
12    type Rejection = Infallible;
13
14    async fn from_request_parts(_: &mut Parts, _: &S) -> Result<(), Self::Rejection> {
15        Ok(())
16    }
17}
18
19macro_rules! impl_from_request {
20    (
21        [$($ty:ident),*], $last:ident
22    ) => {
23        #[async_trait]
24        #[allow(non_snake_case, unused_mut, unused_variables)]
25        impl<S, $($ty,)* $last> FromRequestParts<S> for ($($ty,)* $last,)
26        where
27            $( $ty: FromRequestParts<S> + Send, )*
28            $last: FromRequestParts<S> + Send,
29            S: Send + Sync,
30        {
31            type Rejection = Response;
32
33            async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
34                $(
35                    let $ty = $ty::from_request_parts(parts, state)
36                        .await
37                        .map_err(|err| err.into_response())?;
38                )*
39                let $last = $last::from_request_parts(parts, state)
40                    .await
41                    .map_err(|err| err.into_response())?;
42
43                Ok(($($ty,)* $last,))
44            }
45        }
46
47        // This impl must not be generic over M, otherwise it would conflict with the blanket
48        // implementation of `FromRequest<S, Mut>` for `T: FromRequestParts<S>`.
49        #[async_trait]
50        #[allow(non_snake_case, unused_mut, unused_variables)]
51        impl<S, $($ty,)* $last> FromRequest<S> for ($($ty,)* $last,)
52        where
53            $( $ty: FromRequestParts<S> + Send, )*
54            $last: FromRequest<S> + Send,
55            S: Send + Sync,
56        {
57            type Rejection = Response;
58
59            async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
60                let (mut parts, body) = req.into_parts();
61
62                $(
63                    let $ty = $ty::from_request_parts(&mut parts, state).await.map_err(|err| err.into_response())?;
64                )*
65
66                let req = Request::from_parts(parts, body);
67
68                let $last = $last::from_request(req, state).await.map_err(|err| err.into_response())?;
69
70                Ok(($($ty,)* $last,))
71            }
72        }
73    };
74}
75
76all_the_tuples!(impl_from_request);
77
78#[cfg(test)]
79mod tests {
80    use bytes::Bytes;
81    use http::Method;
82
83    use crate::extract::{FromRequest, FromRequestParts};
84
85    fn assert_from_request<M, T>()
86    where
87        T: FromRequest<(), M>,
88    {
89    }
90
91    fn assert_from_request_parts<T: FromRequestParts<()>>() {}
92
93    #[test]
94    fn unit() {
95        assert_from_request_parts::<()>();
96        assert_from_request::<_, ()>();
97    }
98
99    #[test]
100    fn tuple_of_one() {
101        assert_from_request_parts::<(Method,)>();
102        assert_from_request::<_, (Method,)>();
103        assert_from_request::<_, (Bytes,)>();
104    }
105
106    #[test]
107    fn tuple_of_two() {
108        assert_from_request_parts::<((), ())>();
109        assert_from_request::<_, ((), ())>();
110        assert_from_request::<_, (Method, Bytes)>();
111    }
112
113    #[test]
114    fn nested_tuple() {
115        assert_from_request_parts::<(((Method,),),)>();
116        assert_from_request::<_, ((((Bytes,),),),)>();
117    }
118}