axum_core/extract/
tuple.rs

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