contraband_codegen 0.1.2

Contraband proc macros
Documentation
use proc_macro2::{Ident, Span};
use std::collections::HashMap;
use syn::Meta;

pub(crate) struct ModuleArgs {
    pub(crate) controllers: Vec<syn::Path>,
    pub(crate) imports: Vec<syn::Path>,
    pub(crate) exports: Vec<syn::Path>,
    pub(crate) providers: Vec<syn::Path>,
}

impl ModuleArgs {
    pub(crate) fn parse_and_strip(attrs: &mut std::vec::Vec<syn::Attribute>) -> syn::Result<Self> {
        let mut controllers = Vec::new();
        let mut imports = Vec::new();
        let mut exports = Vec::new();
        let mut providers = Vec::new();
        let mut path_to_vec = HashMap::new();
        let call_site = Span::call_site();
        path_to_vec.insert(Ident::new("controller", call_site), &mut controllers);
        path_to_vec.insert(Ident::new("import", call_site), &mut imports);
        path_to_vec.insert(Ident::new("export", call_site), &mut exports);
        path_to_vec.insert(Ident::new("provider", call_site), &mut providers);
        for attr in attrs.clone() {
            match attr.parse_meta() {
                Ok(Meta::List(nv)) => {
                    if let Some(vec) = nv.path.get_ident().and_then(|x| path_to_vec.get_mut(x)) {
                        for item in nv.nested {
                            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = item {
                                vec.push(path);
                            } else {
                                return Err(syn::Error::new_spanned(
                                    nv.path,
                                    "Attribute guard expects a path!",
                                ));
                            }
                        }
                    } else {
                        return Err(syn::Error::new_spanned(
                            nv.path,
                            "Unknown attribute key is specified.",
                        ));
                    }
                }
                Ok(Meta::Path(path)) => {
                    return Err(syn::Error::new_spanned(
                        path,
                        "Unknown attribute key is specified.",
                    ))
                }
                Ok(arg) => {
                    return Err(syn::Error::new_spanned(arg, "Unknown attribute."));
                }
                Err(_) => {}
            }
        }
        attrs.retain(|attr| {
            attr.path
                .get_ident()
                .and_then(|x| path_to_vec.get(x))
                .is_none()
        });
        Ok(Self {
            controllers,
            imports,
            exports,
            providers,
        })
    }
}