some changes

This commit is contained in:
2024-12-23 11:58:21 +01:00
parent 2f1f2b3395
commit cee73fb885
2 changed files with 28 additions and 104 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "osui-element" name = "osui-element"
version = "0.1.17" version = "0.1.19"
edition = "2021" edition = "2021"
description = "The element attribute for defining elements in OSUI" description = "The element attribute for defining elements in OSUI"
license = "Apache-2.0" license = "Apache-2.0"
+27 -103
View File
@@ -1,94 +1,7 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote; use quote::quote;
use syn::{ use syn::{parse_macro_input, FnArg, ItemFn, Lifetime, PatIdent, PatType, Type, TypeReference};
parse::Parser, parse_macro_input, DeriveInput, Fields, GenericParam, ItemFn,
Lifetime, LifetimeParam,
};
#[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(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"),
}
// 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] #[proc_macro_attribute]
pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream {
@@ -101,30 +14,41 @@ pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream {
syn::ReturnType::Default => syn::parse_quote! { Element }, syn::ReturnType::Default => syn::parse_quote! { Element },
syn::ReturnType::Type(_, t) => t, syn::ReturnType::Type(_, t) => t,
}; };
let mut fn_lifetime = false;
let struct_fields = input_fn.sig.inputs.iter().filter_map(|arg| { let mut struct_fields = Vec::new();
if let syn::FnArg::Typed(pat_type) = arg {
if let syn::Pat::Ident(pat_ident) = *pat_type.pat.clone() { for arg in input_fn.sig.inputs.iter() {
let field_name = pat_ident.ident; if let FnArg::Typed(PatType { pat, ty, .. }) = arg {
let field_type = pat_type.ty.clone(); if let syn::Pat::Ident(PatIdent { ident, .. }) = &**pat {
Some(quote! { pub #field_name: #field_type }) let field_name = ident.clone();
} else { let mut field_type = *(ty.clone());
None
if let Type::Reference(TypeReference { lifetime, .. }) = &mut field_type {
fn_lifetime = true;
*lifetime = Some(Lifetime::new("'a", Span::call_site()));
} }
} else {
None struct_fields.push(quote! { pub #field_name: #field_type });
} }
}); }
}
let lifetime = if fn_lifetime {
quote! {<'a>}
} else {
quote! {}
};
let expanded = quote! { let expanded = quote! {
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#visibility struct #fn_name { #visibility struct #fn_name #lifetime {
#(#struct_fields),* #(#struct_fields),*
} }
impl Component for #fn_name { impl #lifetime #fn_name #lifetime {
fn create_element(&self) -> #return_type { fn create_element(self) -> #return_type {
#code #code
} }
} }