extern crate proc_macro;
use std::{collections::HashMap, path};
use quote::quote;
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::token::Enum;
use syn::{parse_macro_input, DeriveInput, Expr, Ident, Item, ItemEnum, ItemFn, ItemStruct, LitStr, Token};
use enum_map::{EnumMap};
use std::fs;
use std::path::Path;
#[proc_macro_attribute]
pub fn generate_enum_and_map(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream
{
let input = parse_macro_input!(item as ItemEnum);
let subdir = attr.to_string().trim_matches('"').to_string();
let paths = std::fs::read_dir(subdir.clone()).unwrap();
let names_and_variants: Vec<(Ident, String)> = paths.into_iter()
.filter_map(|dir| dir.ok())
.map(|dir| dir.path())
.filter(|path| path.is_file())
.filter_map(|path|
match
(
path.file_name().and_then(|x| x.to_str()),
path.file_stem().and_then(|x| x.to_str()),
path.extension().and_then(|x| x.to_str())
)
{
(Some(name), Some(stem), Some(ext)) => Some((name.to_string(), stem.to_string(), ext.to_string())),
_ => None,
}
)
.map
(
|(name, stem, ext)| (format!("{}/{}", subdir.clone(), name), stem.chars().into_iter().filter(|x| x.is_ascii_alphanumeric()).collect::<String>(), ext)
)
.map
(
|(name, variant, ext)| (name, syn::Ident::new(&variant, proc_macro2::Span::call_site()), ext)
)
.map
(
|(name, variant, ext)| (variant, name)
)
.collect();
let variants: Vec<Ident> = names_and_variants.iter().map(|x| x.0.clone()).collect();
let names: Vec<String> = names_and_variants.iter().map(|x| x.1.clone()).collect();
let attrs = &input.attrs;
let vis = &input.vis;
let enum_ident = &input.ident;
let map_ident = syn::Ident::new(&format!("{}{}", &input.ident, "Map"), proc_macro2::Span::call_site());
let expanded = quote!
{
#(#attrs)*
#vis enum #enum_ident
{
#(#variants),*
}
struct #map_ident ( HashMap < #enum_ident, String >);
impl #map_ident
{
fn new() -> Self
{
let mut map: Self = #map_ident(HashMap::new());
let a: Vec<(#enum_ident, String)> = vec![#( (#enum_ident::#variants, #names.to_string()) ),*];
a.iter().for_each
(
|(variant, name)| {map.0.insert(variant.clone(), name.clone());}
);
map
}
}
};
proc_macro::TokenStream::from(expanded)
}