Skip to main content

rust_wechat_codegen/
lib.rs

1use proc_macro2::{Ident, TokenStream};
2use quote::{format_ident, quote};
3use syn::{parse_macro_input, DeriveInput, LitStr, Meta};
4
5#[proc_macro_derive(ServerResponse, attributes(sr))]
6pub fn server_response(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
7
8    let ast = parse_macro_input!(input as DeriveInput);
9    let struct_name = &ast.ident;
10    let response_struct_name = format_ident!("{}Response", struct_name);
11    
12    let mut flatten: TokenStream = quote! {};
13    let mut data_name: Ident = format_ident!("data");
14    ast.attrs.iter().for_each(|a| {
15        if a.path().is_ident("sr") {
16            match &a.meta {
17                Meta::List(meta) => {
18                    meta.parse_nested_meta(|nest| {
19                        if nest.path.is_ident("flatten") {
20                            flatten = quote! {
21                                #[serde(flatten)]
22                            }
23                        } else if nest.path.is_ident("name") {
24                            let value = nest.value()?;
25                            let s: LitStr = value.parse()?;
26                            data_name = format_ident!("{}", s.value());
27                        }
28                        Ok(())
29                    }).unwrap()
30                },
31                _ => {}
32            }
33        }
34    });
35    
36    let new_struct = quote! {
37        #[derive(Debug, serde::Serialize, serde::Deserialize)]
38        pub struct #response_struct_name {
39            #flatten
40            pub #data_name: #struct_name,
41            pub errcode: i32,
42            pub errmsg: Option<String>,
43        }
44    };
45
46    let method = quote! {
47        impl #response_struct_name {
48            pub fn is_ok(&self) -> bool {
49                self.errcode == 0
50            }
51
52            pub fn #data_name(self) -> Result<#struct_name, rust_wechat_core::ServerError> {
53                if self.is_ok() {
54                    Ok(self.#data_name)
55                } else {
56                    let err = rust_wechat_core::ServerError::default().code(self.errcode);
57                    if let Some(msg) = self.errmsg {
58                        Err(err.message(msg))
59                    } else {
60                        Err(err)
61                    }
62                }
63            }
64            
65            pub fn ignore(self) -> Result<(), rust_wechat_core::ServerError> {
66                if self.is_ok() {
67                    Ok(())
68                } else {
69                    let err = rust_wechat_core::ServerError::default().code(self.errcode);
70                    if let Some(msg) = self.errmsg {
71                        Err(err.message(msg))
72                    } else {
73                        Err(err)
74                    }
75                }
76            }
77        }
78    };
79
80    let expanded = quote! {
81        #new_struct
82        #method
83    };
84
85    proc_macro::TokenStream::from(expanded)
86}