use crate::parse::deps::*;
use proc_macro2::{Ident, TokenStream};
use quote::{ToTokens, format_ident, quote};
use syn::{Attribute, Type};
use super::TransformerField;
impl crate::codegen::CodegenWrapper<super::TransformerStruct> {
pub(crate) fn gen_structs(&self, token_stream: &mut TokenStream) {
self
.gen_structs_inner(
&self.attrs,
self.struct_name(),
|f| f.field.attrs.clone(),
|f| &f.name,
TransformerField::self_type,
)
.to_tokens(token_stream);
self
.gen_structs_inner(
&[],
&self.graphql_input_name(),
|_| Vec::default(),
|f| f.graphql_input_name(),
TransformerField::graphql_input_type,
)
.to_tokens(token_stream);
self.gen_hash_impls().to_tokens(token_stream);
self
.gen_graphql_output_struct_inner()
.to_tokens(token_stream);
}
fn gen_graphql_output_struct_inner(&self) -> TokenStream {
let struct_name = self.graphql_output_name();
let struct_attrs = self.struct_opts.graphql_opts.attrs.outer_attributes();
let struct_vis = &self.vis;
let fields = self.fields.iter().map(|f| {
let attrs = f.graphql_config.attrs.outer_attributes();
let field_vis = &f.field.vis;
let field_name = &f.name;
let field_type = &f.self_type();
quote! {
#(#attrs)*
#field_vis #field_name: #field_type
}
});
let self_name = self.struct_name();
let block_ty = quote!(<<<#self_name as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber);
let block_fields = if self.is_entity() {
quote! {
pub(crate) __block_number_range: <#block_ty as ::cido::__internal::BlockNumber>::Range,
}
} else {
quote! {
pub(crate) __block_number: #block_ty,
}
};
quote! {
#(#struct_attrs)*
#[allow(non_snake_case)]
#struct_vis struct #struct_name {
pub(crate) __query_block: #block_ty,
#block_fields
#(#fields),*
}
impl #struct_name {
pub fn __query_block(&self) -> #block_ty {
self.__query_block
}
pub fn __set_query_block(&mut self, query_block: #block_ty) {
self.__query_block = query_block;
}
}
}
}
fn gen_structs_inner(
&self,
struct_attrs: &[Attribute],
struct_name: &Ident,
field_attrs: impl Fn(&TransformerField) -> Vec<Attribute>,
field_name: impl Fn(&TransformerField) -> &Ident,
field_type: impl Fn(&TransformerField) -> Type,
) -> TokenStream {
let struct_vis = &self.vis;
let mut alias_accessors = vec![];
let fields = self.fields.iter().map(|f| {
let attrs = field_attrs(f);
let field_vis = &f.field.vis;
let field_name = field_name(f);
let field_type = field_type(f);
f.alias.iter().for_each(|alias| {
let setter = format_ident!("set_{}", alias);
let getter = format_ident!("get_{}", alias);
alias_accessors.push(quote! {
#field_vis fn #setter(&mut self, val: #field_type) {
self.#field_name = val;
}
#field_vis fn #getter(&self) -> &#field_type {
&self.#field_name
}
});
});
quote! {
#(#attrs)*
#field_vis #field_name: #field_type
}
});
quote! {
#[allow(non_snake_case)]
#(#struct_attrs)*
#struct_vis struct #struct_name {
#(#fields),*
}
impl #struct_name {
#(#alias_accessors)*
}
}
}
#[allow(unused_assignments, unused_mut)]
fn gen_hash_impls(&self) -> TokenStream {
let struct_name = self.struct_name();
let fast_fields_hashing = self.fields.iter().enumerate().map(|(i, f)| {
let field_name = &f.name;
let field_name_str = f.graphql_output_name().to_string();
quote! {
{
let i = #i;
let field_hashing = ::cido::__internal::ValueTypeHasher {
field: #field_name_str,
data: &self.#field_name,
};
let mut new_hasher = H::new();
let (a, b) = field_address.unordered();
field_hashing.stable_hash(a, &mut new_hasher);
state.write(b, new_hasher.to_bytes().as_ref());
}
}
});
quote! {
impl ::cido::__internal::stable_hash::StableHash for #struct_name {
fn stable_hash<H: ::cido::__internal::stable_hash::StableHasher>(
&self,
field_address: H::Addr,
state: &mut H
) {
use ::cido::__internal::stable_hash::prelude::*;
use ::cido::__internal::{BigDecimal, BigInt, Hashable};
#(#fast_fields_hashing)*
}
}
}
}
}