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