Game stats that reset every frame, inspired by immediate mode GUI.
gamedev bevy stats
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Replaced `reset_fields` with `reset_field` singular.

This is more reusable for enums.

+28 -26
+28 -26
immediate_stats_macros/src/lib.rs
··· 2 2 mod bevy_butler; 3 3 4 4 use darling::{Error, FromField}; 5 + use proc_macro2::{Span, TokenStream}; 5 6 use proc_macro_error::{ 6 7 emit_call_site_error, emit_call_site_warning, emit_warning, proc_macro_error, 7 8 }; 8 - use proc_macro2::{Span, TokenStream}; 9 - use quote::{ToTokens, quote}; 9 + use quote::{quote, ToTokens}; 10 10 use syn::spanned::Spanned; 11 - use syn::{Data, DataEnum, DeriveInput, Field, Fields, Ident, Index, parse_macro_input}; 11 + use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Field, Ident, Index}; 12 12 13 13 #[proc_macro_derive(StatContainer, attributes(stat, stat_ignore, add_component))] 14 14 #[proc_macro_error] ··· 18 18 let struct_name = &tree.ident; 19 19 20 20 let method_contents = match tree.data.clone() { 21 - Data::Struct(s) => reset_fields(&s.fields).unwrap_or_else(Error::write_errors), 21 + Data::Struct(s) => { 22 + s.fields.iter().enumerate().map(|(index, field)| { 23 + reset_field(field, index).unwrap_or_else(Error::write_errors) 24 + }).flatten().collect() 25 + }, 22 26 Data::Enum(e) => stat_container_enum(e), 23 27 Data::Union(_) => { 24 28 emit_call_site_error!("This trait cannot be derived from unions."); ··· 80 84 } 81 85 } 82 86 83 - /// Returns the code needed to reset any stat fields. 84 - fn reset_fields(fields: &Fields) -> darling::Result<TokenStream> { 85 - for (index, field) in fields.iter().enumerate() { 86 - let options = FieldOptions::from_field(&field)?; 87 + /// Returns the code needed to reset a field. `index` is used for tuple fields. 88 + fn reset_field(field: &Field, index: usize) -> darling::Result<TokenStream> { 89 + let options = FieldOptions::from_field(&field)?; 87 90 88 - if (options.include || options.stat_type) && !options.exclude { 89 - return Ok(match options.ident { 90 - Some(ident) => { 91 - quote! { self.#ident.reset_modifiers(); } 92 - } 93 - None => { 94 - let index = Index::from(index); 95 - quote! { self.#index.reset_modifiers(); } 96 - } 97 - }); 98 - } 99 - 100 - if options.include && options.exclude { 101 - emit_warning!( 102 - field.span(), 103 - "`stat` attribute is overruled by `stat_ignore` attribute." 104 - ); 105 - } 91 + if (options.include || options.stat_type) && !options.exclude { 92 + return Ok(match options.ident { 93 + Some(ident) => { 94 + quote! { self.#ident.reset_modifiers(); } 95 + } 96 + None => { 97 + let index = Index::from(index); 98 + quote! { self.#index.reset_modifiers(); } 99 + } 100 + }); 106 101 } 107 102 103 + if options.include && options.exclude { 104 + emit_warning!( 105 + field.span(), 106 + "`stat` attribute is overruled by `stat_ignore` attribute." 107 + ); 108 + } 109 + 108 110 Ok(TokenStream::new()) 109 111 } 110 112