1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput, Fields};
4
5#[proc_macro_derive(FromEmbedRow)]
6pub fn derive_from_embed_row(input: TokenStream) -> TokenStream {
7 let input = parse_macro_input!(input as DeriveInput);
8 let name = &input.ident;
9
10 let fields = match &input.data {
11 Data::Struct(s) => match &s.fields {
12 Fields::Named(named) => &named.named,
13 _ => {
14 return syn::Error::new_spanned(name, "FromEmbedRow requires named fields")
15 .to_compile_error()
16 .into();
17 }
18 },
19 _ => {
20 return syn::Error::new_spanned(name, "FromEmbedRow can only be derived for structs")
21 .to_compile_error()
22 .into();
23 }
24 };
25
26 let inits = fields.iter().map(|field| {
27 let ident = field.ident.as_ref().unwrap();
28 let col = ident.to_string();
29 let ty = &field.ty;
30 quote! {
31 #ident: {
32 let __idx = __columns.iter().position(|c| c == #col);
33 let __v = __idx.and_then(|i| __row.get(i));
34 <#ty as ::embeddb::FromEmbedValue>::from_embed_value(__v)
35 .map_err(|e| ::embeddb::EmbedError::Other(
36 format!("column '{}': {}", #col, e)))?
37 }
38 }
39 });
40
41 let expanded = quote! {
42 impl ::embeddb::FromEmbedRow for #name {
43 fn from_row(__row: &::embeddb::EmbedRow, __columns: &[String]) -> ::embeddb::Result<Self> {
44 Ok(#name {
45 #(#inits),*
46 })
47 }
48 }
49 };
50 expanded.into()
51}