diff options
| author | HampusM <hampus@hampusmat.com> | 2026-09-21 19:26:45 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-09-21 19:26:45 +0200 |
| commit | 7a1f851b4d10912ac645b7167535c2c4d5345802 (patch) | |
| tree | c080d07a4d4fa7d7107a15f2633a80ba93ffd158 | |
| parent | 7b7e0185af076cfc62914c9e2950709ad2925aa0 (diff) | |
refactor(engine-macros): fix clippy lints
| -rw-r--r-- | engine-macros/src/reflection.rs | 20 | ||||
| -rw-r--r-- | engine-macros/src/reflection/enum_impl.rs | 334 | ||||
| -rw-r--r-- | engine-macros/src/reflection/field.rs | 4 | ||||
| -rw-r--r-- | engine-macros/src/reflection/options_attr.rs | 6 | ||||
| -rw-r--r-- | engine-macros/src/reflection/struct_impl.rs | 165 | ||||
| -rw-r--r-- | engine-macros/src/util.rs | 2 |
6 files changed, 290 insertions, 241 deletions
diff --git a/engine-macros/src/reflection.rs b/engine-macros/src/reflection.rs index 2180084..ad1df04 100644 --- a/engine-macros/src/reflection.rs +++ b/engine-macros/src/reflection.rs @@ -14,8 +14,8 @@ pub fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream let options = get_options(&input); match input { - syn::Item::Struct(input) => struct_impl::generate(input, options), - syn::Item::Enum(input) => enum_impl::generate(input, options), + syn::Item::Struct(input) => struct_impl::generate(&input, &options), + syn::Item::Enum(input) => enum_impl::generate(&input, &options), _ => panic!("Invalid input"), } } @@ -57,17 +57,19 @@ pub fn get_options(input: &syn::Item) -> OptionsAttr } }; - if options.impl_with_generics.is_empty() && !generic_params.is_empty() { - panic!(concat!( + assert!( + !options.impl_with_generics.is_empty() || generic_params.is_empty(), + concat!( "Generic types deriving Reflection must specify which ", "generics to use in the generated impl(s) using the 'reflection' attribute\n", "For example: #[reflection(impl_with_generics(<u32, String>, <u8, u16>))]" - )); - } + ) + ); - if !options.impl_with_generics.is_empty() && generic_params.is_empty() { - panic!("Specifying 'impl_with_generics' for non-generic types is not allowed"); - } + assert!( + options.impl_with_generics.is_empty() || !generic_params.is_empty(), + "Specifying 'impl_with_generics' for non-generic types is not allowed" + ); options } diff --git a/engine-macros/src/reflection/enum_impl.rs b/engine-macros/src/reflection/enum_impl.rs index 14d91a7..96efd71 100644 --- a/engine-macros/src/reflection/enum_impl.rs +++ b/engine-macros/src/reflection/enum_impl.rs @@ -1,10 +1,12 @@ +use proc_macro2::TokenStream; use quote::{format_ident, quote}; use crate::reflection::default_value::gen_get_default_value_fn; use crate::reflection::options_attr::OptionsAttr; use crate::util::find_engine_crate_path; -pub fn generate(input: syn::ItemEnum, options: OptionsAttr) -> proc_macro2::TokenStream +pub fn generate(input: &syn::ItemEnum, options: &OptionsAttr) + -> proc_macro2::TokenStream { let engine_crate_path = find_engine_crate_path().unwrap(); @@ -35,7 +37,7 @@ pub fn generate(input: syn::ItemEnum, options: OptionsAttr) -> proc_macro2::Toke let impls: &mut dyn Iterator<Item = proc_macro2::TokenStream> = if input.generics.params.is_empty() { &mut [generate_impls( - &input, + input, None, is_unit_only, &variant_lookup_match_arms, @@ -45,7 +47,7 @@ pub fn generate(input: syn::ItemEnum, options: OptionsAttr) -> proc_macro2::Toke } else { &mut options.impl_with_generics.iter().map(|generic_args| { generate_impls( - &input, + input, Some(generic_args), is_unit_only, &variant_lookup_match_arms, @@ -69,7 +71,7 @@ fn generate_impls( { let get_default_value_fn = gen_get_default_value_fn(&input.ident, generic_args); - let variants = generate_variants(&input.variants, &engine_crate_path); + let variants = generate_variants(&input.variants, engine_crate_path); let generics_type_aliases = input .generics @@ -77,9 +79,8 @@ fn generate_impls( .zip( generic_args .iter() - .map(|generic_args| &generic_args.args) - .flatten() - .flat_map(|generic_arg| match generic_arg { + .flat_map(|generic_args| &generic_args.args) + .filter_map(|generic_arg| match generic_arg { syn::GenericArgument::Type(ty) => Some(ty), _ => None, }), @@ -165,43 +166,7 @@ fn generate_variants<'a>( let variant_name = syn::LitStr::new(&variant.ident.to_string(), variant.ident.span()); - let fields = match &variant.fields { - syn::Fields::Unit => quote! { None }, - syn::Fields::Named(named_fields) => { - let fields = named_fields.named.iter().enumerate().map( - |(variant_field_index, variant_field)| { - generate_enum_variant_field( - variant_field, - variant_field_index, - &engine_crate_path, - ) - }, - ); - - quote! { - Some(#engine_crate_path::reflection::EnumVariantFields::Named { - fields: &[#(#fields),*] - }) - } - } - syn::Fields::Unnamed(unnamed_fields) => { - let fields = unnamed_fields.unnamed.iter().enumerate().map( - |(variant_field_index, variant_field)| { - generate_enum_variant_field( - variant_field, - variant_field_index, - &engine_crate_path, - ) - }, - ); - - quote! { - Some(#engine_crate_path::reflection::EnumVariantFields::Unnamed { - fields: &[#(#fields),*] - }) - } - } - }; + let fields = gen_variant_fields(variant, engine_crate_path); let variant_field_vars = variant.fields.iter().enumerate().map( |(variant_field_index, variant_field)| { @@ -227,9 +192,7 @@ fn generate_variants<'a>( syn::Fields::Unit => { let variant_ident = &variant.ident; - quote! { - Self::#variant_ident - } + quote! { Self::#variant_ident } } syn::Fields::Named(named_fields) => { let variant_ident = &variant.ident; @@ -241,9 +204,7 @@ fn generate_variants<'a>( let field_var_ident = format_ident!("field_{field_ident}"); - quote! { - #field_ident: *#field_var_ident - } + quote! { #field_ident: *#field_var_ident } }); quote! { @@ -259,74 +220,20 @@ fn generate_variants<'a>( |(field_index, _)| { let field_var_ident = format_ident!("field_{field_index}"); - quote! { - *#field_var_ident - } + quote! { *#field_var_ident } }, ); quote! { - Self::#variant_ident( - #(#fields),* - ) + Self::#variant_ident(#(#fields),*) } } }; - let variant_ident = &variant.ident; - - let variant_pattern = match &variant.fields { - syn::Fields::Unit => quote! { Self::#variant_ident }, - syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { - let field_idents = named_fields.iter().map(|field| { - let Some(field_ident) = &field.ident else { - unreachable!(); - }; - - field_ident - }); - - quote! { Self::#variant_ident { #(#field_idents),* } } - } - syn::Fields::Unnamed(syn::FieldsUnnamed { - unnamed: unnamed_fields, .. - }) => { - let field_idents = unnamed_fields - .iter() - .enumerate() - .map(|(field_index, _)| format_ident!("field_{field_index}")); - - quote! { Self::#variant_ident(#(#field_idents),*) } - } - }; - - let field_index_match_arms = match &variant.fields { - syn::Fields::Unit => quote! {}, - syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { - let match_arms = - named_fields.iter().enumerate().map(|(field_index, field)| { - let Some(field_ident) = &field.ident else { - unreachable!(); - }; - - quote! { #field_index => { #field_ident } } - }); - - quote! { #(#match_arms)* } - } - syn::Fields::Unnamed(syn::FieldsUnnamed { - unnamed: unnamed_fields, .. - }) => { - let match_arms = - unnamed_fields.iter().enumerate().map(|(field_index, _)| { - let field_ident = format_ident!("field_{field_index}"); - - quote! { #field_index => { #field_ident } } - }); - - quote! { #(#match_arms)* } - } - }; + let VariantTryGetFieldFns { + immutable: try_get_field_immutable_fn, + mutable: try_get_field_mutable_fn, + } = gen_variant_try_get_field_functions(variant, engine_crate_path); quote! { #engine_crate_path::reflection::EnumVariant { @@ -352,52 +259,8 @@ fn generate_variants<'a>( Ok(()) }, - try_get_field: |target, field_index| { { - #![allow(unreachable_code)] - - use std::any::Any; - use #engine_crate_path::reflection::GetError; - - let target = target - .downcast_ref::<Self>() - .ok_or(GetError::WrongTargetType)?; - - let #variant_pattern = target else { - return Err(GetError::WrongTargetEnumVariant); - }; - - let field: &dyn Any = match field_index { - #field_index_match_arms - _ => { - return Err(GetError::IndexOutOfBounds); - } - }; - - Ok(field) - } }, - try_get_field_mut: |target, field_index| { { - #![allow(unreachable_code)] - - use std::any::Any; - use #engine_crate_path::reflection::GetError; - - let target = target - .downcast_mut::<Self>() - .ok_or(GetError::WrongTargetType)?; - - let #variant_pattern = target else { - return Err(GetError::WrongTargetEnumVariant); - }; - - let field: &mut dyn Any = match field_index { - #field_index_match_arms - _ => { - return Err(GetError::IndexOutOfBounds); - } - }; - - Ok(field) - } }, + try_get_field: #try_get_field_immutable_fn, + try_get_field_mut: #try_get_field_mutable_fn, } } }) @@ -483,3 +346,162 @@ fn gen_get_optional_type_reflection( .field_type_reflection() } } + +fn gen_variant_fields( + variant: &syn::Variant, + engine_crate_path: &syn::Path, +) -> TokenStream +{ + match &variant.fields { + syn::Fields::Unit => quote! { None }, + syn::Fields::Named(named_fields) => { + let fields = named_fields.named.iter().enumerate().map( + |(variant_field_index, variant_field)| { + generate_enum_variant_field( + variant_field, + variant_field_index, + engine_crate_path, + ) + }, + ); + + quote! { + Some(#engine_crate_path::reflection::EnumVariantFields::Named { + fields: &[#(#fields),*] + }) + } + } + syn::Fields::Unnamed(unnamed_fields) => { + let fields = unnamed_fields.unnamed.iter().enumerate().map( + |(variant_field_index, variant_field)| { + generate_enum_variant_field( + variant_field, + variant_field_index, + engine_crate_path, + ) + }, + ); + + quote! { + Some(#engine_crate_path::reflection::EnumVariantFields::Unnamed { + fields: &[#(#fields),*] + }) + } + } + } +} + +struct VariantTryGetFieldFns +{ + immutable: TokenStream, + mutable: TokenStream, +} + +fn gen_variant_try_get_field_functions( + variant: &syn::Variant, + engine_crate_path: &syn::Path, +) -> VariantTryGetFieldFns +{ + let field_index_match_arms = match &variant.fields { + syn::Fields::Unit => quote! {}, + syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { + let match_arms = + named_fields.iter().enumerate().map(|(field_index, field)| { + let Some(field_ident) = &field.ident else { + unreachable!(); + }; + + quote! { #field_index => { #field_ident } } + }); + + quote! { #(#match_arms)* } + } + syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed: unnamed_fields, .. }) => { + let match_arms = unnamed_fields.iter().enumerate().map(|(field_index, _)| { + let field_ident = format_ident!("field_{field_index}"); + + quote! { #field_index => { #field_ident } } + }); + + quote! { #(#match_arms)* } + } + }; + + let variant_ident = &variant.ident; + + let variant_pattern = match &variant.fields { + syn::Fields::Unit => quote! { Self::#variant_ident }, + syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { + let field_idents = named_fields.iter().map(|field| { + let Some(field_ident) = &field.ident else { + unreachable!(); + }; + + field_ident + }); + + quote! { Self::#variant_ident { #(#field_idents),* } } + } + syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed: unnamed_fields, .. }) => { + let field_idents = unnamed_fields + .iter() + .enumerate() + .map(|(field_index, _)| format_ident!("field_{field_index}")); + + quote! { Self::#variant_ident(#(#field_idents),*) } + } + }; + + VariantTryGetFieldFns { + immutable: quote! { + |target, field_index| { { + #![allow(unreachable_code)] + + use std::any::Any; + use #engine_crate_path::reflection::GetError; + + let target = target + .downcast_ref::<Self>() + .ok_or(GetError::WrongTargetType)?; + + let #variant_pattern = target else { + return Err(GetError::WrongTargetEnumVariant); + }; + + let field: &dyn Any = match field_index { + #field_index_match_arms + _ => { + return Err(GetError::IndexOutOfBounds); + } + }; + + Ok(field) + } } + }, + mutable: quote! { + |target, field_index| { { + #![allow(unreachable_code)] + + use std::any::Any; + use #engine_crate_path::reflection::GetError; + + let target = target + .downcast_mut::<Self>() + .ok_or(GetError::WrongTargetType)?; + + let #variant_pattern = target else { + return Err(GetError::WrongTargetEnumVariant); + }; + + let field: &mut dyn Any = match field_index { + #field_index_match_arms + _ => { + return Err(GetError::IndexOutOfBounds); + } + }; + + Ok(field) + } } + }, + } +} diff --git a/engine-macros/src/reflection/field.rs b/engine-macros/src/reflection/field.rs index 7c50f47..105a35b 100644 --- a/engine-macros/src/reflection/field.rs +++ b/engine-macros/src/reflection/field.rs @@ -12,7 +12,7 @@ pub fn generate( field: &syn::Field, field_index: usize, engine_crate_path: &syn::Path, - options: ReflectionFieldGenOptions<'_>, + options: &ReflectionFieldGenOptions<'_>, ) -> proc_macro2::TokenStream { let field_ident = &field.ident; @@ -31,7 +31,7 @@ pub fn generate( let field_vis = options.field_vis_override.as_ref().unwrap_or(&field.vis); - let field_reflection_vis = generate_visibility(field_vis, &engine_crate_path); + let field_reflection_vis = generate_visibility(field_vis, engine_crate_path); let get_type_fn_body = { gen_get_optional_type_reflection(field_type, engine_crate_path) }; diff --git a/engine-macros/src/reflection/options_attr.rs b/engine-macros/src/reflection/options_attr.rs index 231b969..6fc2eea 100644 --- a/engine-macros/src/reflection/options_attr.rs +++ b/engine-macros/src/reflection/options_attr.rs @@ -9,8 +9,10 @@ impl syn::parse::Parse for OptionsAttr { fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let params = - input.parse_terminated(|param| param.parse::<syn::Meta>(), syn::Token![,])?; + let params = input.parse_terminated( + syn::parse::ParseBuffer::parse::<syn::Meta>, + syn::Token![,], + )?; let mut impl_with_generics = syn::punctuated::Punctuated::new(); diff --git a/engine-macros/src/reflection/struct_impl.rs b/engine-macros/src/reflection/struct_impl.rs index 0ba426d..27d62ba 100644 --- a/engine-macros/src/reflection/struct_impl.rs +++ b/engine-macros/src/reflection/struct_impl.rs @@ -1,3 +1,4 @@ +use proc_macro2::TokenStream; use quote::{format_ident, quote}; use crate::reflection::default_value::gen_get_default_value_fn; @@ -5,19 +6,21 @@ use crate::reflection::field::{generate as generate_field, ReflectionFieldGenOpt use crate::reflection::options_attr::OptionsAttr; use crate::util::find_engine_crate_path; -pub fn generate(input: syn::ItemStruct, options: OptionsAttr) - -> proc_macro2::TokenStream +pub fn generate( + input: &syn::ItemStruct, + options: &OptionsAttr, +) -> proc_macro2::TokenStream { let engine_crate_path = find_engine_crate_path().unwrap(); if input.generics.params.is_empty() { - return gen_impl(&input, None, &engine_crate_path); + return gen_impl(input, None, &engine_crate_path); } let impls = options .impl_with_generics - .into_iter() - .map(|generic_args| gen_impl(&input, Some(&generic_args), &engine_crate_path)); + .iter() + .map(|generic_args| gen_impl(input, Some(generic_args), &engine_crate_path)); quote! { #(#impls)* @@ -32,10 +35,10 @@ fn gen_impl( { let fields = input.fields.iter().enumerate().map(|(field_index, field)| { generate_field( - &field, + field, field_index, - &engine_crate_path, - ReflectionFieldGenOptions { + engine_crate_path, + &ReflectionFieldGenOptions { field_vis_override: None, gen_get_byte_offset: &|field| { if let Some(field_ident) = &field.ident { @@ -58,9 +61,8 @@ fn gen_impl( .zip( generic_args .iter() - .map(|generic_args| &generic_args.args) - .flatten() - .flat_map(|generic_arg| match generic_arg { + .flat_map(|generic_args| &generic_args.args) + .filter_map(|generic_arg| match generic_arg { syn::GenericArgument::Type(ty) => Some(ty), _ => None, }), @@ -68,11 +70,52 @@ fn gen_impl( .map(|(type_param, generic_arg_type)| { let type_param_ident = &type_param.ident; - quote! { - type #type_param_ident = #generic_arg_type; - } + quote! { type #type_param_ident = #generic_arg_type; } }); + let TryGetFieldFns { + immutable: try_get_field_immutable_fn, + mutable: try_get_field_mutable_fn, + } = gen_try_get_field_functions(input); + + quote! { + unsafe impl #engine_crate_path::reflection::Reflection for + #input_ident #generic_args + { + const TYPE_REFLECTION: &#engine_crate_path::reflection::Type = + &const { + use std::any::Any; + + use #engine_crate_path::reflection::GetError; + + #(#generics_type_aliases)* + + #engine_crate_path::reflection::Type::Struct( + #engine_crate_path::reflection::Struct { + fields: &[ + #(#fields),* + ], + get_default_value: || { + #get_default_value_fn + }, + cast_dyn_any: |ptr| ptr.cast::<Self>(), + try_get_field: #try_get_field_immutable_fn, + try_get_field_mut: #try_get_field_mutable_fn, + } + ) + }; + } + } +} + +struct TryGetFieldFns +{ + immutable: TokenStream, + mutable: TokenStream, +} + +fn gen_try_get_field_functions(input: &syn::ItemStruct) -> TryGetFieldFns +{ let struct_pattern = match &input.fields { syn::Fields::Unit => quote! { Self }, syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { @@ -121,66 +164,46 @@ fn gen_impl( } }; - quote! { - unsafe impl #engine_crate_path::reflection::Reflection for - #input_ident #generic_args - { - const TYPE_REFLECTION: &#engine_crate_path::reflection::Type = - &const { - use std::any::Any; + TryGetFieldFns { + immutable: quote! { + |target, field_index| { { + #![allow(unreachable_code)] - use #engine_crate_path::reflection::GetError; + let target = target + .downcast_ref::<Self>() + .ok_or(GetError::WrongTargetType)?; - #(#generics_type_aliases)* + let #struct_pattern = target; - #engine_crate_path::reflection::Type::Struct( - #engine_crate_path::reflection::Struct { - fields: &[ - #(#fields),* - ], - get_default_value: || { - #get_default_value_fn - }, - cast_dyn_any: |ptr| ptr.cast::<Self>(), - try_get_field: |target, field_index| { { - #![allow(unreachable_code)] - - let target = target - .downcast_ref::<Self>() - .ok_or(GetError::WrongTargetType)?; - - let #struct_pattern = target; - - let field: &dyn Any = match field_index { - #field_index_match_arms - _ => { - return Err(GetError::IndexOutOfBounds); - } - }; - - Ok(field) - } }, - try_get_field_mut: |target, field_index| { { - #![allow(unreachable_code)] - - let target = target - .downcast_mut::<Self>() - .ok_or(GetError::WrongTargetType)?; - - let #struct_pattern = target; - - let field: &mut dyn Any = match field_index { - #field_index_match_arms - _ => { - return Err(GetError::IndexOutOfBounds); - } - }; - - Ok(field) - } }, - } - ) + let field: &dyn Any = match field_index { + #field_index_match_arms + _ => { + return Err(GetError::IndexOutOfBounds); + } }; - } + + Ok(field) + } } + }, + mutable: quote! { + |target, field_index| { { + #![allow(unreachable_code)] + + let target = target + .downcast_mut::<Self>() + .ok_or(GetError::WrongTargetType)?; + + let #struct_pattern = target; + + let field: &mut dyn Any = match field_index { + #field_index_match_arms + _ => { + return Err(GetError::IndexOutOfBounds); + } + }; + + Ok(field) + } } + }, } } diff --git a/engine-macros/src/util.rs b/engine-macros/src/util.rs index 515b066..dbeb042 100644 --- a/engine-macros/src/util.rs +++ b/engine-macros/src/util.rs @@ -54,7 +54,7 @@ pub fn syn_path_to_string(path: &syn::Path) -> String for (segment, punct) in path.segments.pairs().map(syn::punctuated::Pair::into_tuple) { let segment_ident = &segment.ident; - write!(output, "{segment_ident}",).unwrap(); + write!(output, "{segment_ident}").unwrap(); if let Some(punct) = punct { write!(output, "{}", punct.to_token_stream()).unwrap(); |
