use proc_macro::TokenStream; use quote::quote; use syn::Data; fn impl_serialize_ex(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; let fields = match ast.data { Data::Struct(ref data) => &data.fields, _ => panic!("CustomSerialize 只能用于结构体!"), }; let field_len = fields.len(); // 迭代器,为每一个字段实现serialize_field let serialize_fields = match fields { syn::Fields::Named(ref fields) => { fields.named.iter().map(|f| { let name = &f.ident; let ty = &f.ty; let mut child_token_stream = proc_macro2::TokenStream::new(); // 如果字段是数组类型 if let syn::Type::Array(ref array) = ty { let len = &array.len; let child_ty = &array.elem; // 类型所占字节 child_token_stream = quote! { children = Some(Vec::new()); let field_size = std::mem::size_of::<#child_ty>(); for i in 0..#len { let child_value = serde_json::json!({ "name": format!("{}[{}]", stringify!(#name), i), "value": format!("0x{:0width$X}",self.#name[i], width=field_size), "field_type": stringify!(#child_ty), "size": field_size, "offset": (&self.#name[i] as *const _ as usize) - (self as *const _ as usize), "children": null }); children.as_mut().unwrap().push(child_value); } }; }else{ child_token_stream = quote! { let field_size = std::mem::size_of::<#ty>(); value = serde_json::json!(format!("0x{:0width$X}",&self.#name, width=field_size)); }; } quote! { let mut value = serde_json::Value::Null; let mut children: Option> = None; #child_token_stream let json_value = serde_json::json!({ "name": stringify!(#name), "value": value, "field_type": stringify!(#ty), "size": std::mem::size_of::<#ty>(), "offset": (&self.#name as *const _ as usize) - (self as *const _ as usize), "children": &children }); state.serialize_field(stringify!(#name), &json_value)?; } }) } _ => panic!("CustomSerialize 只能用于结构体!"), }; let gen = quote! { impl serde::Serialize for #name { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { let mut state = serializer.serialize_struct(stringify!(#name), #field_len)?; #(#serialize_fields)* state.end() } } }; gen.into() } // 拓展Serialize #[proc_macro_derive(SerializeEX)] pub fn serialize_ex(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); impl_serialize_ex(&ast) }