planetscale_driver_macros/
lib.rs

1use proc_macro::TokenStream;
2
3#[proc_macro_derive(Database)]
4pub fn derive_database(_input: TokenStream) -> TokenStream {
5    let input = syn::parse_macro_input!(_input as syn::DeriveInput);
6    let name = &input.ident;
7
8    if let syn::Data::Struct(data) = &input.data {
9        let fields = match &data.fields {
10            syn::Fields::Named(fields) => &fields.named,
11            _ => panic!("Only named fields are supported"),
12        };
13        let fields_len = syn::Index::from(fields.len());
14
15        let mut names = Vec::new();
16        let mut values = Vec::new();
17
18        for i in 0..fields.len() {
19            let field = &fields[i];
20
21            let name = &field.ident;
22            let ty = &field.ty;
23            names.push(name);
24
25            let index = syn::Index::from(i);
26            values.push(quote::quote! {
27                #ty::custom_parse(input[#index])?
28            });
29        }
30
31        let output = quote::quote! {
32            impl planetscale_driver::Deserializer for #name {
33                fn deserialize_raw(input: Vec<&str>) -> anyhow::Result<Self> {
34                    use planetscale_driver::Parser;
35
36                    if input.len() != #fields_len {
37                        anyhow::bail!("Invalid number of fields");
38                    }
39
40                    Ok(Self {
41                        #(
42                            #names: #values,
43                        )*
44                    })
45                }
46            }
47        };
48
49        TokenStream::from(output)
50    } else {
51        panic!("Only structs are supported")
52    }
53}
54
55#[proc_macro_derive(DatabaseJSON)]
56pub fn derive_database_json(_input: TokenStream) -> TokenStream {
57    let input = syn::parse_macro_input!(_input as syn::DeriveInput);
58    let name = &input.ident;
59
60    if let syn::Data::Struct(_) = &input.data {
61        let output = quote::quote! {
62            impl planetscale_driver::Parser for #name {
63                fn custom_parse(input: &str) -> anyhow::Result<Self> {
64                    serde_json::from_str(input).map_err(|e| e.into())
65                }
66            }
67
68            impl ToString for #name {
69                fn to_string(&self) -> String {
70                    serde_json::to_string(self).unwrap()
71                }
72            }
73        };
74
75        TokenStream::from(output)
76    } else {
77        panic!("Only structs are supported")
78    }
79}