Skip to main content

alux_http_poem/
input.rs

1use core::future::Future;
2use core::marker::PhantomData;
3use poem::Request;
4use poem::web::headers::Header;
5use poem::web::{FromRequest, Json, Path, Query, RequestBody, TypedHeader};
6use serde::de::DeserializeOwned;
7
8/// Marks a value extracted from the request path by Poem.
9pub struct PoemPathInput<Input>(PhantomData<Input>);
10/// Marks a value extracted from the query string by Poem.
11pub struct PoemQueryInput<Input>(PhantomData<Input>);
12/// Marks a JSON value extracted from the request body by Poem.
13pub struct PoemBodyInput<Input>(PhantomData<Input>);
14/// Marks a typed value extracted from a request header by Poem.
15pub struct PoemHeaderInput<Input>(PhantomData<Input>);
16/// Marks a value extracted through Poem's general request extractor.
17pub struct PoemRequestInput<Input>(PhantomData<Input>);
18
19pub(crate) trait PoemInputAlg<Output> {
20    fn extract(request: &Request, body: &mut RequestBody) -> impl Future<Output = poem::Result<Output>> + Send;
21}
22
23macro_rules! poem_input {
24    ($marker:ident, $extractor:ident) => {
25        impl<Input> PoemInputAlg<Input> for $marker<Input>
26        where
27            Input: DeserializeOwned + Send,
28        {
29            async fn extract(request: &Request, body: &mut RequestBody) -> poem::Result<Input> {
30                Ok($extractor::<Input>::from_request(request, body).await?.0)
31            }
32        }
33    };
34}
35
36poem_input!(PoemPathInput, Path);
37poem_input!(PoemQueryInput, Query);
38poem_input!(PoemBodyInput, Json);
39
40impl<Input> PoemInputAlg<Input> for PoemHeaderInput<Input>
41where
42    Input: Header + Send,
43{
44    async fn extract(request: &Request, body: &mut RequestBody) -> poem::Result<Input> {
45        Ok(TypedHeader::<Input>::from_request(request, body).await?.0)
46    }
47}
48
49impl<Input> PoemInputAlg<Input> for PoemRequestInput<Input>
50where
51    Input: for<'a> FromRequest<'a> + Send,
52{
53    fn extract(request: &Request, body: &mut RequestBody) -> impl Future<Output = poem::Result<Input>> + Send {
54        Input::from_request(request, body)
55    }
56}
57
58pub(crate) trait PoemInputsAlg<Outputs> {
59    fn extract(request: &Request, body: &mut RequestBody) -> impl Future<Output = poem::Result<Outputs>> + Send;
60}
61
62impl PoemInputsAlg<()> for () {
63    async fn extract(_request: &Request, _body: &mut RequestBody) -> poem::Result<()> {
64        Ok(())
65    }
66}
67
68macro_rules! poem_inputs {
69    ($($input:ident => $output:ident),+ $(,)?) => {
70        impl<$($input, $output),+> PoemInputsAlg<($($output,)+)> for ($($input,)+)
71        where
72            $($input: PoemInputAlg<$output>, $output: Send,)+
73        {
74            async fn extract(request: &Request, body: &mut RequestBody) -> poem::Result<($($output,)+)> {
75                Ok(($($input::extract(request, body).await?,)+))
76            }
77        }
78    };
79}
80
81poem_inputs!(I1 => O1);
82poem_inputs!(I1 => O1, I2 => O2);
83poem_inputs!(I1 => O1, I2 => O2, I3 => O3);
84poem_inputs!(I1 => O1, I2 => O2, I3 => O3, I4 => O4);
85poem_inputs!(I1 => O1, I2 => O2, I3 => O3, I4 => O4, I5 => O5);
86poem_inputs!(I1 => O1, I2 => O2, I3 => O3, I4 => O4, I5 => O5, I6 => O6);
87poem_inputs!(I1 => O1, I2 => O2, I3 => O3, I4 => O4, I5 => O5, I6 => O6, I7 => O7);
88poem_inputs!(I1 => O1, I2 => O2, I3 => O3, I4 => O4, I5 => O5, I6 => O6, I7 => O7, I8 => O8);