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
123
124
extern crate proc_macro;
use std::collections::HashMap;
use proc_macro::{TokenStream,TokenTree};
#[proc_macro_attribute]
pub fn reflective(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut code = item.to_string();
let tokens = item.clone().into_iter().peekable();
let struct_body : TokenStream;
let mut struct_props = HashMap::new();
for t in tokens{
match t{
TokenTree::Group(struct_body) => {
let mut struct_iter = struct_body.stream().into_iter();
let mut field_name = String::new();
let mut field_type = String::new();
loop {
let struct_body_token = match struct_iter.next() {
None => break,
Some(t) => t,
};
match &struct_body_token {
TokenTree::Ident(ident) => {
field_name = ident.to_string();
},
TokenTree::Punct(punct) => {
if punct.as_char() == ':'{
let mut brak_ref = 0;
loop {
let line_token = match struct_iter.next(){
None => break,
Some(t) => t,
};
match &line_token{
TokenTree::Punct(line_p) =>{
match line_p.as_char() {
',' | '}' => {
if brak_ref == 0{
struct_props.insert(field_name, field_type);
field_name = String::new();
field_type = String::new();
break;
}
},
'<' => { brak_ref +=1; },
'>' => { brak_ref-=1; },
_ => {},
}
},
TokenTree::Ident(_)=> {
if !field_type.ends_with('\''){
field_type.push(' ');
}
},
_ => {},
}
field_type.push_str(&line_token.to_string());
}
}
continue;
},
_ => {},
}
}
},
_ => {},
}
}
let struct_name = item
.into_iter()
.filter(|x| match x{
TokenTree::Ident(_) => true,
_ => false,
})
.last()
.unwrap()
.to_string();
let mut get_body = String::new();
get_body.push_str("{ match field \n\r{");
for (field,datatype) in &struct_props {
get_body.push_str(&format!(
"\"{field}\" => &(s.{field}) as &dyn std::any::Any,\n\r",
field=field
));
}
get_body.push_str("_ => panic!(\"Invalid field.\"), }}");
let mut set_body = String::new();
set_body.push_str("match field {");
for (field,datatype) in &struct_props {
set_body.push_str(&format!("
\"{field}\" => {{ s.{field} = ((&val as &dyn std::any::Any).downcast_ref::<{datatype}>().unwrap()).to_owned(); }},\r\n",
field=field,
datatype=datatype
));
}
set_body.push_str("_ => { panic!(\"invalid field\"); } }");
code.push_str(&format!("
impl {struct_name} {{
{access_nodifier} fn get_field<T: Copy + 'static>(s: &{struct_name}, field: &str) -> T {{
let a : &dyn std::any::Any = {get_body};
*(a.downcast_ref::<T>().unwrap())
}}
{access_nodifier} fn set_field<T: Copy + 'static>(s: &mut {struct_name}, field: &str, val : T) {{
{set_body}
}}
}}
", struct_name=struct_name, access_nodifier=attr.to_string(), get_body=get_body, set_body=set_body));
println!("{}", code);
code.parse().expect("Generated invalid tokens")
}