Skip to main content

embeddb_derive/
lib.rs

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}