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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
extern crate proc_macro;
use proc_macro::TokenStream;
use std::collections::HashMap;
#[derive(Debug)]
enum TreeEntry {
Node(String),
Branch(HashMap<String, Box<TreeEntry>>),
}
impl TreeEntry {
fn get_mut(&mut self, part: &str) -> Option<&mut Box<TreeEntry>> {
match self {
TreeEntry::Branch(tree) => tree.get_mut(part),
_ => panic!(),
}
}
fn get(&mut self, part: &str) -> Option<&Box<TreeEntry>> {
match self {
TreeEntry::Branch(tree) => tree.get(part),
_ => panic!(),
}
}
fn insert(&mut self, part: String, node: TreeEntry) {
match self {
TreeEntry::Branch(tree) => {
tree.insert(part, Box::new(node));
}
_ => panic!(),
}
}
}
#[proc_macro]
pub fn include_protos(_item: TokenStream) -> TokenStream {
let out_dir = std::env::var("TIP_OUT_DIR")
.or(std::env::var("OUT_DIR"))
.unwrap();
let files = std::fs::read_dir(&out_dir).unwrap();
let file_names = files
.map(|x| x.unwrap().file_name().to_string_lossy().to_string());
let mut tree = TreeEntry::Branch(Default::default());
for file_name in file_names {
let mut current_branch = &mut tree;
for part in file_name.split('.') {
if part == "rs" {
*current_branch = TreeEntry::Node(file_name.to_string());
continue;
}
if let None = current_branch.get(part) {
current_branch.insert(part.to_owned(), TreeEntry::Branch(Default::default()));
}
current_branch = current_branch.get_mut(part).unwrap();
}
}
fn construct(tree_entry: Box<TreeEntry>, result: &mut String, out_dir: &str) {
match *tree_entry {
TreeEntry::Node(node) => {
result.push_str(&format!(r#"include!("{}/{}");"#, out_dir, node));
}
TreeEntry::Branch(branch) => {
for (name, child) in branch {
result.push_str(&format!("pub mod {} {{", name));
construct(child, result, out_dir);
result.push_str("}");
}
}
}
};
let mut result = String::new();
construct(Box::new(tree), &mut result, &out_dir);
result.parse().unwrap()
}