coaxial/
handler.rs

1use axum::extract::{FromRequest, FromRequestParts, Request};
2use std::{future::Future, pin::Pin};
3
4use crate::{context::Context, CoaxialResponse};
5
6pub trait CoaxialHandler<T, S>: Clone + Send + Sized + 'static {
7    type Future: Future<Output = CoaxialResponse<S>> + Send + 'static;
8    fn call(self, req: Request, state: S) -> Self::Future;
9}
10
11// implement handler for the basic func that takes only the context
12impl<F, Fut, S> CoaxialHandler<((),), S> for F
13where
14    F: FnOnce(Context<S>) -> Fut + Clone + Send + 'static,
15    Fut: Future<Output = CoaxialResponse<S>> + Send,
16    S: Send + Sync + 'static,
17{
18    type Future = Pin<Box<dyn Future<Output = CoaxialResponse<S>> + Send>>;
19
20    fn call(self, _req: Request, _state: S) -> Self::Future {
21        Box::pin(async move { self(Context::default()).await })
22    }
23}
24
25macro_rules! impl_handler {
26    (
27        [$($ty:ident),*], $last:ident
28    ) => {
29        #[allow(non_snake_case, unused_mut)]
30        impl<F, Fut, S, M, $($ty,)* $last> CoaxialHandler<((M, $($ty,)* $last,),), S> for F
31        where
32            F: FnOnce(Context<S>, $($ty,)* $last,) -> Fut + Clone + Send + 'static,
33            Fut: Future<Output = CoaxialResponse<S>> + Send,
34            S: Send + Sync + 'static,
35            $( $ty: FromRequestParts<S> + Send, )*
36            $last: FromRequest<S, M> + Send,
37        {
38            type Future = Pin<Box<dyn Future<Output = CoaxialResponse<S>> + Send>>;
39
40            fn call(self, req: Request, state: S) -> Self::Future {
41                Box::pin(async move {
42                    let (mut parts, body) = req.into_parts();
43                    let state = &state;
44
45                    $(
46                        let $ty = match $ty::from_request_parts(&mut parts, state).await {
47                            Ok(value) => value,
48                            Err(_rejection) => todo!("rejections aren't handled yet"),
49                        };
50                    )*
51
52                    let req = Request::from_parts(parts, body);
53
54                    let $last = match $last::from_request(req, state).await {
55                        Ok(value) => value,
56                        Err(_rejection) => todo!("rejections aren't handled yet"),
57                    };
58
59                    self(Context::default(), $($ty,)* $last,).await
60                })
61            }
62        }
63    };
64}
65
66#[rustfmt::skip]
67macro_rules! all_the_tuples {
68    ($name:ident) => {
69        $name!([], T1);
70        $name!([T1], T2);
71        $name!([T1, T2], T3);
72        $name!([T1, T2, T3], T4);
73        $name!([T1, T2, T3, T4], T5);
74        $name!([T1, T2, T3, T4, T5], T6);
75        $name!([T1, T2, T3, T4, T5, T6], T7);
76        $name!([T1, T2, T3, T4, T5, T6, T7], T8);
77        $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
78        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
79        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
80        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
81        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
82        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
83        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
84        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
85    };
86}
87
88all_the_tuples!(impl_handler);