yadro_codegen/
lib.rs

1use proc_macro::TokenStream;
2
3#[proc_macro_attribute]
4pub fn handler(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
5    let mut components = Vec::new();
6    let mut next_function_name = false;
7    let mut filtered: Vec<proc_macro::TokenTree> = Vec::new();
8    for t in tokens {
9        match t {
10            proc_macro::TokenTree::Group(g) => {
11                if filtered.len() == 1 {
12                    for group in g.stream() {
13                        match group {
14                            proc_macro::TokenTree::Ident(token) => match token.to_string().as_str() {
15                                "Request" => components.push("req"),
16                                "Response" => components.push("res"),
17                                _ => {},
18                            },
19                            _ => {},
20                        }
21                    }
22                }
23                filtered.push(g.into());
24            },
25            proc_macro::TokenTree::Ident(i) => {
26                if next_function_name {
27                    filtered.push(i.into());
28                    next_function_name = false;
29                    continue;
30                }
31                if i.to_string().eq("fn") {
32                    next_function_name = true;
33                }
34            }
35            _ => {}
36        }
37    }
38
39    format!(r#"
40    #[allow(non_camel_case_types)]
41    struct {name};
42    #[allow(non_camel_case_types)]
43    impl ::core::fmt::Debug for {name} {{
44        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {{
45            ::core::fmt::Formatter::write_str(f, "{name}")
46        }}
47    }}
48    impl {name} {{
49        async fn {name}{args} {{
50            {body}
51        }}
52    }}
53    impl yadro::router::Handler for {name} {{
54        #[must_use = "handle future must be used"]
55        #[allow(clippy::type_complexity,clippy::type_repetition_in_bounds)]
56        fn handle<'life0,'life1,'life2,'async_trait>(
57            &'life0 self,req: &'life1 mut yadro::http::Request,res: &'life2 mut yadro::http::Response
58        ) -> ::core::pin::Pin<Box<dyn ::core::future::Future<Output = ()> + ::core::marker::Send+'async_trait> >
59        where 'life0:'async_trait,'life1:'async_trait,'life2:'async_trait,Self:'async_trait {{
60            Box::pin(async move {{
61                let __self = self;
62                let () = {{ Self::{name}({}).await }};
63            }})
64        }}
65    }}"#,
66    components.join(","),
67    name = &filtered[0],
68    args = &filtered[1],
69    body = &filtered[2],
70    ).parse().unwrap()
71}