1use quote::ToTokens;
6use syn::{Data, DataStruct, Fields, Type};
7extern crate proc_macro;
8extern crate syn;
9#[macro_use]
10extern crate quote;
11
12#[proc_macro_derive(MetaDataNode)]
13pub fn derive_md_node(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
14 let input = proc_macro2::TokenStream::from(input);
15
16 let output = derive_md_node_impl(input);
17
18 proc_macro::TokenStream::from(output)
19}
20
21fn derive_md_node_impl(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
22 let ast: syn::DeriveInput = syn::parse2(input).unwrap();
23 let name = ast.ident;
24 quote! {
25 impl MetaDataNode for #name {
26 fn get_metadata(&self) -> &indexmap::IndexMap<String, u32> {
27 &self.metadata
28 }
29
30 fn get_metadata_mut(&mut self) -> &mut indexmap::IndexMap<String, u32> {
31 &mut self.metadata
32 }
33 }
34 }
35}
36
37fn map_fields<F>(fields: &Fields, mapper: F) -> proc_macro2::TokenStream
38where
39 F: FnMut((&proc_macro2::Ident, &Type)) -> proc_macro2::TokenStream,
40{
41 proc_macro2::TokenStream::from_iter(
42 fields
43 .iter()
44 .map(|field| (field.ident.as_ref().unwrap(), &field.ty))
45 .map(mapper),
46 )
47}
48
49#[proc_macro_derive(MetadataDefinition, attributes(MetaDataKey))]
135pub fn derive_md_definition(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
136 let input = proc_macro2::TokenStream::from(input);
137
138 let output = derive_md_definition_impl(input);
139 proc_macro::TokenStream::from(output)
140}
141
142fn derive_md_definition_impl(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
143 let ast: syn::DeriveInput = syn::parse2(input).unwrap();
144
145 let struct_name = ast.ident;
146 let mut meta_data_key = None;
147 for attr in &ast.attrs {
148 if attr.path().is_ident("MetaDataKey") {
149 attr.parse_nested_meta(|meta| match meta.path.get_ident() {
151 Some(id) => {
152 meta_data_key = Some(id.clone());
153 Ok(())
154 }
155 None => Err(syn::Error::new(
156 proc_macro2::Span::call_site(),
157 "expand MetadataDefinition failed: MetaDataKey isn't set",
158 )),
159 })
160 .unwrap();
161 }
162 }
163 match ast.data {
164 Data::Struct(DataStruct { fields, .. }) => {
165 let fields_access = map_fields(&fields, |(ident, ty)| {
166 let getter_name = format_ident!("get_{}", ident);
167 quote!(pub fn #ident(mut self, value: #ty) -> Self {
168 self.#ident = value;
169 self
170 }
171 pub fn #getter_name(&self) -> #ty {
172 self.#ident.clone()
173 }
174 )
175 });
176
177 let fields_to_literals = map_fields(&fields, |(ident, ty)| field_to_literal(ident, ty));
178 let mut fields_count = 0;
179 let literals_to_fields = map_fields(&fields, |(ident, ty)| {
180 let result = literal_to_field(fields_count, ident, ty);
181 fields_count += 1;
182 result
183 });
184 let meta_data_key = meta_data_key
185 .unwrap_or_else(|| {
186 panic!("expand MetadataDefinition failed: MetaDataKey isn't set")
187 })
188 .to_string();
189 let meta_data_key =
190 syn::LitStr::new(meta_data_key.as_str(), proc_macro2::Span::call_site());
191
192 quote!(
193 impl #struct_name {
194 #fields_access
196
197 pub fn from(metadata: &MetaData) -> Result<Self, String> {
198 Ok(Self {
199 #literals_to_fields
200 })
201 }
202
203 pub fn to_metadata(&self) -> MetaData {
204 let mut metadata = MetaData::default();
205 #fields_to_literals
206 metadata
207 }
208
209 pub fn get_metadata_key() -> String {
210 #meta_data_key.to_string()
211 }
212
213 pub fn add_to_context(
214 ctx: &IRContext,
215 md_node: &mut dyn MetaDataNode,
216 loc: &#struct_name,
217 ) {
218 let md_idx = ctx.add_metadata(loc.to_metadata());
219 let metadata = md_node.get_metadata_mut();
220 metadata.insert(#meta_data_key.to_string(), md_idx);
221 }
222 pub fn get_from_context(ctx: &IRContext, md_node: &dyn MetaDataNode) -> Option<#struct_name> {
223 let metadata = md_node.get_metadata();
224 let md_idx = metadata.get(#meta_data_key)?;
225 #struct_name::from(ctx.get_metadata(md_idx).as_ref()?).ok()
226 }
227 }
228 )
229 }
230 _ => panic!(),
231 }
232}
233
234fn field_to_literal(ident: &proc_macro2::Ident, ty: &Type) -> proc_macro2::TokenStream {
235 match ty {
236 Type::Path(val) => {
237 let ty_str = val.path.get_ident().unwrap().to_string();
238 return match ty_str.as_str() {
239 "String" => quote!(
240 metadata.push_field(Literal::Str(self.#ident.clone()));
241 ),
242 "bool" => quote!(
243 metadata.push_field(Literal::Bool(self.#ident));
244 ),
245 "i8" => quote!(
246 metadata.push_field(Literal::Int(IntLiteral::I8(self.#ident)));
247 ),
248 "i16" => quote!(
249 metadata.push_field(Literal::Int(IntLiteral::I16(self.#ident)));
250 ),
251 "i32" => quote!(
252 metadata.push_field(Literal::Int(IntLiteral::I32(self.#ident)));
253 ),
254 "i64" => quote!(
255 metadata.push_field(Literal::Int(IntLiteral::I64(self.#ident)));
256 ),
257 "i128" => quote!(
258 metadata.push_field(Literal::Int(IntLiteral::I128(self.#ident)));
259 ),
260 "u8" => quote!(
261 metadata.push_field(Literal:Int(IntLiteral:::U8(self.#ident)));
262 ),
263 "u16" => quote!(
264 metadata.push_field(Literal::Int(IntLiteral::U16(self.#ident)));
265 ),
266 "u32" => quote!(
267 metadata.push_field(Literal::Int(IntLiteral::U32(self.#ident)));
268 ),
269 "u64" => quote!(
270 metadata.push_field(Literal::Int(IntLiteral::U64(self.#ident)));
271 ),
272 "u128" => quote!(
273 metadata.push_field(Literal::Int(IntLiteral::U128(self.#ident)));
274 ),
275 _ => {
276 let token_stream = ty.to_token_stream();
277 panic!(
278 "{}",
279 format!(
280 "MetadataDefinition expand failed: unsupported field ty: {token_stream}"
281 )
282 )
283 }
284 };
285 }
286 _ => {
287 let token_stream = ty.to_token_stream();
288 panic!(
289 "{}",
290 format!("MetadataDefinition expand failed: unsupported field ty: {token_stream}",)
291 )
292 }
293 }
294}
295
296fn literal_to_field(
297 field_idx: i32,
298 ident: &proc_macro2::Ident,
299 ty: &Type,
300) -> proc_macro2::TokenStream {
301 let field_idx_lit = syn::LitInt::new(
302 field_idx.to_string().as_str(),
303 proc_macro2::Span::call_site(),
304 );
305 match ty {
306 Type::Path(val) => {
307 let ty_str = val.path.get_ident().unwrap().to_string();
308 let result = match ty_str.as_str() {
309 "String" => quote!(
310 #ident: metadata.get_operand(#field_idx_lit).get_string()?,
311 ),
312 "bool" => quote!(
313 #ident: metadata.get_operand(#field_idx_lit).get_bool()?,
314 ),
315 "i8" => quote!(
316 #ident: metadata.get_operand(#field_idx_lit).get_i8()?,
317 ),
318 "i16" => quote!(
319 #ident: metadata.get_operand(#field_idx_lit).get_i16()?,
320 ),
321 "i32" => quote!(
322 #ident: metadata.get_operand(#field_idx_lit).get_i32()?,
323 ),
324 "i64" => quote!(
325 #ident: metadata.get_operand(#field_idx_lit).get_i64()?,
326 ),
327 "i128" => quote!(
328 #ident: metadata.get_operand(#field_idx_lit).get_i128()?,
329 ),
330 "u8" => quote!(
331 #ident: metadata.get_operand(#field_idx_lit).get_u8()?,
332 ),
333 "u16" => quote!(
334 #ident: metadata.get_operand(#field_idx_lit).get_u16()?,
335 ),
336 "u32" => quote!(
337 #ident: metadata.get_operand(#field_idx_lit).get_u32()?,
338 ),
339 "u64" => quote!(
340 #ident: metadata.get_operand(#field_idx_lit).get_u64()?,
341 ),
342 "u128" => quote!(
343 #ident: metadata.get_operand(#field_idx_lit).get_u128()?,
344 ),
345 _ => {
346 let token_stream = ty.to_token_stream();
347 panic!(
348 "{}",
349 format!(
350 "MetadataDefinition expand failed: unsupported field ty: {token_stream}",
351 )
352 )
353 }
354 };
355 result
356 }
357 _ => {
358 let token_stream = ty.to_token_stream();
359 panic!(
360 "{}",
361 format!("MetadataDefinition expand failed: unsupported field ty: {token_stream}")
362 )
363 }
364 }
365}