holy 0.2.1

Holy is a proc-macro library that provides helper macros.
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Field, Fields};

use crate::utils::{determine_visibility, should_skip};

pub fn impl_setters_macro(ast: &DeriveInput) -> Result<TokenStream, syn::Error> {
    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

    let setters = match &ast.data {
        Data::Struct(data) => match &data.fields {
            Fields::Named(fields) => fields
                .named
                .iter()
                .filter(|f| !should_skip(&f.attrs))
                .map(generate_setter)
                .collect::<Result<Vec<_>, syn::Error>>()?,
            _ => {
                return Err(syn::Error::new_spanned(
                    ast,
                    "Setters macro only supports structs with named fields",
                ));
            }
        },
        _ => {
            return Err(syn::Error::new_spanned(
                ast,
                "Setters macro only supports structs",
            ));
        }
    };

    let expanded = quote! {
        impl #impl_generics #name #ty_generics #where_clause {
            #(#setters)*
        }
    };

    Ok(TokenStream::from(expanded))
}

fn generate_setter(field: &Field) -> Result<proc_macro2::TokenStream, syn::Error> {
    let field_name = field
        .ident
        .as_ref()
        .ok_or_else(|| syn::Error::new_spanned(field, "Field without a name"))?;
    let field_type = &field.ty;
    let vis = &field.vis;
    let setter_name = syn::Ident::new(&format!("set_{}", field_name), field_name.span());
    let setter_vis = determine_visibility(vis, &field.attrs)?;

    let setter = quote! {
        #setter_vis fn #setter_name(&mut self, value: #field_type) {
            self.#field_name = value;
        }
    };

    Ok(setter)
}