Skip to content

Commit b881a11

Browse files
HanKruigerandrewzhurov
authored andcommitted
implement MapEntities for higher-order types (bevyengine#19071)
# Objective With the current `MapEntities` `impl`s, it is not possible to derive things like this: ```rust #[derive(Component)] pub struct Inventory { #[entities] slots: Vec<Option<Entity>>, } ``` This is because `MapEntities` is only implemented for `Vec<Entity>` & `Option<Entity>`, and not arbitrary combinations of those. It would be nice to also support those types. ## Solution I replaced the `impl`s of the following types - `Option<Entity>`: replaced with `Option<T>` - `Vec<Entity>`: replaced with `Vec<T>` - `HashSet<Entity, S>`: replaced with `HashSet<T, S>` - `T` also had to be `Eq + core::hash::Hash` here. **Not sure if this is too restrictive?** - `IndexSet<Entity, S>`: replaced with `IndexSet <T, S>` - `T` also had to be `Eq + core::hash::Hash` here. **Not sure if this is too restrictive?** - `BTreeSet<Entity>`: replaced with `BTreeSet<T>` - `VecDeque<Entity>`: replaced with `VecDeque<T>` - `SmallVec<A: smallvec::Array<Item = Entity>>`: replaced with `SmallVec<A: smallvec::Array<Item = T>>` (in all of the above, `T` is a generic type that implements `MapEntities` (`Entity` being one of them).) ## Testing I did not test any of this, but extended the `Component::map_entities` doctest with an example usage of the newly supported types. --- ## Showcase With these changes, this is now possible: ```rust #[derive(Component)] pub struct Inventory { #[entities] slots: Vec<Option<Entity>>, } ```
1 parent 9d26706 commit b881a11

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

crates/bevy_ecs/src/component.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,17 @@ pub trait Component: Send + Sync + 'static {
574574
/// ```
575575
///
576576
/// Fields with `#[entities]` must implement [`MapEntities`](crate::entity::MapEntities).
577+
///
578+
/// Bevy provides various implementations of [`MapEntities`](crate::entity::MapEntities), so that arbitrary combinations like these are supported with `#[entities]`:
579+
///
580+
/// ```rust
581+
/// # use bevy_ecs::{component::Component, entity::Entity};
582+
/// #[derive(Component)]
583+
/// struct Inventory {
584+
/// #[entities]
585+
/// items: Vec<Option<Entity>>
586+
/// }
587+
/// ```
577588
#[inline]
578589
fn map_entities<E: EntityMapper>(_this: &mut Self, _mapper: &mut E) {}
579590
}

crates/bevy_ecs/src/entity/map_entities.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,25 +65,38 @@ impl MapEntities for Entity {
6565
}
6666
}
6767

68-
impl MapEntities for Option<Entity> {
68+
impl<T: MapEntities> MapEntities for Option<T> {
6969
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
70-
if let Some(entity) = self {
71-
*entity = entity_mapper.get_mapped(*entity);
70+
if let Some(entities) = self {
71+
entities.map_entities(entity_mapper);
7272
}
7373
}
7474
}
7575

76-
impl<S: BuildHasher + Default> MapEntities for HashSet<Entity, S> {
76+
impl<T: MapEntities + Eq + core::hash::Hash, S: BuildHasher + Default> MapEntities
77+
for HashSet<T, S>
78+
{
7779
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
78-
*self = self.drain().map(|e| entity_mapper.get_mapped(e)).collect();
80+
*self = self
81+
.drain()
82+
.map(|mut entities| {
83+
entities.map_entities(entity_mapper);
84+
entities
85+
})
86+
.collect();
7987
}
8088
}
8189

82-
impl<S: BuildHasher + Default> MapEntities for IndexSet<Entity, S> {
90+
impl<T: MapEntities + Eq + core::hash::Hash, S: BuildHasher + Default> MapEntities
91+
for IndexSet<T, S>
92+
{
8393
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
8494
*self = self
8595
.drain(..)
86-
.map(|e| entity_mapper.get_mapped(e))
96+
.map(|mut entities| {
97+
entities.map_entities(entity_mapper);
98+
entities
99+
})
87100
.collect();
88101
}
89102
}
@@ -97,35 +110,38 @@ impl MapEntities for EntityIndexSet {
97110
}
98111
}
99112

100-
impl MapEntities for BTreeSet<Entity> {
113+
impl<T: MapEntities + Ord> MapEntities for BTreeSet<T> {
101114
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
102115
*self = mem::take(self)
103116
.into_iter()
104-
.map(|e| entity_mapper.get_mapped(e))
117+
.map(|mut entities| {
118+
entities.map_entities(entity_mapper);
119+
entities
120+
})
105121
.collect();
106122
}
107123
}
108124

109-
impl MapEntities for Vec<Entity> {
125+
impl<T: MapEntities> MapEntities for Vec<T> {
110126
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
111-
for entity in self.iter_mut() {
112-
*entity = entity_mapper.get_mapped(*entity);
127+
for entities in self.iter_mut() {
128+
entities.map_entities(entity_mapper);
113129
}
114130
}
115131
}
116132

117-
impl MapEntities for VecDeque<Entity> {
133+
impl<T: MapEntities> MapEntities for VecDeque<T> {
118134
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
119-
for entity in self.iter_mut() {
120-
*entity = entity_mapper.get_mapped(*entity);
135+
for entities in self.iter_mut() {
136+
entities.map_entities(entity_mapper);
121137
}
122138
}
123139
}
124140

125-
impl<A: smallvec::Array<Item = Entity>> MapEntities for SmallVec<A> {
141+
impl<T: MapEntities, A: smallvec::Array<Item = T>> MapEntities for SmallVec<A> {
126142
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
127-
for entity in self.iter_mut() {
128-
*entity = entity_mapper.get_mapped(*entity);
143+
for entities in self.iter_mut() {
144+
entities.map_entities(entity_mapper);
129145
}
130146
}
131147
}

0 commit comments

Comments
 (0)