rust-wechat-codegen 0.1.0

wechat api codegen
Documentation
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use syn::{parse_macro_input, DeriveInput, LitStr, Meta};

#[proc_macro_derive(ServerResponse, attributes(sr))]
pub fn server_response(input: proc_macro::TokenStream) -> proc_macro::TokenStream {

    let ast = parse_macro_input!(input as DeriveInput);
    let struct_name = &ast.ident;
    let response_struct_name = format_ident!("{}Response", struct_name);
    
    let mut flatten: TokenStream = quote! {};
    let mut data_name: Ident = format_ident!("data");
    ast.attrs.iter().for_each(|a| {
        if a.path().is_ident("sr") {
            match &a.meta {
                Meta::List(meta) => {
                    meta.parse_nested_meta(|nest| {
                        if nest.path.is_ident("flatten") {
                            flatten = quote! {
                                #[serde(flatten)]
                            }
                        } else if nest.path.is_ident("name") {
                            let value = nest.value()?;
                            let s: LitStr = value.parse()?;
                            data_name = format_ident!("{}", s.value());
                        }
                        Ok(())
                    }).unwrap()
                },
                _ => {}
            }
        }
    });
    
    let new_struct = quote! {
        #[derive(Debug, serde::Serialize, serde::Deserialize)]
        pub struct #response_struct_name {
            #flatten
            pub #data_name: #struct_name,
            pub errcode: i32,
            pub errmsg: Option<String>,
        }
    };

    let method = quote! {
        impl #response_struct_name {
            pub fn is_ok(&self) -> bool {
                self.errcode == 0
            }

            pub fn #data_name(self) -> Result<#struct_name, rust_wechat_core::ServerError> {
                if self.is_ok() {
                    Ok(self.#data_name)
                } else {
                    let err = rust_wechat_core::ServerError::default().code(self.errcode);
                    if let Some(msg) = self.errmsg {
                        Err(err.message(msg))
                    } else {
                        Err(err)
                    }
                }
            }
            
            pub fn ignore(self) -> Result<(), rust_wechat_core::ServerError> {
                if self.is_ok() {
                    Ok(())
                } else {
                    let err = rust_wechat_core::ServerError::default().code(self.errcode);
                    if let Some(msg) = self.errmsg {
                        Err(err.message(msg))
                    } else {
                        Err(err)
                    }
                }
            }
        }
    };

    let expanded = quote! {
        #new_struct
        #method
    };

    proc_macro::TokenStream::from(expanded)
}