use proc_macro2::TokenStream;
use quote::quote;
use syn::Result;
use syn::spanned::Spanned;
pub fn generate_impls(input: &syn::DeriveInput) -> Result<TokenStream> {
match &input.data {
syn::Data::Struct(item) => generate_from_struct(input, item),
_ => err(input, "Can only derive Deletable for structs"),
}
}
fn generate_from_struct(
input: &syn::DeriveInput,
item: &syn::DataStruct,
) -> Result<TokenStream> {
let ident = &input.ident;
let mut generics = input.generics.clone();
let body = match &item.fields {
syn::Fields::Named(fields_named) => {
let calls: Vec<TokenStream> = fields_named
.named
.iter()
.map(|f| {
let name = &f.ident;
quote! { self.#name.delete_internal(exclusive); }
})
.collect();
for field in &fields_named.named {
let ty = &field.ty;
generics
.make_where_clause()
.predicates
.push(syn::parse_quote!(#ty: Deletable));
}
quote! { #(#calls)* }
}
syn::Fields::Unit => quote! { let _ = exclusive; },
_ => {
return err(&item.fields, "Can only handle named or unit structs");
}
};
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
Ok(quote! {
const _: () = {
use ::thruput_sdk::storage::Deletable;
impl #impl_generics Deletable for #ident #ty_generics
#where_clause
{
fn delete_internal(&mut self, exclusive: bool) {
#body
}
}
};
})
}
fn err<T, S, M>(spanned: &S, msg: M) -> Result<T>
where
S: Spanned,
M: AsRef<str>,
{
Err(syn::Error::new(spanned.span(), msg.as_ref()))
}