-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Add VisitEntities for generic and reflectable Entity iteration
#15425
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
Merged
alice-i-cecile
merged 36 commits into
bevyengine:main
from
jrobsonchase:map_entities_rework
Sep 30, 2024
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
16b341b
rework MapEntities into two iter-derived traits
jrobsonchase b411dac
rename existing ReflectMapEntities methods
jrobsonchase e988ae1
add IterEntities traits and rebase MapEntities on them
jrobsonchase 42d8b65
replace MapEntities impls with IntoIterator
jrobsonchase 7b316af
make ReflectMapEntities match MapEntities
jrobsonchase 6e606b1
documentation
jrobsonchase c5be438
appease clippy
jrobsonchase 796e820
Update ReflectMapEntitesResource to match ReflectMapEntities
jrobsonchase 9fda2f1
Remove read-only trait bounds from (Iter|Map)EntitiesMut
jrobsonchase 2c79e1c
add IterEntities derive macro
jrobsonchase 6bb3665
consolidate Iter/MapEntities into a single trait
jrobsonchase df619ad
use iter::once instead of Some(...).into_iter()
jrobsonchase 7f1c597
implement IterEntities instead of IntoIterator for WindowRef
jrobsonchase 20e548a
Change Map to Visit, split Reflect
jrobsonchase 33c4a98
remove unneeded tests, document derive
jrobsonchase 7115fb7
move EntityMapper & co back to map_entities.rs
jrobsonchase 415b760
Bring back (Reflect)MapEntities since HashSet requires it, impl both …
jrobsonchase 6702c6f
move pub use IterEntities to visit_entities
jrobsonchase de152bc
merge main@upstream into map_entities_rework
jrobsonchase 9448830
std -> iter
jrobsonchase 5f86a55
don't reflect(MapEntities) for WindowRef - not a component
jrobsonchase e889d42
merge main@upstream
jrobsonchase 01a4dcf
remove _mut methods from Visit/IterEntities along with blanket MapEnt…
jrobsonchase 8162cfb
put back all of the MapEntities impls I removed
jrobsonchase 3fe5675
remove extra IntoIterator impl for Children
jrobsonchase 2b1f0d8
fix docs in visit_entities.rs
jrobsonchase dc2429b
add test for VisitEntities
jrobsonchase b240b41
Remove IterEntities, change proc macro to VisitEntities
jrobsonchase d659cfd
replace more IterEntities with VisitEntities
jrobsonchase e1dea3b
add iter_related hierarchy query extension
jrobsonchase 68e6f17
merge main@upstream
jrobsonchase a77b366
don't expose iter_related publicly yet
jrobsonchase 202393c
back out an over-aggressive find/replace
jrobsonchase d8dde38
Back out "don't expose iter_related publicly yet"
jrobsonchase f144976
bring back VisitEntitiesMut
jrobsonchase 36022e8
DRY out VisitEntities derive macros
jrobsonchase File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| pub use bevy_ecs_macros::{VisitEntities, VisitEntitiesMut}; | ||
|
|
||
| use crate::entity::Entity; | ||
|
|
||
| /// Apply an operation to all entities in a container. | ||
| /// | ||
| /// This is implemented by default for types that implement [`IntoIterator`]. | ||
| /// | ||
| /// It may be useful to implement directly for types that can't produce an | ||
| /// iterator for lifetime reasons, such as those involving internal mutexes. | ||
| pub trait VisitEntities { | ||
| /// Apply an operation to all contained entities. | ||
| fn visit_entities<F: FnMut(Entity)>(&self, f: F); | ||
| } | ||
|
|
||
| impl<T> VisitEntities for T | ||
| where | ||
| for<'a> &'a T: IntoIterator<Item = &'a Entity>, | ||
| { | ||
| fn visit_entities<F: FnMut(Entity)>(&self, f: F) { | ||
| self.into_iter().copied().for_each(f); | ||
| } | ||
| } | ||
|
|
||
| impl VisitEntities for Entity { | ||
| fn visit_entities<F: FnMut(Entity)>(&self, mut f: F) { | ||
| f(*self); | ||
| } | ||
| } | ||
|
|
||
| /// Apply an operation to mutable references to all entities in a container. | ||
| /// | ||
| /// This is implemented by default for types that implement [`IntoIterator`]. | ||
| /// | ||
| /// It may be useful to implement directly for types that can't produce an | ||
| /// iterator for lifetime reasons, such as those involving internal mutexes. | ||
| pub trait VisitEntitiesMut: VisitEntities { | ||
| /// Apply an operation to mutable references to all contained entities. | ||
| fn visit_entities_mut<F: FnMut(&mut Entity)>(&mut self, f: F); | ||
| } | ||
|
|
||
| impl<T: VisitEntities> VisitEntitiesMut for T | ||
| where | ||
| for<'a> &'a mut T: IntoIterator<Item = &'a mut Entity>, | ||
| { | ||
| fn visit_entities_mut<F: FnMut(&mut Entity)>(&mut self, f: F) { | ||
| self.into_iter().for_each(f); | ||
| } | ||
| } | ||
|
|
||
| impl VisitEntitiesMut for Entity { | ||
| fn visit_entities_mut<F: FnMut(&mut Entity)>(&mut self, mut f: F) { | ||
| f(self); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use crate::{ | ||
| self as bevy_ecs, | ||
| entity::{EntityHashMap, MapEntities, SceneEntityMapper}, | ||
| world::World, | ||
| }; | ||
| use bevy_utils::HashSet; | ||
|
|
||
| use super::*; | ||
|
|
||
| #[derive(VisitEntities, Debug, PartialEq)] | ||
| struct Foo { | ||
| ordered: Vec<Entity>, | ||
| unordered: HashSet<Entity>, | ||
| single: Entity, | ||
| #[allow(dead_code)] | ||
| #[visit_entities(ignore)] | ||
| not_an_entity: String, | ||
| } | ||
|
|
||
| // Need a manual impl since VisitEntitiesMut isn't implemented for `HashSet`. | ||
| // We don't expect users to actually do this - it's only for test purposes | ||
| // to prove out the automatic `MapEntities` impl we get with `VisitEntitiesMut`. | ||
| impl VisitEntitiesMut for Foo { | ||
| fn visit_entities_mut<F: FnMut(&mut Entity)>(&mut self, mut f: F) { | ||
| self.ordered.visit_entities_mut(&mut f); | ||
| self.unordered = self | ||
| .unordered | ||
| .drain() | ||
| .map(|mut entity| { | ||
| f(&mut entity); | ||
| entity | ||
| }) | ||
| .collect(); | ||
| f(&mut self.single); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn visit_entities() { | ||
| let mut world = World::new(); | ||
| let entities = world.entities(); | ||
| let mut foo = Foo { | ||
| ordered: vec![entities.reserve_entity(), entities.reserve_entity()], | ||
| unordered: [ | ||
| entities.reserve_entity(), | ||
| entities.reserve_entity(), | ||
| entities.reserve_entity(), | ||
| ] | ||
| .into_iter() | ||
| .collect(), | ||
| single: entities.reserve_entity(), | ||
| not_an_entity: "Bar".into(), | ||
| }; | ||
|
|
||
| let mut entity_map = EntityHashMap::<Entity>::default(); | ||
| let mut remapped = Foo { | ||
| ordered: vec![], | ||
| unordered: HashSet::new(), | ||
| single: Entity::PLACEHOLDER, | ||
| not_an_entity: foo.not_an_entity.clone(), | ||
| }; | ||
|
|
||
| // Note: this assumes that the VisitEntities derive is field-ordered, | ||
| // which isn't explicitly stated/guaranteed. | ||
| // If that changes, this test will fail, but that might be OK if | ||
| // we're intentionally breaking that assumption. | ||
| let mut i = 0; | ||
| foo.visit_entities(|entity| { | ||
| let new_entity = entities.reserve_entity(); | ||
| if i < foo.ordered.len() { | ||
| assert_eq!(entity, foo.ordered[i]); | ||
| remapped.ordered.push(new_entity); | ||
| } else if i < foo.ordered.len() + foo.unordered.len() { | ||
| assert!(foo.unordered.contains(&entity)); | ||
| remapped.unordered.insert(new_entity); | ||
| } else { | ||
| assert_eq!(entity, foo.single); | ||
| remapped.single = new_entity; | ||
| } | ||
|
|
||
| entity_map.insert(entity, new_entity); | ||
|
|
||
| i += 1; | ||
| }); | ||
|
|
||
| SceneEntityMapper::world_scope(&mut entity_map, &mut world, |_, mapper| { | ||
| foo.map_entities(mapper); | ||
| }); | ||
|
|
||
| assert_eq!(foo, remapped); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.