feat: 写了一个派生宏,来简单的序列化一个结构体

This commit is contained in:
381848900@qq.com 2024-12-09 16:26:29 +08:00
parent f837e7cdaf
commit 142a8cd3eb
8 changed files with 199 additions and 260 deletions

11
src-tauri/Cargo.lock generated
View File

@ -2409,6 +2409,16 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
[[package]]
name = "pe_serialize_proc_macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.90",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -3764,6 +3774,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"memmap", "memmap",
"pe_serialize_proc_macro",
"serde", "serde",
"serde_json", "serde_json",
"tauri", "tauri",

View File

@ -1,9 +1,9 @@
[package] [package]
authors = ["you"]
description = "A Tauri App"
edition = "2021"
name = "test-tauri" name = "test-tauri"
version = "0.1.0" version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -11,19 +11,19 @@ edition = "2021"
# The `_lib` suffix may seem redundant but it is necessary # The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name. # to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "test_tauri_lib"
crate-type = ["staticlib", "cdylib", "rlib"] crate-type = ["staticlib", "cdylib", "rlib"]
name = "test_tauri_lib"
[build-dependencies] [build-dependencies]
tauri-build = { version = "2", features = [] } tauri-build = {version = "2", features = [] }
[dependencies] [dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2.0.4"
bitflags = "2.6.0" bitflags = "2.6.0"
memmap = "0.7.0" memmap = "0.7.0"
pe_serialize_proc_macro = {path = "./pe_serialize_proc_macro"}
serde = {version = "1", features = ["derive"] }
serde_json = "1"
tauri = {version = "2", features = [] }
tauri-plugin-dialog = "2" tauri-plugin-dialog = "2"
tauri-plugin-shell = "2"
thiserror = "2.0.4"

View File

@ -0,0 +1 @@
/target/

View File

@ -0,0 +1,68 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "pe_serialize_proc_macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"serde",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"

View File

@ -0,0 +1,16 @@
[lib]
proc-macro = true
[package]
name = "pe_serialize_proc_macro"
version = "0.1.0"
edition = "2021"
[dependencies]
proc-macro2 = "1.0.92"
quote = "1.0.37"
serde = "1.0.215"
syn = "2.0.90"
[serde.features]
default = ["derive"]

View File

@ -0,0 +1,85 @@
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<Vec<serde_json::Value>> = 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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)
}

View File

@ -3,8 +3,8 @@ use crate::{
pe_parse::{header::ImageDosHeader, pe::PE}, pe_parse::{header::ImageDosHeader, pe::PE},
services::{self, GLOBAL_FILE_DATA}, services::{self, GLOBAL_FILE_DATA},
}; };
use serde::{ser::SerializeStruct, Serialize, Serializer}; use serde::Serialize;
use serde_json::Value;
#[tauri::command] #[tauri::command]
pub fn greet(name: &str) -> String { pub fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name) format!("Hello, {}! You've been greeted from Rust!", name)
@ -99,250 +99,6 @@ pub struct ResponseDOSHeaderData {
children: Option<Vec<ResponseDOSHeaderData>>, children: Option<Vec<ResponseDOSHeaderData>>,
} }
fn serialize_field<S>(
state: &mut S,
name: &'static str,
value: Option<String>,
size: usize,
field_type: &str,
offset: usize,
children: Option<Vec<ResponseDOSHeaderData>>,
) -> Result<(), S::Error>
where
S: serde::ser::SerializeStruct,
{
state.serialize_field(
name,
&ResponseDOSHeaderData {
name: name.to_string(),
value,
size,
field_type: field_type.to_string(),
offset,
children,
},
)
}
impl Serialize for ImageDosHeader {
fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("ResponseDOSHeaderData", 19)?;
// 序列化每个字段
serialize_field(
&mut state,
"e_magic",
Some(format!("0x{:04X}", self.e_magic)),
std::mem::size_of_val(&self.e_magic),
"u16",
offset_of!(self, e_magic),
None,
)?;
serialize_field(
&mut state,
"e_cblp",
Some(format!("0x{:04X}", self.e_cblp)),
std::mem::size_of_val(&self.e_cblp),
"u16",
offset_of!(self, e_cblp),
None,
)?;
serialize_field(
&mut state,
"e_cp",
Some(format!("0x{:04X}", self.e_cp)),
std::mem::size_of_val(&self.e_cp),
"u16",
offset_of!(self, e_cp),
None,
)?;
serialize_field(
&mut state,
"e_crlc",
Some(format!("0x{:04X}", self.e_crlc)),
std::mem::size_of_val(&self.e_crlc),
"u16",
offset_of!(self, e_crlc),
None,
)?;
serialize_field(
&mut state,
"e_cparhdr",
Some(format!("0x{:04X}", self.e_cparhdr)),
std::mem::size_of_val(&self.e_cparhdr),
"u16",
offset_of!(self, e_cparhdr),
None,
)?;
serialize_field(
&mut state,
"e_minalloc",
Some(format!("0x{:04X}", self.e_minalloc)),
std::mem::size_of_val(&self.e_minalloc),
"u16",
offset_of!(self, e_minalloc),
None,
)?;
serialize_field(
&mut state,
"e_maxalloc",
Some(format!("0x{:04X}", self.e_maxalloc)),
std::mem::size_of_val(&self.e_maxalloc),
"u16",
offset_of!(self, e_maxalloc),
None,
)?;
serialize_field(
&mut state,
"e_ss",
Some(format!("0x{:04X}", self.e_ss)),
std::mem::size_of_val(&self.e_ss),
"u16",
offset_of!(self, e_ss),
None,
)?;
serialize_field(
&mut state,
"e_sp",
Some(format!("0x{:04X}", self.e_sp)),
std::mem::size_of_val(&self.e_sp),
"u16",
offset_of!(self, e_sp),
None,
)?;
serialize_field(
&mut state,
"e_csum",
Some(format!("0x{:04X}", self.e_csum)),
std::mem::size_of_val(&self.e_csum),
"u16",
offset_of!(self, e_csum),
None,
)?;
serialize_field(
&mut state,
"e_ip",
Some(format!("0x{:04X}", self.e_ip)),
std::mem::size_of_val(&self.e_ip),
"u16",
offset_of!(self, e_ip),
None,
)?;
serialize_field(
&mut state,
"e_cs",
Some(format!("0x{:04X}", self.e_cs)),
std::mem::size_of_val(&self.e_cs),
"u16",
offset_of!(self, e_cs),
None,
)?;
serialize_field(
&mut state,
"e_lfarlc",
Some(format!("0x{:04X}", self.e_lfarlc)),
std::mem::size_of_val(&self.e_lfarlc),
"u16",
offset_of!(self, e_lfarlc),
None,
)?;
serialize_field(
&mut state,
"e_ovno",
Some(format!("0x{:04X}", self.e_ovno)),
std::mem::size_of_val(&self.e_ovno),
"u16",
offset_of!(self, e_ovno),
None,
)?;
// e_res 序列化,带 children
let mut e_res_children = Vec::new();
for (index, value) in self.e_res.iter().enumerate() {
e_res_children.push(ResponseDOSHeaderData {
name: format!("e_res[{}]", index),
value: Some(format!("0x{:04X}", value)),
size: std::mem::size_of_val(value),
field_type: "u16".to_string(),
offset: offset_of!(self, e_res) + index * std::mem::size_of::<u16>(),
children: None,
});
}
serialize_field(
&mut state,
"e_res",
None,
std::mem::size_of_val(&self.e_res),
"[u16;4]",
offset_of!(self, e_res),
Some(e_res_children),
)?;
// e_oemid 序列化
serialize_field(
&mut state,
"e_oemid",
Some(format!("0x{:04X}", self.e_oemid)),
std::mem::size_of_val(&self.e_oemid),
"u16",
offset_of!(self, e_oemid),
None,
)?;
// e_oeminfo 序列化
serialize_field(
&mut state,
"e_oeminfo",
Some(format!("0x{:04X}", self.e_oeminfo)),
std::mem::size_of_val(&self.e_oeminfo),
"u16",
offset_of!(self, e_oeminfo),
None,
)?;
// e_res2 序列化
let mut e_res2_children = Vec::new();
for (index, value) in self.e_res2.iter().enumerate() {
e_res2_children.push(ResponseDOSHeaderData {
name: format!("e_res2[{}]", index),
value: Some(format!("0x{:04X}", value)),
size: std::mem::size_of_val(value),
field_type: "u16".to_string(),
offset: offset_of!(self, e_res2) + index * std::mem::size_of::<u16>(),
children: None,
});
}
serialize_field(
&mut state,
"e_res2",
None,
std::mem::size_of_val(&self.e_res2),
"[u16;10]",
offset_of!(self, e_res2),
Some(e_res2_children),
)?;
// e_lfanew 序列化
serialize_field(
&mut state,
"e_lfanew",
Some(format!("0x{:04X}", self.e_lfanew.0)), // 假设 Offset 是简单的 tuple struct
std::mem::size_of_val(&self.e_lfanew),
"Offset",
offset_of!(self, e_lfanew),
None,
)?;
state.end()
}
}
// 命令获取DOS头数据 // 命令获取DOS头数据
#[tauri::command] #[tauri::command]
pub fn command_get_pe_data_dos_header() -> Result<ImageDosHeader, AppError> { pub fn command_get_pe_data_dos_header() -> Result<ImageDosHeader, AppError> {

View File

@ -1,8 +1,10 @@
use super::types::*; use super::types::*;
use bitflags::bitflags; use bitflags::bitflags;
use serde::Serialize; use pe_serialize_proc_macro::SerializeEX;
use serde::ser::SerializeStruct;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, SerializeEX)]
pub struct ImageDosHeader { pub struct ImageDosHeader {
pub e_magic: u16, // Magic number 固定值 0x5A4D pub e_magic: u16, // Magic number 固定值 0x5A4D
pub e_cblp: u16, pub e_cblp: u16,
@ -22,7 +24,7 @@ pub struct ImageDosHeader {
pub e_oemid: u16, pub e_oemid: u16,
pub e_oeminfo: u16, pub e_oeminfo: u16,
pub e_res2: [u16; 10], pub e_res2: [u16; 10],
pub e_lfanew: Offset, // File address of new exe header nt头的偏移 pub e_lfanew: u32, // File address of new exe header nt头的偏移
} }
#[repr(C)] #[repr(C)]