1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};

#[proc_macro_derive(Query)]
pub fn derive_query(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let ret = match input.data {
        Data::Struct(data_struct) => match data_struct.fields {
            Fields::Named(fields) => {
                let field_names: Vec<_> = fields.named.iter().map(|f| &f.ident).collect();
                assert!(!field_names.is_empty(), "can't derive on empty field");
                quote! {
                    impl #impl_generics ::skytable::query::SQParam for #name #ty_generics #where_clause {
                        fn append_param(&self, q: &mut Vec<u8>) -> usize {
                            let mut size = 0;
                            #(size += ::skytable::query::SQParam::append_param(&self.#field_names, q);)*
                            size
                        }
                    }
                }
            }
            _ => unimplemented!(),
        },
        _ => unimplemented!(),
    };
    TokenStream::from(ret)
}

#[proc_macro_derive(Response)]
pub fn derive_response(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let ret = match input.data {
        Data::Struct(data_struct) => match data_struct.fields {
            Fields::Named(fields) => {
                let field_names: Vec<_> = fields.named.iter().map(|f| &f.ident).collect();
                assert!(!field_names.is_empty(), "can't derive on empty field");
                let tuple_pattern = if field_names.len() == 1 {
                    quote! { quote! { (#(#field_names),*,) } }
                } else {
                    quote! { (#(#field_names),*) }
                };
                let struct_instantiation = quote! { Self { #(#field_names),* } };
                quote! {
                    impl #impl_generics skytable::response::FromResponse for #name #ty_generics #where_clause {
                        fn from_response(resp: skytable::response::Response) -> skytable::ClientResult<Self> {
                            let #tuple_pattern = skytable::response::FromResponse::from_response(resp)?;
                            Ok(#struct_instantiation)
                        }
                    }
                }
            }
            _ => unimplemented!(),
        },
        _ => unimplemented!(),
    };
    TokenStream::from(ret)
}