async_variadic/
lib.rs

1use async_trait::async_trait;
2use std::future::Future;
3
4#[async_trait]
5pub trait AsyncFn<Args, Output> {
6    async fn call(&self, args: Args) -> Output;
7}
8
9/// Generates a [`AsyncFn`] trait impl for N-ary functions where N is specified with a
10/// space separated type parameters.
11///
12/// # Examples
13/// ```ignore
14/// ary! {}        // implements Handler for types: fn() -> R
15/// ary! { A B C } // implements Handler for types: fn(A, B, C) -> R
16/// ```
17macro_rules! ary ({ $($param:ident)* } => {
18    #[async_trait::async_trait]
19    impl<Func, Fut, $($param:Send + 'static,)*> AsyncFn<($($param,)*), Fut::Output> for Func
20    where
21        Func: Send + Sync + Fn($($param),*) -> Fut,
22        Fut: Future + Send
23    {
24        #[inline]
25        #[allow(non_snake_case)]
26        async fn call(&self, ($($param,)*): ($($param,)*)) -> Fut::Output {
27            (self)($($param,)*).await
28        }
29    }
30});
31
32ary! {}
33ary! { A }
34ary! { A B }
35ary! { A B C }
36ary! { A B C D }
37ary! { A B C D E }
38ary! { A B C D E F }
39ary! { A B C D E F G }
40ary! { A B C D E F G H }
41ary! { A B C D E F G H I }
42ary! { A B C D E F G H I J }
43ary! { A B C D E F G H I J K }
44ary! { A B C D E F G H I J K L }
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    struct Request {}
51    struct Response {}
52    struct Body {}
53
54    impl From<Request> for (Request,) {
55        fn from(req: Request) -> Self {
56            (req,)
57        }
58    }
59
60    impl From<Request> for (Body,) {
61        fn from(_req: Request) -> Self {
62            (Body {},)
63        }
64    }
65
66    impl From<&'static str> for Response {
67        fn from(_s: &'static str) -> Self {
68            Response {}
69        }
70    }
71
72    fn assert_impl_output<T: From<Request>, O: Into<Response>>(_: impl AsyncFn<T, O>) {}
73
74    #[test]
75    fn test_trait_bounds() {
76        async fn with_request_resp(_req: Request) -> &'static str {
77            "hello"
78        }
79
80        async fn with_body_resp(_body: Body) -> &'static str {
81            "hello"
82        }
83
84        assert_impl_output(with_request_resp);
85        assert_impl_output(with_body_resp);
86    }
87
88    fn assert_impl_fn<T, O>(_: impl AsyncFn<T, O>) {}
89
90    #[test]
91    fn test_args() {
92        async fn min() {}
93        async fn min_output() -> i32 {
94            4
95        }
96        async fn with_req(_req: String) -> &'static str {
97            "foo"
98        }
99        async fn with_refs(_r: &str, _b: &[u8]) -> &'static str {
100            "asdf"
101        }
102        struct Test {
103            _a: bool,
104            b: u8,
105        }
106
107        impl Test {
108            async fn bleh(&self) -> &u8 {
109                &self.b
110            }
111        }
112
113        #[rustfmt::skip]
114        #[allow(clippy::too_many_arguments, clippy::just_underscores_and_digits)]
115        async fn max(
116            _01: (), _02: (), _03: (), _04: (), _05: (), _06: (),
117            _07: (), _08: (), _09: (), _10: (), _11: (), _12: (),
118        ) {}
119
120        assert_impl_fn(min);
121        assert_impl_fn(with_req);
122        assert_impl_fn(min_output);
123        assert_impl_fn(max);
124        assert_impl_fn(with_refs);
125        assert_impl_fn(Test::bleh);
126    }
127}