Skip to content

get_components_mut#21780

Merged
alice-i-cecile merged 40 commits intobevyengine:mainfrom
hymm:get_components_mut
Dec 8, 2025
Merged

get_components_mut#21780
alice-i-cecile merged 40 commits intobevyengine:mainfrom
hymm:get_components_mut

Conversation

@hymm
Copy link
Copy Markdown
Contributor

@hymm hymm commented Nov 7, 2025

Objective

  • Add a checked version of EntityMut::get_components_mut and EntityWorldMut::get_components_mut that does not allocate

Solution

  • Add a iterator over the access type to QueryData. This is then used to iterate over the pairs of access to check if they are compatible or not.

Testing

  • Added a unit test

Bench checked vs unchecked (50000 entities)

#components unchecked checked times slower
2 509 us 1123 us 2.2x
5 903 us 2902us 3.2x
10 1700 us 11424 us 6.72x

so at 10 components each call was taking about 0.22us vs 0.03 us


ToDo

  • add release note
  • add migration guide
  • add macro for more benches
  • add bench results to pr description
  • look into if this will help with uncached queries
  • see if we can optimize it a bit

@hymm hymm mentioned this pull request Nov 7, 2025
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events M-Release-Note Work that should be called out in the blog due to impact S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Nov 9, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 9, 2025

It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note.

Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes.

github-merge-queue bot pushed a commit that referenced this pull request Nov 13, 2025
# Objective

- As part of #21780, I need a way to iterate over the component ids of a
bundle for `Entity*Except` conflict checking without allocating. Pulled
this out as it changes some unrelated code too.

## Solution

- Change `Bundle::component_ids` and `Bundle::get_component_ids` to
return an iterator instead of taking a closure. In theory I would expect
this to compile to the same asm. I would also argue that using an
iterator is a more natural api for this than the closure. It probably
took a closure before because expressing that the iterator doesn't
capture the `&mut ComponentRegistrator` lifetime wasn't possible without
the `use` syntax.
- Removed some #[allow(deprecated)] in the Bundle macro that was missed.

## Testing

- Checked the asm for `hook_on_add` in the observers example for to
confirm it was still the same. This is a pretty simple example though,
so not sure how good of a check this is.
- None of the code touched are in any hot paths, but ran the spawn and
insert benches. Any changes seem to be in the noise.
Copy link
Copy Markdown
Contributor

@chescock chescock left a comment

Choose a reason for hiding this comment

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

Awesome!

}
}
} else {
// we can optimize small sizes by caching the iteration result in an array on the stack
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this actually help? For the really small sizes, I would have expected the compiler to unroll the whole thing anyway.

Copy link
Copy Markdown
Contributor Author

@hymm hymm Nov 17, 2025

Choose a reason for hiding this comment

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

yeah, it's like 50% faster at 10 components. I think it's mostly the calls to Components::component_id.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yeah, it's like 50% faster at 10 components. The call to Components::component_id is surprisingly expensive.

Yeah, but the component_id call is now done only once in get_state, right? So the ComponentIds are already cached on the stack, and this is just caching the trivial conversions to EcsAccessType.

Anyway, if it's 50% faster then we should definitely keep it!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

looked at the assembly a little. Best I can tell is that it's inlining way more stuff. I see 10 is_compatible checks vs just 3. I see some other changes, but don't fully understand them to know if they're helping the speed.

ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Nov 18, 2025
# Objective

- As part of bevyengine#21780, I need a way to iterate over the component ids of a
bundle for `Entity*Except` conflict checking without allocating. Pulled
this out as it changes some unrelated code too.

## Solution

- Change `Bundle::component_ids` and `Bundle::get_component_ids` to
return an iterator instead of taking a closure. In theory I would expect
this to compile to the same asm. I would also argue that using an
iterator is a more natural api for this than the closure. It probably
took a closure before because expressing that the iterator doesn't
capture the `&mut ComponentRegistrator` lifetime wasn't possible without
the `use` syntax.
- Removed some #[allow(deprecated)] in the Bundle macro that was missed.

## Testing

- Checked the asm for `hook_on_add` in the observers example for to
confirm it was still the same. This is a pretty simple example though,
so not sure how good of a check this is.
- None of the code touched are in any hot paths, but ran the spawn and
insert benches. Any changes seem to be in the noise.
@hymm hymm added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Nov 18, 2025
beicause pushed a commit to beicause/bevy that referenced this pull request Nov 26, 2025
# Objective

- As part of bevyengine#21780, I need a way to iterate over the component ids of a
bundle for `Entity*Except` conflict checking without allocating. Pulled
this out as it changes some unrelated code too.

## Solution

- Change `Bundle::component_ids` and `Bundle::get_component_ids` to
return an iterator instead of taking a closure. In theory I would expect
this to compile to the same asm. I would also argue that using an
iterator is a more natural api for this than the closure. It probably
took a closure before because expressing that the iterator doesn't
capture the `&mut ComponentRegistrator` lifetime wasn't possible without
the `use` syntax.
- Removed some #[allow(deprecated)] in the Bundle macro that was missed.

## Testing

- Checked the asm for `hook_on_add` in the observers example for to
confirm it was still the same. This is a pretty simple example though,
so not sure how good of a check this is.
- None of the code touched are in any hot paths, but ran the spawn and
insert benches. Any changes seem to be in the noise.
@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Nov 30, 2025
@alice-i-cecile alice-i-cecile added this to the 0.18 milestone Nov 30, 2025
@alice-i-cecile
Copy link
Copy Markdown
Member

Updating the branch to see if miri behaves :) It would be nice to land this in 0.18: it seems very close.

@hymm hymm added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Dec 3, 2025
Copy link
Copy Markdown
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

I think this should exist, and I like the implementation strategy.

I think that there's a fair bit of context needed in the release notes to explain why this is cool (it enables OOP-y patterns), but I'll add that later during editing :)

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Dec 8, 2025
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 8, 2025
Merged via the queue into bevyengine:main with commit d76c3aa Dec 8, 2025
42 checks passed
@hymm hymm deleted the get_components_mut branch January 22, 2026 22:14
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-Feature A new feature, making something new possible M-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants