some changes
This commit is contained in:
@@ -1,7 +1,94 @@
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, FnArg, ItemFn, Lifetime, PatIdent, PatType, Type, TypeReference};
|
||||
use syn::{
|
||||
parse::Parser, parse_macro_input, DeriveInput, FnArg, ItemFn, Lifetime, LifetimeParam,
|
||||
PatIdent, PatType, Type, TypeReference,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn element(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut ast = parse_macro_input!(input as DeriveInput);
|
||||
let struct_name = &ast.ident;
|
||||
|
||||
// Check if the struct has generics
|
||||
let has_generics = !ast.generics.params.is_empty();
|
||||
|
||||
// If there are no generics, add a lifetime (if necessary)
|
||||
if ast.generics.lifetimes().count() == 0 && !has_generics {
|
||||
ast.generics
|
||||
.params
|
||||
.push(syn::GenericParam::Lifetime(LifetimeParam::new(
|
||||
Lifetime::new("'a", proc_macro2::Span::call_site()),
|
||||
)));
|
||||
}
|
||||
|
||||
// Modify the struct fields to include additional fields
|
||||
match &mut ast.data {
|
||||
syn::Data::Struct(ref mut struct_data) => {
|
||||
if let syn::Fields::Named(fields) = &mut struct_data.fields {
|
||||
fields.named.push(
|
||||
syn::Field::parse_named
|
||||
.parse2(quote! { pub children: Children })
|
||||
.unwrap(),
|
||||
);
|
||||
fields.named.push(
|
||||
syn::Field::parse_named
|
||||
.parse2(quote! { pub style: Style })
|
||||
.unwrap(),
|
||||
);
|
||||
fields.named.push(
|
||||
syn::Field::parse_named
|
||||
.parse2(quote! { pub id: &'a str })
|
||||
.unwrap(),
|
||||
);
|
||||
fields.named.push(
|
||||
syn::Field::parse_named
|
||||
.parse2(quote! { pub class: &'a str })
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => panic!("`element` can only be used with structs"),
|
||||
}
|
||||
|
||||
// Generate the impl block with generics if needed
|
||||
let impl_block = quote! {
|
||||
impl<'a> ElementCore for #struct_name<'a> {
|
||||
fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element> {
|
||||
if let Children::Children(children, _) = &mut self.children {
|
||||
for elem in children {
|
||||
if elem.get_id() == id {
|
||||
return Some(elem);
|
||||
} else if let Some(e) = elem.get_element_by_id(id) {
|
||||
return Some(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.to_string()
|
||||
}
|
||||
|
||||
fn get_class(&self) -> String {
|
||||
self.class.to_string()
|
||||
}
|
||||
|
||||
fn get_style(&self) -> &Style {
|
||||
&self.style
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let expanded = quote! {
|
||||
#ast
|
||||
#impl_block
|
||||
};
|
||||
|
||||
expanded.into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
|
||||
Reference in New Issue
Block a user