use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::{Render, core::Field, params};
use super::syntax::GetSyntax;
#[derive(Clone, Default)]
pub struct StructSyntax;
impl Render for StructSyntax {
type Args = params::StructParams;
fn render(&self, args: Self::Args) -> syn::Result<TokenStream> {
let ident = &args.input.ident;
let (impl_generics, type_generics, where_generics) = &args.input.generics.split_for_impl();
let fields: Vec<_> = args
.data
.fields
.iter()
.enumerate()
.map(|(i, field)| Field::parse(i, field))
.collect::<syn::Result<Vec<_>>>()?;
let fields: Vec<_> = fields
.into_iter()
.filter(|field| field.attrs().exists("get"))
.collect();
let methods: Vec<TokenStream> = fields
.iter()
.map(|field| -> syn::Result<TokenStream> {
let fname = field.name();
let ty = field.ty();
let doc_attrs = field.docs();
let opts = GetSyntax::parse(field)?;
let method_name = match opts.custom_name {
Some(id) => id,
None => format_ident!("{}", fname.to_string()),
};
let callback = opts
.on
.as_ref()
.map(|expr| quote!(#expr;))
.unwrap_or_default();
let getter = if field.is_option() {
let inner_ty = field.as_inner().unwrap();
quote! {
#(#doc_attrs)*
pub fn #method_name(&self) -> ::std::option::Option<&<#inner_ty as ::std::ops::Deref>::Target> {
#callback
self.#fname.as_deref()
}
}
} else if field.is_bool() || opts.copy {
quote! {
#(#doc_attrs)*
pub fn #method_name(&self) -> #ty {
#callback
self.#fname
}
}
} else if opts.clone {
quote! {
#(#doc_attrs)*
pub fn #method_name(&self) -> #ty {
#callback
self.#fname.clone()
}
}
} else {
quote! {
#(#doc_attrs)*
pub fn #method_name(&self) -> &<#ty as ::std::ops::Deref>::Target {
#callback
&self.#fname
}
}
};
let mut_getter = if opts.mutable {
let mut_name = format_ident!("{}_mut", fname.to_string());
quote! {
pub fn #mut_name(&mut self) -> &mut #ty {
&mut self.#fname
}
}
} else {
quote!()
};
Ok(quote! {
#getter
#mut_getter
})
})
.collect::<syn::Result<Vec<_>>>()?;
Ok(quote! {
impl #impl_generics #ident #type_generics #where_generics {
#(#methods)*
}
})
}
}