diff --git a/Cargo.toml b/Cargo.toml index 4daaeb2..607b673 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "osui-element" -version = "0.1.14" +version = "0.1.15" edition = "2021" description = "The element attribute for defining elements in OSUI" license = "Apache-2.0" @@ -9,6 +9,10 @@ license = "Apache-2.0" proc-macro = true path = "./lib.rs" +[[bin]] +name = "osui-element" +path = "./main.rs" + [dependencies] proc-macro2 = "1.0.89" quote = "1.0" diff --git a/lib.rs b/lib.rs index 29e98bf..e5103c1 100644 --- a/lib.rs +++ b/lib.rs @@ -1,7 +1,8 @@ use proc_macro::TokenStream; use quote::quote; use syn::{ - parse::Parser, parse_macro_input, DeriveInput, Fields, GenericParam, Lifetime, LifetimeParam, + parse::Parser, parse_macro_input, DeriveInput, Fields, GenericParam, ItemFn, Lifetime, + LifetimeParam, }; #[proc_macro_attribute] @@ -112,3 +113,46 @@ pub fn elem_fn(_args: TokenStream, input: TokenStream) -> TokenStream { expanded.into() } + +#[proc_macro_attribute] +pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream { + let input_fn = parse_macro_input!(input as ItemFn); + + let fn_name = input_fn.sig.ident.clone(); + let code = input_fn.block; + let visibility = input_fn.vis; + let return_type = match input_fn.sig.output { + syn::ReturnType::Default => syn::parse_quote! { Element }, + syn::ReturnType::Type(_, t) => t, + }; + + let struct_fields = input_fn.sig.inputs.iter().filter_map(|arg| { + if let syn::FnArg::Typed(pat_type) = arg { + if let syn::Pat::Ident(pat_ident) = *pat_type.pat.clone() { + let field_name = pat_ident.ident; + let field_type = pat_type.ty.clone(); + Some(quote! { pub #field_name: #field_type }) + } else { + None + } + } else { + None + } + }); + + let expanded = quote! { + #[derive(Debug)] + #[allow(non_camel_case_types)] + #visibility struct #fn_name { + #(#struct_fields),* + } + + impl #fn_name { + pub fn create_element(&self) -> #return_type { + #code + } + } + }; + + TokenStream::from(expanded) +}