query_macros 0.1.0

macros for query crate
Documentation
use std::ops::Not;

use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{parse2, visit::Visit, Fields, Ident};
use syn::{
    parse_quote, DeriveInput, GenericParam, Generics, ImplItem,
    ItemImpl, Member,
};

pub fn consume_into_argument_impl(
    input: &DeriveInput,
    tokens: &mut TokenStream,
) {
    #[derive(Default)]
    pub struct I<'i> {
        pub wheres: Vec<&'i syn::Type>,
        pub members: Vec<syn::Member>,
        pub params: Vec<&'i syn::GenericParam>,
        pub wheres2: Vec<&'i syn::WherePredicate>,
        inc: u32,
        pub body: TokenStream,
    }

    impl<'ast> Visit<'ast> for I<'ast> {
        fn visit_generics(&mut self, i: &'ast syn::Generics) {
            if let Some(wc) = &i.where_clause {
                wc.predicates.iter().for_each(|i| {
                    self.wheres2.push(i);
                });
            }
            for i in i.params.iter() {
                self.params.push(i);
            }
        }
        fn visit_type(&mut self, i: &'ast syn::Type) {
            self.wheres.push(i);
        }
        fn visit_field(&mut self, i: &'ast syn::Field) {
            let inc = self.inc;
            self.inc += 1;

            let member = match i.ident.as_ref() {
                Some(ident) => Member::Named(ident.clone()),
                None => Member::Unnamed(syn::Index {
                    index: inc,
                    span: Span::call_site(),
                }),
            };
            self.members.push(member);

            syn::visit::visit_field(self, i);
        }
        fn visit_data_enum(&mut self, i: &'ast syn::DataEnum) {
            panic!("enum are not supported");
        }
        fn visit_data_union(&mut self, i: &'ast syn::DataUnion) {
            panic!("unions are not supported")
        }
    }
    let mut this = I::default();
    this.visit_derive_input(input);

    let wheres = this.wheres;
    let members = this.members;

    let params = this.params;
    let wheres2 = this.wheres2;

    let ident = &input.ident;
    let db = Ident::new("IntoMutArgumentsDB", Span::call_site());

    tokens.extend( quote!( const _: () = {
        use ::query::impl_into_mut_arguments_prelude::*;
        impl<
            'q, 
            #db,
            #(#params,)*
        >
            IntoMutArguments<'q, #db>
        for #ident
        where
            #db: Database,
            #(
                #wheres: Type<#db> + Encode<'q, #db> + Send + 'q,
            )*
            #(#wheres2,)*
        {
            fn members_ord() -> &'static [&'static str] {
                &[
                    #(
                        stringify!(#members),
                    )*
                ]
            }
            fn into_arguments(
                self,
                argument: &mut <#db as HasArguments<'q>>::Arguments,
            ) {
                #(
                    argument.add(self.#members);
                )*
            }
        }
    };));
}