summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-09-21 19:26:45 +0200
committerHampusM <hampus@hampusmat.com>2026-09-21 19:26:45 +0200
commit7a1f851b4d10912ac645b7167535c2c4d5345802 (patch)
treec080d07a4d4fa7d7107a15f2633a80ba93ffd158
parent7b7e0185af076cfc62914c9e2950709ad2925aa0 (diff)
refactor(engine-macros): fix clippy lints
-rw-r--r--engine-macros/src/reflection.rs20
-rw-r--r--engine-macros/src/reflection/enum_impl.rs334
-rw-r--r--engine-macros/src/reflection/field.rs4
-rw-r--r--engine-macros/src/reflection/options_attr.rs6
-rw-r--r--engine-macros/src/reflection/struct_impl.rs165
-rw-r--r--engine-macros/src/util.rs2
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();