from_sqlite_row_macro/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, parse_macro_input, Fields, Type};
4
5/// 定义派生宏:#[derive(FromSqliteRow)]
6/// 
7/// 用于展开代码,为结构体实现 `dev_tool::sqlite_util::FromSqliteRow` trait
8#[proc_macro_derive(FromSqliteRow)]
9pub fn derive_from_sqlite_row(input: TokenStream) -> TokenStream {
10    // 解析输入的结构体定义
11    let input = parse_macro_input!(input as DeriveInput);
12    let name = input.ident; // 获取结构体名称
13
14    // 提取结构体字段(只处理命名字段的结构体,如 struct User { id: i32, name: String })
15    let fields = match input.data {
16        syn::Data::Struct(s) => s.fields,
17        _ => panic!("FromSqliteRow 只能用于结构体"),
18    };
19
20    // 为每个字段生成从 sqlite::Row 读取的代码
21    let field_initializers = match fields {
22        Fields::Named(fields) => {
23                let field_names = fields.named.clone();
24                field_names.into_iter().map(|field| {
25                // 获取字段名(如 id、name)
26                let ident = field.ident.as_ref().unwrap();
27                // 将字段名转换为字符串(用于作为SQL列名)
28                let ident_str = ident.to_string();
29                // 获取字段类型
30                let field_type = &field.ty;
31
32                let field_get_code = if let Type::Path(path) = field_type {
33                    // 获取字段类型最后一层的名字
34                    if let Some(seg) = path.path.segments.last() {
35                        if seg.ident == "String" {
36                            // 如果是 String 类型
37                            quote! { row.read::<&str, _>(#ident_str).to_string() }
38                        } else {
39                            // 其他类型
40                            quote! { row.read(#ident_str) }
41                        }
42                    } else {
43                        quote! { row.read(#ident_str) }
44                    }
45                } else {
46                    quote! { row.read(#ident_str) }
47                };
48
49                // 生成代码:#ident: <根据字段类型生成的获取代码>
50                quote! {
51                    #ident: #field_get_code
52                }
53            })
54        },
55        _ => panic!("FromSqliteRow 只支持带命名字段的结构体"),
56    };
57
58    // 生成完整的实现代码
59    let expanded = quote! {
60        impl FromSqliteRow for #name {
61            fn from_row(row: &sqlite::Row) -> Self {
62                Self {
63                    #(#field_initializers),*
64                }
65            }
66        }
67    };
68
69    TokenStream::from(expanded)
70}