aspartial_derive 0.0.1

Derive macros for the aspartial crate. Don't use this crate directly
Documentation
use proc_macro2::Span;

pub struct NameConfig {
    pub partial_type_key: syn::Ident,
    #[allow(dead_code)]
    pub equals_sign: syn::Token![=],
    pub ident: syn::Ident,
}

pub struct AttrsConfig {
    #[allow(dead_code)]
    pub attrs_key: syn::Ident,
    #[allow(dead_code)]
    pub opening_paren: syn::token::Paren,
    pub attrs: Vec<syn::Attribute>
}

pub enum Config{
    Name(NameConfig),
    Attrs(AttrsConfig),
}

impl syn::parse::Parse for Config {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let ident: syn::Ident = input.parse()?;
        if ident.to_string() == "name" {
            return Ok(Self::Name(NameConfig {
                partial_type_key: ident,
                equals_sign: input.parse()?,
                ident: input.parse()?,
            }))
        }
        if ident.to_string() == "attrs" {
            let attrs_content;
            return Ok(Self::Attrs(AttrsConfig{
                attrs_key: ident,
                opening_paren: syn::parenthesized!(attrs_content in input),
                attrs: attrs_content.call(syn::Attribute::parse_outer)?,
            }))
        }
        Err(syn::Error::new(
            ident.span(),
            format!("Unrecognized AsPartial config. Expected 'name' or 'attrs', found {ident}")
        ))
    }
}

pub struct ConfigsForAsPartial {
    pub partial_type_ident: syn::Ident,
    pub attrs: Vec<syn::Attribute>,
}

impl ConfigsForAsPartial {
    pub fn from_attrs(attrs: &[syn::Attribute]) -> syn::Result<Self> {
        let mut name_config: syn::Result<NameConfig> = Err(syn::Error::new(Span::call_site(), "no partial name set"));
        let mut attrs_for_partial_config = Vec::<syn::Attribute>::new();

        for attr in attrs {
            if attr.path().segments.last().unwrap().ident.to_string() != "aspartial" {
                continue
            }
            let syn::Meta::List(meta_list) = &attr.meta else {
                continue
            };
            match meta_list.parse_args::<Config>()? {
                Config::Name(new_name_conf) => {
                    if name_config.is_ok() {
                        return Err(syn::Error::new(new_name_conf.partial_type_key.span(), "Setting partial name again"))
                    }
                    name_config = Ok(new_name_conf);
                },
                Config::Attrs(new_attrs_conf) => {
                    attrs_for_partial_config.extend(new_attrs_conf.attrs);
                },
            }
        }

        Ok(Self{
            partial_type_ident: name_config?.ident,
            attrs: attrs_for_partial_config,
        })
    }
}