1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::collections::HashMap;

use crate::request::ApiParamExtractor;
use crate::{
    request::ApiRequest,
    response::{ApiResponse, ApiResultExtractor},
};
use std::future::Future;

use super::ty::ApiModel;

pub trait ApiAsyncHandler<T> {
    fn get_request(models: &mut HashMap<String, Option<ApiModel>>) -> ApiRequest;

    fn get_response(models: &mut HashMap<String, Option<ApiModel>>) -> ApiResponse;
}

impl<F, Fut, Res> ApiAsyncHandler<()> for F
where
    F: FnOnce() -> Fut + Clone + Send + 'static,
    Fut: Future<Output = Res> + Send,
    Res: ApiResultExtractor,
{
    fn get_request(_models: &mut HashMap<String, Option<ApiModel>>) -> ApiRequest {
        ApiRequest::default()
    }

    fn get_response(models: &mut HashMap<String, Option<ApiModel>>) -> ApiResponse {
        Res::api_response(models)
    }
}

macro_rules! impl_async_handler {
    (
        [$($ty:ident),*]
    ) => {
        impl<F, Fut, Res, $($ty,)*> ApiAsyncHandler<($($ty,)*)> for F
        where
            F: FnOnce($($ty,)*) -> Fut + Clone + Send + 'static,
            Fut: Future<Output = Res> + Send,
            Res: ApiResultExtractor,
            $( $ty: ApiParamExtractor, )*
        {
            fn get_request(models: &mut HashMap<String, Option<ApiModel>>) -> ApiRequest {
                let mut request = ApiRequest::default();
                $(
                    let param = $ty :: api_param_kind(models);
                    request.add_param(param);
                    let errors = $ty :: api_error();
                    request.add_error(errors);
                )*

                request
            }

            fn get_response(models: &mut HashMap<String, Option<ApiModel>>) -> ApiResponse {
                Res::api_response(models)
            }
        }
    };
}

macro_rules! all_the_tuples {
    ($name:ident) => {
        $name!([T1]);
        $name!([T1, T2]);
        $name!([T1, T2, T3]);
        $name!([T1, T2, T3, T4]);
        $name!([T1, T2, T3, T4, T5]);
        $name!([T1, T2, T3, T4, T5, T6]);
        $name!([T1, T2, T3, T4, T5, T6, T7]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]);
        $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]);
    };
}

all_the_tuples!(impl_async_handler);