1extern crate proc_macro;
2extern crate proc_macro2;
3#[macro_use]
4extern crate quote;
5extern crate syn;
6extern crate serde_derive_internals;
7extern crate serde;
8
9use proc_macro2::TokenStream;
10use std::str::FromStr;
11use proc_macro2::TokenTree;
12
13#[proc_macro_attribute]
14pub fn jvm_object(metadata: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
15
16 let input: TokenStream = input.clone().into();
17
18 let tokens = input.clone().into_iter().peekable();
19 let mut struct_props = Vec::new();
20 let mut inner_types = vec![];
21
22 for t in tokens {
23
24 match t{
25 TokenTree::Group(struct_body) => {
26 let mut struct_iter = struct_body.stream().into_iter();
27 let mut field_name = String::new();
28 let mut field_type = String::new();
29 loop {
30 let struct_body_token = match struct_iter.next() {
31 None => break,
32 Some(t) => t,
33 };
34 match &struct_body_token {
35 TokenTree::Ident(ident) => {
36 field_name = ident.to_string();
37 },
38 TokenTree::Punct(punct) => {
39 if punct.as_char() == ':'{
40 let mut brak_ref = 0;
41 loop {
42 let line_token = match struct_iter.next() {
43 None => {
44 if field_type.replace(" ", "").len() > 3 && field_type.trim_start().ne("String") {
45 inner_types.push((field_name.clone().replace(" ", ""), field_type.clone().replace(" ", "")));
46 }
47 struct_props.push ((field_name.clone(), field_type.clone().replace(" ", "")));
48 break
49 },
50 Some(t) => t,
51 };
52
53 match &line_token{
54 TokenTree::Punct(line_p) => {
55 match line_p.as_char() {
56 ',' | '}' => {
57 if brak_ref == 0 {
58 if field_type.replace(" ", "").len() > 3 && field_type.trim_start().ne("String") {
59 inner_types.push((field_name.clone().replace(" ", ""), field_type.replace(" ", "")));
60 }
61 struct_props.push((field_name, field_type.replace(" ", "")));
62 field_name = String::new();
63 field_type = String::new();
64 break;
65 }
66 },
67 '<' => { brak_ref +=1; },
68 '>' => { brak_ref-=1; },
69 _ => {},
70 }
71 },
72 TokenTree::Ident(_) => {
73 if !field_type.ends_with('\'') {
74 field_type.push(' ');
75 }
76 },
77 _ => {},
78 }
79 field_type.push_str(&line_token.to_string());
80 }
81 }
82 continue;
83 },
84 _ => {},
85 }
86 }
87 },
88 _ => {},
89 }
90 }
91
92 let struct_name = input.clone().into_iter().filter(|x| match x {
93 TokenTree::Ident(_) => true,
94 _ => false,
95 }).last().unwrap().to_string();
96
97 let output = quote! {
98 #[derive(Deserialize, Serialize, PartialEq, Eq, Clone, Debug, Default)]
99 #input
100 };
101 let mut out_as_string = output.to_string();
102 let jvm_params = metadata.to_string().replace(" ", "");
103 let jvm_params: Vec<&str> = jvm_params.split(',').collect();
104
105 let mut get_body = String::new();
106 get_body.push_str("{ match field \n\r{");
107 for (field, _datatype) in &struct_props {
108 get_body.push_str(&format!(
109 "\"{field}\" => &(s.{field}) as &dyn std::any::Any,\n\r",
110 field=field
111 ));
112 }
113 get_body.push_str("_ => panic!(\"Invalid field.\"), }}");
114
115 let mut set_body = String::new();
116 set_body.push_str("match field {");
117 for (field,datatype) in &struct_props {
118 set_body.push_str(&format!("
119 \"{field}\" => {{ s.{field} = ((&val as &dyn std::any::Any).downcast_ref::<{datatype}>().unwrap()).to_owned(); }},\r\n",
120 field=field,
121 datatype=datatype
122 ));
123
124 }
125 set_body.push_str("_ => { panic!(\"invalid field\"); } }");
126
127 let mut struct_props_as_string = String::from("[");
128 let mut idx = 0;
129 for (key, value) in &struct_props {
130 struct_props_as_string.push_str(&format!("(\"{}\".to_string(), \"{}\".to_string(), {}),", key, value, idx));
131 idx += 1;
132 }
133 struct_props_as_string.remove(struct_props_as_string.len()-1);
134 struct_props_as_string.push_str("].iter().cloned().collect()");
135
136 let mut items = String::new();
137 let mut string_of_get_items = String::new();
138 let mut count = 1;
139 for inner in inner_types {
140 string_of_get_items.push_str(&format!(" #[inline]\nfn get_item{}(&self) -> Option<&Self::Item{}> ", count, count));
141 string_of_get_items.push_str("{");
142 string_of_get_items.push_str(&format!(" Some(&self.{}) ", inner.0));
143 string_of_get_items.push_str("}\n");
144
145 items.push_str(&format!(" type Item{} = {};\n ", count, inner.1));
146
147 count += 1;
148 }
149 for i in count..6 {
150 string_of_get_items.push_str(&format!(" #[inline]\nfn get_item{}(&self) -> Option<&Self::Item{}> ", i, i));
151 string_of_get_items.push_str("{ None }\n");
152 items.push_str(&format!(" type Item{} = {}; \n ", i, &struct_name));
153 }
154
155
156 let impl_value = r#"
157 impl Serializable for {{struct_name}} {
158
159 {{items}}
160
161 #[inline]
162 fn java_class_name (&self) -> String {
163 "{{jvm_class}}".to_string()
164 }
165
166 #[inline]
167 fn serial_version_uid(&self) -> u64 {
168 {{jvm_uid}}
169 }
170
171 #[inline]
172 fn get_field<T: std::any::Any + Clone + 'static>(s: &Self, field: &str) -> T {{
173 let a : &dyn std::any::Any = {{get_body}};
174 (a.downcast_ref::<T>().unwrap().clone())
175 }}
176
177 #[inline]
178 fn set_field<T: std::any::Any + Clone + 'static>(s: &mut Self, field: &str, val : T) {{
179 {{set_body}}
180 }}
181
182 #[inline]
183 fn get_fields(&self) -> Vec<(String, String, i32)> {
184 {{fields_string}}
185 }
186
187 {{get_items}}
188
189 }"#;
190 out_as_string.push_str(&impl_value.replace("{{struct_name}}", &struct_name)
191 .replace("{{jvm_class}}", &jvm_params[0])
192 .replace("{{jvm_uid}}", &jvm_params[1])
193 .replace("{{set_body}}", &set_body)
194 .replace("{{get_body}}", &get_body)
195 .replace("{{fields_string}}", &struct_props_as_string)
196 .replace("{{get_items}}", &string_of_get_items)
197 .replace("{{items}}", &items)
198 );
199 proc_macro::TokenStream::from_str(&out_as_string).unwrap()
200}