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
use proc_macro::TokenStream;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

/// generate enum Category from `output/categories.json`
#[proc_macro]
pub fn enum_category(_item: TokenStream) -> TokenStream {
    let path = Path::new(env!("CARGO_MANIFEST_DIR"));
    let mut f = File::open(path.join("output/categories.json")).unwrap();
    let mut contents = String::new();
    f.read_to_string(&mut contents).unwrap();
    let categories: Vec<String> = serde_json::from_str(&contents).unwrap();

    let mut enum_category = String::from("#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]\npub enum Category {\n");
    for category in &categories {
        enum_category.push_str(&format!(
            "    {},\n",
            category.split(' ').collect::<Vec<&str>>()[0].replace('+', "").replace("-", "_")
        ));
    }
    enum_category.push_str("    NoCategory,\n");
    enum_category.push_str("}");

    enum_category.push_str(
        "
impl std::str::FromStr for Category {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
",
    );
    for category in &categories {
        enum_category.push_str(&format!(
            "            \"{}\" => Ok(Category::{}),\n",
            category,
            category.split(' ').collect::<Vec<&str>>()[0].replace('+', "").replace("-", "_")
        ));
    }
    enum_category.push_str(
        "
            _ => Err(()),
        }
    }
}
",
    );

    // impl Display for Category
    enum_category.push_str(
        "
impl std::fmt::Display for Category {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
",
    );
    for category in &categories {
        enum_category.push_str(&format!(
            "            Category::{} => write!(f, \"{}\"),\n",
            category.split(' ').collect::<Vec<&str>>()[0].replace('+', "").replace("-", "_"),
            category.split(' ').collect::<Vec<&str>>()[0].replace('+', "").replace("-", "_")
        ));
    }
    enum_category.push_str(
        "
            Category::NoCategory => write!(f, \"NoCategory\"),
        }
    }
}
",
    );

    enum_category.parse().unwrap()
}