tosic_http/traits/
from_request.rs

1//! # FromRequest
2//!
3//! The `FromRequest` trait is used to define how to extract data from the request
4
5#![allow(non_snake_case)]
6
7use crate::body::message_body::MessageBody;
8use crate::body::BoxBody;
9use crate::error::Error;
10use crate::futures::{ok, Ready};
11use crate::request::{HttpPayload, HttpRequest};
12use bytes::Bytes;
13use pin_project_lite::pin_project;
14use std::convert::Infallible;
15use std::{
16    future::Future,
17    marker::PhantomData,
18    pin::Pin,
19    task::{Context, Poll},
20};
21
22#[diagnostic::on_unimplemented(
23    message = "Make sure to implement `FromRequest` if you wish to use `{Self}` as an extractor",
24    label = "Consider not calling it here if this was intended and wrapping it function that may be used here",
25    note = "The FromRequest trait is implemented on all tuples up to size 26 that are filled with types that implement `FromRequest`",
26    note = "If you have more than 26 arguments the trait will not be implemented and you will need to restructure your endpoint"
27)]
28/// # FromRequest
29///
30/// The `FromRequest` trait is used to define how to extract data from the request
31///
32/// Any type that implements `FromRequest` can be used as an extractor and will be extracted from the request automatically in a handler
33///
34pub trait FromRequest: Sized {
35    /// The error that can happen when extracting data
36    type Error: Into<Error>;
37    /// The future that will be used to extract the data
38    type Future: Future<Output = Result<Self, Self::Error>>;
39
40    /// Extracts a value of type `Self` from the request. The request contains the request body at the moment but that might change in the future
41    fn from_request(req: &HttpRequest, payload: &mut HttpPayload) -> Self::Future;
42
43    /// Extracts a value of type `Self` from the request
44    fn extract(req: &HttpRequest) -> Self::Future {
45        Self::from_request(req, &mut HttpPayload::default())
46    }
47}
48
49pin_project! {
50    /// Future for results `FromRequest`
51    pub struct FromRequestResFuture<Fut, E> {
52        #[pin]
53        fut: Fut,
54        _phantom: PhantomData<E>,
55    }
56}
57
58pin_project! {
59    /// Future for option `FromRequest`
60    pub struct FromRequestOptFuture<Fut> {
61        #[pin]
62        fut: Fut,
63    }
64}
65
66pin_project! {
67    #[project = ExtractProj]
68    #[project_replace = ExtractReplaceProj]
69    enum ExtractFuture<Fut, Res> {
70        Future {
71            #[pin]
72            fut: Fut
73        },
74        Done {
75            output: Res,
76        },
77        Empty
78    }
79}
80
81macro_rules! impl_tuple_from_request {
82        ($fut: ident; $($T: ident),*) => {
83            /// FromRequest implementation for tuple
84            #[allow(unused_parens)]
85            impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
86            {
87                type Error = Error;
88                type Future = $fut<$($T),+>;
89
90                fn from_request(req: &HttpRequest, payload: &mut HttpPayload) -> Self::Future {
91                    $fut {
92                        $(
93                            $T: ExtractFuture::Future {
94                                fut: $T::from_request(req, payload),
95                            },
96                        )+
97                    }
98                }
99            }
100
101            pin_project! {
102                /// Future for tuple
103                pub struct $fut<$($T: FromRequest),+> {
104                    $(
105                        #[pin]
106                        $T: ExtractFuture<$T::Future, $T>,
107                    )+
108                }
109            }
110
111            impl<$($T: FromRequest),+> Future for $fut<$($T),+>
112            {
113                type Output = Result<($($T,)+), Error>;
114
115                fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
116                    let mut this = self.project();
117
118                    let mut ready = true;
119                    $(
120                        match this.$T.as_mut().project() {
121                            ExtractProj::Future { fut } => match fut.poll(cx) {
122                                Poll::Ready(Ok(output)) => {
123                                    let _ = this.$T.as_mut().project_replace(ExtractFuture::Done { output });
124                                },
125                                Poll::Ready(Err(err)) => return Poll::Ready(Err(err.into())),
126                                Poll::Pending => ready = false,
127                            },
128                            ExtractProj::Done { .. } => {},
129                            ExtractProj::Empty => unreachable!("FromRequest polled after finished"),
130                        }
131                    )+
132
133                    if ready {
134                        Poll::Ready(Ok(
135                            ($(
136                                match this.$T.project_replace(ExtractFuture::Empty) {
137                                    ExtractReplaceProj::Done { output } => output,
138                                    _ => unreachable!("FromRequest polled after finished"),
139                                },
140                            )+)
141                        ))
142                    } else {
143                        Poll::Pending
144                    }
145                }
146            }
147        };
148    }
149
150impl_tuple_from_request!(TupleFromRequestFuture1; A);
151impl_tuple_from_request!(TupleFromRequestFuture2; A, B);
152impl_tuple_from_request!(TupleFromRequestFuture3; A, B, C);
153impl_tuple_from_request!(TupleFromRequestFuture4; A, B, C, D);
154impl_tuple_from_request!(TupleFromRequestFuture5; A, B, C, D, E);
155impl_tuple_from_request!(TupleFromRequestFuture6; A, B, C, D, E, F);
156impl_tuple_from_request!(TupleFromRequestFuture7; A, B, C, D, E, F, G);
157impl_tuple_from_request!(TupleFromRequestFuture8; A, B, C, D, E, F, G, H);
158impl_tuple_from_request!(TupleFromRequestFuture9; A, B, C, D, E, F, G, H, I);
159impl_tuple_from_request!(TupleFromRequestFuture10; A, B, C, D, E, F, G, H, I, J);
160impl_tuple_from_request!(TupleFromRequestFuture11; A, B, C, D, E, F, G, H, I, J, K);
161impl_tuple_from_request!(TupleFromRequestFuture12; A, B, C, D, E, F, G, H, I, J, K, L);
162impl_tuple_from_request!(TupleFromRequestFuture13; A, B, C, D, E, F, G, H, I, J, K, L, M);
163impl_tuple_from_request!(TupleFromRequestFuture14; A, B, C, D, E, F, G, H, I, J, K, L, M, N);
164impl_tuple_from_request!(TupleFromRequestFuture15; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
165impl_tuple_from_request!(TupleFromRequestFuture16; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
166impl_tuple_from_request!(TupleFromRequestFuture17; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
167impl_tuple_from_request!(TupleFromRequestFuture18; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
168impl_tuple_from_request!(TupleFromRequestFuture19; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
169impl_tuple_from_request!(TupleFromRequestFuture20; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
170impl_tuple_from_request!(TupleFromRequestFuture21; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
171impl_tuple_from_request!(TupleFromRequestFuture22; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
172impl_tuple_from_request!(TupleFromRequestFuture23; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
173impl_tuple_from_request!(TupleFromRequestFuture24; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
174impl_tuple_from_request!(TupleFromRequestFuture25; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
175impl_tuple_from_request!(TupleFromRequestFuture26; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
176
177impl FromRequest for () {
178    type Error = Infallible;
179    type Future = Ready<Result<Self, Self::Error>>;
180
181    fn from_request(_: &HttpRequest, _: &mut HttpPayload) -> Self::Future {
182        ok(())
183    }
184}
185
186impl FromRequest for Bytes {
187    type Error = Infallible;
188    type Future = Ready<Result<Self, Self::Error>>;
189
190    fn from_request(_: &HttpRequest, payload: &mut HttpPayload) -> Self::Future {
191        ok(<BoxBody as Clone>::clone(payload)
192            .boxed()
193            .try_into_bytes()
194            .expect("Unable to read body"))
195    }
196}