actix_type_handler/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Ident, Item, ReturnType, Pat};
4
5#[proc_macro_attribute]
6pub fn type_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
7 let ast = parse_macro_input!(item as Item);
8
9 let fn_item = if let Item::Fn(item) = ast {
10 item
11 } else {
12 panic!("The attribute should be applied to functions.");
13 };
14
15 let fn_name = &fn_item.sig.ident;
16 let api_fn_name = Ident::new(&format!("{}_api", fn_name), fn_name.span());
17
18 let args = &fn_item.sig.inputs;
19
20 let _return_type = match &fn_item.sig.output {
21 ReturnType::Type(_, ty) => match &**ty {
22 syn::Type::Path(path) => &path.path.segments[0].ident,
23 _ => panic!("The function must return a Result."),
24 },
25 _ => panic!("The function must return a Result."),
26 };
27
28 let mut _request_type = None;
29 let mut new_args = Vec::new();
30 let mut call_args = Vec::new();
31
32 for arg in args.iter() {
33 if let syn::FnArg::Typed(pat_type) = arg {
34 let arg_name = pat_type.pat.clone();
35 let arg_type = &*pat_type.ty;
36 if let Pat::Ident(ref pat_ident) = *arg_name {
37 if pat_ident.ident == "query" {
38 _request_type = Some(arg_type);
39 new_args.push(quote! {actix_web::web::Query(query): actix_web::web::Query<#_request_type>});
40 call_args.push(quote! {query});
41 } else if pat_ident.ident == "body" {
42 _request_type = Some(arg_type);
43 new_args.push(quote! {body: actix_web::web::Json<#_request_type>});
44 call_args.push(quote! {body.into_inner()});
45
46 } else if pat_ident.ident == "path" {
47 _request_type = Some(arg_type);
48 new_args.push(quote! {path: actix_web::web::Path<#_request_type>});
49 call_args.push(quote! {path.into_inner()});
50 } else{
51 new_args.push(quote! {#arg_name: #arg_type});
52 call_args.push(quote! {#arg_name});
53 }
54 }
55 }
56 }
57
58 let output = quote! {
59 #fn_item
60
61 pub async fn #api_fn_name(#(#new_args),*) -> impl actix_web::Responder {
62 match #fn_name(#(#call_args),*).await {
63 Ok(d) => {
64 let res = ApiResponse { message: "".to_string(), data: d };
65 actix_web::HttpResponse::Ok().json(res)
66 }
67 Err(e) => { e.error_response() }
68 }
69 }
70 };
71
72 output.into()
73}
74