我正在使用结构来构建数据库的架构,因此我需要结构的元信息。
假设我的架构结构定义如下:
#[derive(ParseStruct)]
pub struct User {
#[field_attr( unique = true, default = "", index=["@hash", "@count"] )]
pub name: String,
#[field_attr( unique = true, default = "" )]
pub username: String,
pub description: Option<String>,
pub age: u32
}
我想解析为以下结构:pub struct Schema<T>{
name: String, // the struct name
origin: T, // the struct to be parse, like the User struct above.
fields: Vec<Field>, // the struct's fields
}
pub struct Field {
field_name: String,
field_type: String,
field_attrs: FieldAttribute
}
pub struct FieldAttribute {
unique: bool,
default: String,
index: Vec<String> // Index of the database
}
我写了一个开始,但是我不知道如何继续写:#[proc_macro_derive(ParseStruct)]
pub fn parse_struct_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
let name = &ast.ident;
let gen = quote! {
impl #name {
fn parsed_schema()-> Schema {
// return the parsed schema
//...
}
}
};
gen.into()
}
预期结果:use parse_struct::ParseStruct;
#[derive(ParseStruct)]
struct User{
#[field_attr( unique = true, default = "", index=["@hash", "@count"] )]
pub name: String
}
fn main() {
let schema = User::parsed_schema();
println!("{:#?}",schema);
}
我不知道如何实现它。我只是最近才开始学习派生宏,还没有完全掌握它。很难在Internet上找到有用的有关衍生宏的教程。
请帮助我,谢谢。
最佳答案
使用proc_macro_derive(过程宏)
src/main.rs:
use print_struct_trait::PrintStruct;
#[derive(PrintStruct)]
struct Point {
name: String,
x: i32,
y: i32,
}
fn main() {
let point = Point {
name: "origin".to_string(),
x: 2,
y: 3,
};
point.print();
}
输出:key=name, value=origin, type=String
key=x, value=2, type=i32
key=y, value=3, type=i32
print_struct_derive/src/lib.rs:use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::spanned::Spanned;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(PrintStruct, attributes(serde))]
pub fn derive_signature(item: TokenStream) -> TokenStream {
let ast = parse_macro_input!(item as DeriveInput);
let struct_name = &ast.ident;
let fields = if let syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(ref fields),
..
}) = ast.data
{
fields
} else {
panic!("Only support Struct")
};
let mut keys = Vec::new();
let mut idents = Vec::new();
let mut types = Vec::new();
for field in fields.named.iter() {
let field_name: &syn::Ident = field.ident.as_ref().unwrap();
let name: String = field_name.to_string();
let literal_key_str = syn::LitStr::new(&name, field.span());
let type_name = &field.ty;
keys.push(quote! { #literal_key_str });
idents.push(&field.ident);
types.push(type_name.to_token_stream());
}
let expanded = quote! {
impl PrintStruct for #struct_name {
fn print(&self) {
#(
println!(
"key={key}, value={value}, type={type_name}",
key = #keys,
value = self.#idents,
type_name = stringify!(#types)
);
)*
}
}
};
expanded.into()
}
PrintStruct在github上的源代码引用:
关于struct - rust -如何使用派生宏来解析结构的元信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62837767/