1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
extern crate proc_macro; extern crate toml; use dirs::home_dir; use proc_macro::TokenStream; use quote::quote; use std::fs; use std::io::{BufReader, Read}; use std::path::PathBuf; use toml::Value; use syn::{parse_macro_input, DeriveInput}; fn file_open(path: PathBuf) -> Result<String, String> { let mut file_content = String::new(); let mut fr = fs::File::open(path) .map(|f| BufReader::new(f)) .map_err(|e| e.to_string())?; fr.read_to_string(&mut file_content) .map_err(|e| e.to_string())?; Ok(file_content) } #[proc_macro_derive(order)] pub fn order_builder(item: TokenStream) -> TokenStream { let ast = parse_macro_input!(item as DeriveInput); let name = &ast.ident; let enum_variants = if let syn::Data::Enum(syn::DataEnum { variants, .. }) = ast.data { variants } else { unimplemented!(); }; let enum_len = &enum_variants.len(); let mut config_dir: PathBuf = home_dir().unwrap(); config_dir.push(".config/jump-kun/config.toml".to_string()); let order_config: String = match file_open(config_dir) { Ok(e) => e.parse::<Value>().unwrap()["order"] .as_str() .unwrap() .to_owned(), Err(_) => "CurrentDir,VisitedDir,ParentDir,ChildDir,NotSure,Invalid".to_string(), }; let orders: Vec<&str> = order_config.split(",").collect(); assert_eq!( &orders.len(), enum_len, "orders: {:#?}, enum_variants: {:#?}", orders, enum_variants ); let enum_fields = orders.iter().enumerate().map(|(i, elm)| { let elm_ident = syn::Ident::new(&elm, name.span()); let arm = quote! { #name::#elm_ident => #i as i32, }; arm }); let order_func = quote! { impl #name { pub fn order(&self) -> i32{ match self { #(#enum_fields)* } } } }; order_func.into() }