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