better global state structure?
This commit is contained in:
@@ -2,10 +2,11 @@ extern crate proc_macro;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
Attribute, Block, Error, GenericParam, Generics, Ident, ItemTrait, Signature, Token,
|
||||
Visibility,
|
||||
Attribute, Block, Error, Fields, FieldsNamed, GenericParam, Generics, Ident, ItemStruct,
|
||||
ItemTrait, Meta, Signature, Token, Visibility,
|
||||
parse::{Parse, ParseStream, Result},
|
||||
parse_macro_input, parse_quote,
|
||||
spanned::Spanned,
|
||||
};
|
||||
|
||||
struct Input {
|
||||
@@ -94,3 +95,86 @@ pub fn widget_trait(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(UiState, attributes(rsc))]
|
||||
pub fn derive_ui_state(input: TokenStream) -> TokenStream {
|
||||
let mut output = proc_macro2::TokenStream::new();
|
||||
|
||||
let state: ItemStruct = parse_macro_input!(input);
|
||||
let sname = state.ident;
|
||||
let rscname = Ident::new(&(sname.to_string() + "Rsc"), sname.span());
|
||||
let mut rsc_fields = Vec::new();
|
||||
|
||||
for field in state.fields {
|
||||
let Some(attr) = field.attrs.iter().find(|a| a.path().is_ident("rsc")) else {
|
||||
continue;
|
||||
};
|
||||
let Meta::List(list) = &attr.meta else {
|
||||
output.extend(Error::new(attr.span(), "invalid attr syntax").into_compile_error());
|
||||
continue;
|
||||
};
|
||||
let tname: Ident = match list.parse_args::<Ident>() {
|
||||
Ok(ident) => ident,
|
||||
Err(err) => {
|
||||
output.extend(err.to_compile_error());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let fty = &field.ty;
|
||||
let fname = &field.ident.unwrap();
|
||||
rsc_fields.extend(quote! {#fname: #fty,});
|
||||
output.extend(quote! {
|
||||
impl #tname for #sname {
|
||||
fn get(&self) -> &#fty {
|
||||
&self.#fname
|
||||
}
|
||||
fn get_mut(&mut self) -> &mut #fty {
|
||||
&mut self.#fname
|
||||
}
|
||||
}
|
||||
impl #tname for #rscname {
|
||||
fn get(&self) -> &#fty {
|
||||
&self.#fname
|
||||
}
|
||||
fn get_mut(&mut self) -> &mut #fty {
|
||||
&mut self.#fname
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
let vis = state.vis;
|
||||
output.extend(quote! {
|
||||
#vis struct #rscname {
|
||||
#(#rsc_fields)*
|
||||
}
|
||||
|
||||
impl HasState for #sname {
|
||||
type State = #sname;
|
||||
}
|
||||
|
||||
impl HasState for #rscname {
|
||||
type State = #sname;
|
||||
}
|
||||
});
|
||||
output.into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn default_ui_state(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut state: ItemStruct = parse_macro_input!(input);
|
||||
let Fields::Named(fields) = &mut state.fields else {
|
||||
panic!("must be on named fields struct");
|
||||
};
|
||||
let name = &state.ident;
|
||||
state.attrs.push(parse_quote! {#[derive(UiState)]});
|
||||
let new: FieldsNamed = parse_quote! {{
|
||||
#[rsc(HasUi)]
|
||||
pub ui: Ui,
|
||||
#[rsc(HasDefaultUiState)]
|
||||
pub ui_state: DefaultUiState,
|
||||
#[rsc(HasEvents)]
|
||||
pub events: iris::prelude::EventManager<#name>,
|
||||
}};
|
||||
fields.named.extend(new.named);
|
||||
quote! {#state}.into()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user