implement MapEntities for higher-order types (#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` here. **Not sure if this is
too restrictive?**
- `IndexSet<Entity, S>`: replaced with `IndexSet <T, S>`
- `T` also had to be `Eq + core:#️⃣: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>>,
}
```
This commit is contained in:
parent
8f3e45b45f
commit
b8724c21ce
@ -574,6 +574,17 @@ pub trait Component: Send + Sync + 'static {
|
||||
/// ```
|
||||
///
|
||||
/// Fields with `#[entities]` must implement [`MapEntities`](crate::entity::MapEntities).
|
||||
///
|
||||
/// Bevy provides various implementations of [`MapEntities`](crate::entity::MapEntities), so that arbitrary combinations like these are supported with `#[entities]`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use bevy_ecs::{component::Component, entity::Entity};
|
||||
/// #[derive(Component)]
|
||||
/// struct Inventory {
|
||||
/// #[entities]
|
||||
/// items: Vec<Option<Entity>>
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
fn map_entities<E: EntityMapper>(_this: &mut Self, _mapper: &mut E) {}
|
||||
}
|
||||
|
||||
@ -65,25 +65,38 @@ impl MapEntities for Entity {
|
||||
}
|
||||
}
|
||||
|
||||
impl MapEntities for Option<Entity> {
|
||||
impl<T: MapEntities> MapEntities for Option<T> {
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
if let Some(entity) = self {
|
||||
*entity = entity_mapper.get_mapped(*entity);
|
||||
if let Some(entities) = self {
|
||||
entities.map_entities(entity_mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BuildHasher + Default> MapEntities for HashSet<Entity, S> {
|
||||
impl<T: MapEntities + Eq + core::hash::Hash, S: BuildHasher + Default> MapEntities
|
||||
for HashSet<T, S>
|
||||
{
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
*self = self.drain().map(|e| entity_mapper.get_mapped(e)).collect();
|
||||
*self = self
|
||||
.drain()
|
||||
.map(|mut entities| {
|
||||
entities.map_entities(entity_mapper);
|
||||
entities
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BuildHasher + Default> MapEntities for IndexSet<Entity, S> {
|
||||
impl<T: MapEntities + Eq + core::hash::Hash, S: BuildHasher + Default> MapEntities
|
||||
for IndexSet<T, S>
|
||||
{
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
*self = self
|
||||
.drain(..)
|
||||
.map(|e| entity_mapper.get_mapped(e))
|
||||
.map(|mut entities| {
|
||||
entities.map_entities(entity_mapper);
|
||||
entities
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
@ -97,35 +110,38 @@ impl MapEntities for EntityIndexSet {
|
||||
}
|
||||
}
|
||||
|
||||
impl MapEntities for BTreeSet<Entity> {
|
||||
impl<T: MapEntities + Ord> MapEntities for BTreeSet<T> {
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
*self = mem::take(self)
|
||||
.into_iter()
|
||||
.map(|e| entity_mapper.get_mapped(e))
|
||||
.map(|mut entities| {
|
||||
entities.map_entities(entity_mapper);
|
||||
entities
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
impl MapEntities for Vec<Entity> {
|
||||
impl<T: MapEntities> MapEntities for Vec<T> {
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
for entity in self.iter_mut() {
|
||||
*entity = entity_mapper.get_mapped(*entity);
|
||||
for entities in self.iter_mut() {
|
||||
entities.map_entities(entity_mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MapEntities for VecDeque<Entity> {
|
||||
impl<T: MapEntities> MapEntities for VecDeque<T> {
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
for entity in self.iter_mut() {
|
||||
*entity = entity_mapper.get_mapped(*entity);
|
||||
for entities in self.iter_mut() {
|
||||
entities.map_entities(entity_mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: smallvec::Array<Item = Entity>> MapEntities for SmallVec<A> {
|
||||
impl<T: MapEntities, A: smallvec::Array<Item = T>> MapEntities for SmallVec<A> {
|
||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
|
||||
for entity in self.iter_mut() {
|
||||
*entity = entity_mapper.get_mapped(*entity);
|
||||
for entities in self.iter_mut() {
|
||||
entities.map_entities(entity_mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user