anondb-macros 0.1.3

anondb proc macros
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::Result;
use syn::*;

use super::*;

pub fn derive(input: DeriveInput) -> Result<TokenStream> {
    let crate_name = crate_name();

    let name = &input.ident;
    let generics = &input.generics;
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    let fields = parse_struct_and_fields(&input, "Document")?;

    let phantom_associated_functions = fields.iter().map(|f| {
        let field_name = f.ident.clone().unwrap();
        let field_type = f.ty.clone();
        quote! {
            pub fn #field_name () -> ::std::marker::PhantomData<#field_type> {
                ::std::marker::PhantomData::<#field_type>
            }
        }
    });

    let query_fields = fields.iter().map(|f| {
        let field_name = f.ident.clone().unwrap();
        let field_type = f.ty.clone();
        quote! {
            pub #field_name: Option<#crate_name::ParamTyped<#field_type>>
        }
    });

    let match_entries = fields.iter().map(|f| {
        let field_name = f.ident.clone().unwrap();
        let _field_type = f.ty.clone();
        quote! {
            if let Some(param) = query.#field_name.as_ref() {
                if !param.test(&self.#field_name) {
                    return false;
                }
            }
        }
    });
    let query_methods = fields.iter().map(|f| {
        let field_name = f.ident.clone().unwrap();
        let field_type = f.ty.clone();
        quote! {
            pub fn #field_name (mut self, p: impl Into<#crate_name::ParamTyped<#field_type>>) -> Self {
                self.#field_name = Some(p.into());
                self
            }
        }
    });
    let query_struct_name = quote::format_ident!("{}_Query", name);
    let phantom_struct_name = quote::format_ident!("{}_Phantom", name);

    let expanded = quote! {

        #[derive(Default, Debug)]
        #[allow(non_camel_case_types)]
        pub struct #impl_generics #query_struct_name #ty_generics #where_clause {
            #(#query_fields),*
        }

        impl #impl_generics #query_struct_name #ty_generics #where_clause {
            #(#query_methods)*
        }

        #[derive(Debug)]
        #[allow(non_camel_case_types)]
        pub struct #phantom_struct_name;

        impl #phantom_struct_name {
            #(#phantom_associated_functions)*
        }

        impl #impl_generics #crate_name::Queryable for #name #ty_generics #where_clause {
            type DocumentQuery = #query_struct_name;
            type DocumentPhantom = #phantom_struct_name;

            fn matches(&self, query: &Self::DocumentQuery) -> bool {
                #(#match_entries)*
                true
            }
        }
    };

    Ok(TokenStream::from(expanded))
}