79 lines
2.3 KiB
Rust
79 lines
2.3 KiB
Rust
use proc_macro::TokenStream;
|
|
use quote::quote;
|
|
use syn::{
|
|
parse::Parser, parse_macro_input, DeriveInput, Fields, GenericParam, Lifetime, LifetimeParam,
|
|
};
|
|
|
|
#[proc_macro_attribute]
|
|
pub fn element(_args: TokenStream, input: TokenStream) -> TokenStream {
|
|
let mut ast = parse_macro_input!(input as DeriveInput);
|
|
|
|
// Add a lifetime if none exists
|
|
if ast.generics.lifetimes().count() == 0 {
|
|
ast.generics
|
|
.params
|
|
.push(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 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"),
|
|
}
|
|
|
|
let expanded = quote! {
|
|
#ast
|
|
};
|
|
|
|
expanded.into()
|
|
}
|
|
|
|
#[proc_macro_attribute]
|
|
pub fn elem_fn(_args: TokenStream, input: TokenStream) -> TokenStream {
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
let struct_name = &ast.ident;
|
|
let func_name = syn::Ident::new(
|
|
&struct_name.to_string().to_lowercase(),
|
|
proc_macro2::Span::call_site(),
|
|
);
|
|
|
|
let elem_fn = quote! {
|
|
pub fn #func_name<'a, T>() -> Box<#struct_name<'a, T>> {
|
|
Box::new(#struct_name::default())
|
|
}
|
|
};
|
|
|
|
let expanded = quote! {
|
|
#ast
|
|
#elem_fn
|
|
};
|
|
|
|
expanded.into()
|
|
}
|