Skip to content

Derive Macro for MapEntites (#17611) #18311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Wuketuke
Copy link
Contributor

Objective

instead of writing boilerplate like this

impl MapEntities for Foo {
    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
        self.a.map_entities(entity_mapper);
        self.b.map_entities(entity_mapper);
    }
}

users can now use the derive macro MapEntities.
If any fields dont implement that trait, they can be skipped with a #[skip_mapping] attribute.

#[derive(MapEntities)]
struct Foo {
    a: A,
    b: B,
    #[skip_mapping]
    c: C, // C doesnt implement MapEntities, so we need to skip it
}

Fixes #17611

Solution

My implementation is a heavily simplified version of @Liam19's version, as I didnt want to add too much complexity at once, and I am not familiar with that trait. So feedback is appreciated.
Since its possible that people want to derive enums as well, I have put the derive function in its own file, so that it has space to grow

Testing

Theres now an example in the documentation

/// }
///
/// # #[derive(MapEntities)]
/// # struct TestTuple(A);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An extra # here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to eliminate that double newline?

Comment on lines +23 to +26
match &attr.meta {
syn::Meta::Path(_) => continue 'fields,
_ => panic!("just use the bare `#[skip_mapping]`"),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just continue without checking! This is unnessesary code

fn map_struct(name: syn::Ident, fields: &Fields) -> proc_macro2::TokenStream {
let mut map_entities = vec![];

'fields: for (i, field) in fields.iter().enumerate() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'fields: for (i, field) in fields.iter().enumerate() {
for (i, field) in fields.iter().enumerate() {

Comment on lines +23 to +26
match &attr.meta {
syn::Meta::Path(_) => continue 'fields,
_ => panic!("just use the bare `#[skip_mapping]`"),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
match &attr.meta {
syn::Meta::Path(_) => continue 'fields,
_ => panic!("just use the bare `#[skip_mapping]`"),
}
continue

Comment on lines +31 to +44
let map_field = if let Some(field_name) = &field.ident {
// Named field (struct)
quote! {
<#ty as bevy_ecs::entity::MapEntities>::map_entities(&mut self.#field_name, entity_mapper);
}
} else {
// Unnamed field (tuple-like struct)
let idx = syn::Index::from(i);
quote! {
<#ty as bevy_ecs::entity::MapEntities>::map_entities(&mut self.#idx, entity_mapper);
}
};

map_entities.push(map_field);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let map_field = if let Some(field_name) = &field.ident {
// Named field (struct)
quote! {
<#ty as bevy_ecs::entity::MapEntities>::map_entities(&mut self.#field_name, entity_mapper);
}
} else {
// Unnamed field (tuple-like struct)
let idx = syn::Index::from(i);
quote! {
<#ty as bevy_ecs::entity::MapEntities>::map_entities(&mut self.#idx, entity_mapper);
}
};
map_entities.push(map_field);
let member = as_member(&field.ident, i);
map_entities.push(quote! {
<#ty as bevy_ecs::entity::MapEntities>::map_entities(&mut self.#member, entity_mapper);
});

@Bleachfuel Bleachfuel mentioned this pull request Mar 16, 2025
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Macros Code that generates Rust code S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Macros Code that generates Rust code S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Derive Macro for MapEntites
4 participants