cynic_codegen/query_variables_derive/
mod.rsuse {
proc_macro2::TokenStream,
quote::{format_ident, quote, quote_spanned},
syn::visit_mut::{self, VisitMut},
};
mod input;
use crate::{generics_for_serde, variables_fields_ident};
use self::input::QueryVariablesDeriveInput;
pub fn query_variables_derive(ast: &syn::DeriveInput) -> Result<TokenStream, syn::Error> {
use darling::FromDeriveInput;
match QueryVariablesDeriveInput::from_derive_input(ast) {
Ok(input) => query_variables_derive_impl(input),
Err(e) => Ok(e.write_errors()),
}
}
pub fn query_variables_derive_impl(
input: QueryVariablesDeriveInput,
) -> Result<TokenStream, syn::Error> {
let ident = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let generics_with_ser = generics_for_serde::with_serialize_bounds(&input.generics);
let (impl_generics_with_ser, _, where_clause_with_ser) = generics_with_ser.split_for_impl();
let vis = &input.vis;
let schema_module = &input.schema_module();
let fields_struct_ident = variables_fields_ident(ident);
let input_fields = input.data.take_struct().unwrap().fields;
let mut field_funcs = Vec::new();
let mut variables = Vec::new();
let mut field_inserts = Vec::new();
let mut coercion_checks = Vec::new();
let mut field_output_types = Vec::new();
for (field_idx, f) in input_fields.into_iter().enumerate() {
let name = f.ident.as_ref().unwrap();
let ty = &f.ty;
let mut ty_for_fields_struct = match f.graphql_type {
None => ty.clone(),
Some(ref graphql_type) => {
let new_type_that_coerces_to_schema_type =
format_ident!("CoercionProxyForField{field_idx}");
field_output_types.push(quote! {
#vis struct #new_type_that_coerces_to_schema_type;
cynic::impl_coercions!(#new_type_that_coerces_to_schema_type [] [], #schema_module::#graphql_type);
});
coercion_checks.push(quote! {
cynic::assert_impl!(#ty [#impl_generics] [#where_clause]: cynic::coercions::CoercesTo<#schema_module::#graphql_type>);
});
syn::parse_quote! { #new_type_that_coerces_to_schema_type }
}
};
TurnLifetimesToStatic.visit_type_mut(&mut ty_for_fields_struct);
let name_str =
proc_macro2::Literal::string(&f.graphql_ident(input.rename_all).graphql_name());
field_funcs.push(quote! {
#vis fn #name() -> cynic::variables::VariableDefinition<Self, #ty_for_fields_struct> {
cynic::variables::VariableDefinition::new(#name_str)
}
});
variables.push(quote! {
(#name_str, <#ty as #schema_module::variable::Variable>::TYPE)
});
match f.skip_serializing_if {
Some(skip_check_fn) => {
let skip_check_fn = &*skip_check_fn;
field_inserts.push(quote! {
if !#skip_check_fn(&self.#name) {
map_serializer.serialize_entry(#name_str, &self.#name)?;
}
})
}
None => field_inserts.push(quote! {
map_serializer.serialize_entry(#name_str, &self.#name)?;
}),
}
}
let map_len = field_inserts.len();
let ident_span = ident.span();
let fields_struct = quote_spanned! { ident_span =>
#vis struct #fields_struct_ident;
impl cynic::QueryVariablesFields for #fields_struct_ident {}
impl cynic::queries::VariableMatch<#fields_struct_ident> for #fields_struct_ident {}
const _: () = {
#(
#field_output_types
)*
impl #fields_struct_ident {
#(
#field_funcs
)*
}
};
};
Ok(quote! {
#[automatically_derived]
impl #impl_generics cynic::QueryVariables for #ident #ty_generics #where_clause {
type Fields = #fields_struct_ident;
const VARIABLES: &'static [(&'static str, cynic::variables::VariableType)]
= &[#(#variables),*];
}
#[automatically_derived]
impl #impl_generics_with_ser cynic::serde::Serialize for #ident #ty_generics #where_clause_with_ser {
fn serialize<__S>(&self, serializer: __S) -> Result<__S::Ok, __S::Error>
where
__S: cynic::serde::Serializer,
{
use cynic::serde::ser::SerializeMap;
#(#coercion_checks)*
let mut map_serializer = serializer.serialize_map(Some(#map_len))?;
#(#field_inserts)*
map_serializer.end()
}
}
#fields_struct
})
}
struct TurnLifetimesToStatic;
impl VisitMut for TurnLifetimesToStatic {
fn visit_lifetime_mut(&mut self, i: &mut syn::Lifetime) {
i.ident = format_ident!("static");
visit_mut::visit_lifetime_mut(self, i)
}
}