fleetmacros 0.4.0

Macros for fleet
Documentation
/**
* Copyright(2024,)Institute of Software, Chinese Academy of Sciences
* author: yangzichao21@otcaix.iscas.ac.cn
* since: 0.0.0.1
*
**/
use proc_macro::TokenStream;
use heck::ToLowerCamelCase;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, Data, DeriveInput, Fields, LitStr, Type};

pub fn do_fleet_comment(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    let struct_name = &ast.ident;
    // println!("struct_name: {:?}", struct_name);

    let fields = if let Data::Struct(data_struct) = &ast.data {
        if let Fields::Named(fields_named) = &data_struct.fields {
            &fields_named.named
        } else {
            panic!("Commentable can only be derived for structs with named fields");
        }
    } else {
        panic!("Commentable can only be derived for structs");
    };

    let mut direct_inserts = Vec::new();
    let mut nested_inserts = Vec::new();
    // println!("{:?} struct fields: {:?}", struct_name, fields);

    for field in fields.iter() {
        let mut comment_opt = None;
        for attr in field.attrs.iter() {
            if attr.path().is_ident("with_comment") {
                let lit_str: LitStr = attr.parse_args().expect("with_comment 属性需要一个字符串文字");
                comment_opt = Some(lit_str.value());
            }
        }
        let comment = comment_opt.unwrap_or("".to_string());
        // 获取字段的类型作为字符串(这里只做简单比较)
        // println!("full field: {:?}, field.ty: {:?}", quote! { #field }.to_string(), field.ty.to_token_stream().to_string());
        let type_string = field.ty.to_token_stream().to_string().replace(" ", "");
        // println!("type string trimmed: {:?}", type_string);
        let skip_res = [
            "^String$", "^Option<String>$", "^HashMap<String,String>$", "^Vec<String>$", "^HashMap<String,String,>$",
            "^i32$", "^i64$", "^f32$", "Option<DateTime<Local>>", "^Option<i32>$", "^Option<i64>$", "^Option<f32>$",
            "^Option<bool>$",
        ];
        let skip_res = skip_res.iter().map(|x| regex::Regex::new(x).unwrap()).collect::<Vec<_>>();
        let skip_re_match = skip_res.iter().any(|re| re.is_match(&type_string));

        // non-skip-able types
        let vec_re = regex::Regex::new(r"^Vec<(\w+),?>$").unwrap();
        let option_re = regex::Regex::new(r"^Option<(\w+),?>$").unwrap();
        let hash_map_re = regex::Regex::new(r"^HashMap<String,(\w+),?>$").unwrap();
        let field_ident = field.ident.as_ref().unwrap();
        let field_ident_string = field_ident.to_string().to_lower_camel_case().to_string();
        direct_inserts.push(quote! {
            map.insert(#field_ident_string.to_string(), #comment.to_string());
        });
        if skip_re_match {
            continue;
        } else {
            let ty = if hash_map_re.is_match(&type_string) {
                let matched = hash_map_re.captures(&type_string).unwrap().get(1).unwrap();
                let ty: Type = syn::parse_str(matched.as_str()).expect("Failed to parse hash map type");
                ty
            } else if vec_re.is_match(&type_string) {
                let matched = vec_re.captures(&type_string).unwrap().get(1).unwrap();
                let ty: Type = syn::parse_str(matched.as_str()).expect("Failed to parse vec type");
                ty
            } else if option_re.is_match(&type_string) {
                let matched = option_re.captures(&type_string).unwrap().get(1).unwrap();
                let ty: Type = syn::parse_str(matched.as_str()).expect("Failed to parse option type");
                ty
            } else {
                // 对于非 String 类型,假设为嵌套结构体,递归调用其 get_comments 方法
                field.ty.clone()
            };
            if hash_map_re.is_match(&type_string) {
                nested_inserts.push(quote! {
                    for (k, v) in <#ty>::get_comments() {
                        map.insert(format!(r"{}\.[\w-]+\.{}", #field_ident_string, k), v);
                    }
                });
            } else {
                nested_inserts.push(quote! {
                    for (k, v) in <#ty>::get_comments() {
                        map.insert(format!(r"{}\.{}", #field_ident_string, k), v);
                    }
                });
            }
        }
    }
    // 生成最终的 Commentable 实现
    let expanded = quote! {
        impl Commentable for #struct_name {
            fn get_comments() -> std::collections::HashMap<String, String> {
                let mut map: HashMap<String, String> = std::collections::HashMap::new();
                #(#direct_inserts)*
                #(#nested_inserts)*
                map
            }
        }
    };

    TokenStream::from(expanded)
}