use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput, parse_macro_input, Fields, Type};
#[proc_macro_derive(FromSqliteRow)]
pub fn derive_from_sqlite_row(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let fields = match input.data {
syn::Data::Struct(s) => s.fields,
_ => panic!("FromSqliteRow 只能用于结构体"),
};
let field_initializers = match fields {
Fields::Named(fields) => {
let field_names = fields.named.clone();
field_names.into_iter().map(|field| {
let ident = field.ident.as_ref().unwrap();
let ident_str = ident.to_string();
let field_type = &field.ty;
let field_get_code = if let Type::Path(path) = field_type {
if let Some(seg) = path.path.segments.last() {
if seg.ident == "String" {
quote! { row.read::<&str, _>(#ident_str).to_string() }
} else {
quote! { row.read(#ident_str) }
}
} else {
quote! { row.read(#ident_str) }
}
} else {
quote! { row.read(#ident_str) }
};
quote! {
#ident: #field_get_code
}
})
},
_ => panic!("FromSqliteRow 只支持带命名字段的结构体"),
};
let expanded = quote! {
impl FromSqliteRow for #name {
fn from_row(row: &sqlite::Row) -> Self {
Self {
#(#field_initializers),*
}
}
}
};
TokenStream::from(expanded)
}