Skip to content

Commit e05e74a

Browse files
Brezakmockersf
andauthored
Implement RelationshipSourceCollection for IndexSet (#18471)
# Objective `IndexSet` doesn't implement `RelationshipSourceCollection` ## Solution Implement `MapEntities` for `IndexSet` Implement `RelationshipSourceCollection` for `IndexSet` ## Testing `cargo clippy` --------- Co-authored-by: François Mockers <mockersf@gmail.com> Co-authored-by: François Mockers <francois.mockers@vleue.com>
1 parent c6d41a0 commit e05e74a

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed

crates/bevy_ecs/src/entity/map_entities.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub use bevy_ecs_macros::MapEntities;
2+
use indexmap::IndexSet;
23

34
use crate::{
45
entity::{hash_map::EntityHashMap, Entity},
@@ -14,6 +15,8 @@ use bevy_platform::collections::HashSet;
1415
use core::{hash::BuildHasher, mem};
1516
use smallvec::SmallVec;
1617

18+
use super::EntityIndexSet;
19+
1720
/// Operation to map all contained [`Entity`] fields in a type to new values.
1821
///
1922
/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
@@ -76,6 +79,24 @@ impl<S: BuildHasher + Default> MapEntities for HashSet<Entity, S> {
7679
}
7780
}
7881

82+
impl<S: BuildHasher + Default> MapEntities for IndexSet<Entity, S> {
83+
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
84+
*self = self
85+
.drain(..)
86+
.map(|e| entity_mapper.get_mapped(e))
87+
.collect();
88+
}
89+
}
90+
91+
impl MapEntities for EntityIndexSet {
92+
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
93+
*self = self
94+
.drain(..)
95+
.map(|e| entity_mapper.get_mapped(e))
96+
.collect();
97+
}
98+
}
99+
79100
impl MapEntities for BTreeSet<Entity> {
80101
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
81102
*self = mem::take(self)

crates/bevy_ecs/src/relationship/relationship_source_collection.rs

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
use alloc::collections::{btree_set, BTreeSet};
2+
use core::{
3+
hash::BuildHasher,
4+
ops::{Deref, DerefMut},
5+
};
26

3-
use crate::entity::{hash_set::EntityHashSet, Entity};
7+
use crate::entity::{Entity, EntityHashSet, EntityIndexSet};
48
use alloc::vec::Vec;
9+
use indexmap::IndexSet;
510
use smallvec::SmallVec;
611

712
/// The internal [`Entity`] collection used by a [`RelationshipTarget`](crate::relationship::RelationshipTarget) component.
@@ -447,6 +452,97 @@ impl<const N: usize> OrderedRelationshipSourceCollection for SmallVec<[Entity; N
447452
}
448453
}
449454

455+
impl<S: BuildHasher + Default> RelationshipSourceCollection for IndexSet<Entity, S> {
456+
type SourceIter<'a>
457+
= core::iter::Copied<indexmap::set::Iter<'a, Entity>>
458+
where
459+
S: 'a;
460+
461+
fn new() -> Self {
462+
IndexSet::default()
463+
}
464+
465+
fn reserve(&mut self, additional: usize) {
466+
self.reserve(additional);
467+
}
468+
469+
fn with_capacity(capacity: usize) -> Self {
470+
IndexSet::with_capacity_and_hasher(capacity, S::default())
471+
}
472+
473+
fn add(&mut self, entity: Entity) -> bool {
474+
self.insert(entity)
475+
}
476+
477+
fn remove(&mut self, entity: Entity) -> bool {
478+
self.shift_remove(&entity)
479+
}
480+
481+
fn iter(&self) -> Self::SourceIter<'_> {
482+
self.iter().copied()
483+
}
484+
485+
fn len(&self) -> usize {
486+
self.len()
487+
}
488+
489+
fn clear(&mut self) {
490+
self.clear();
491+
}
492+
493+
fn shrink_to_fit(&mut self) {
494+
self.shrink_to_fit();
495+
}
496+
497+
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
498+
self.extend(entities);
499+
}
500+
}
501+
502+
impl RelationshipSourceCollection for EntityIndexSet {
503+
type SourceIter<'a> = core::iter::Copied<crate::entity::index_set::Iter<'a>>;
504+
505+
fn new() -> Self {
506+
EntityIndexSet::new()
507+
}
508+
509+
fn reserve(&mut self, additional: usize) {
510+
self.deref_mut().reserve(additional);
511+
}
512+
513+
fn with_capacity(capacity: usize) -> Self {
514+
EntityIndexSet::with_capacity(capacity)
515+
}
516+
517+
fn add(&mut self, entity: Entity) -> bool {
518+
self.insert(entity)
519+
}
520+
521+
fn remove(&mut self, entity: Entity) -> bool {
522+
self.deref_mut().shift_remove(&entity)
523+
}
524+
525+
fn iter(&self) -> Self::SourceIter<'_> {
526+
self.iter().copied()
527+
}
528+
529+
fn len(&self) -> usize {
530+
self.deref().len()
531+
}
532+
533+
fn clear(&mut self) {
534+
self.deref_mut().clear();
535+
}
536+
537+
fn shrink_to_fit(&mut self) {
538+
self.deref_mut().shrink_to_fit();
539+
}
540+
541+
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
542+
self.extend(entities);
543+
}
544+
}
545+
450546
impl RelationshipSourceCollection for BTreeSet<Entity> {
451547
type SourceIter<'a> = core::iter::Copied<btree_set::Iter<'a, Entity>>;
452548

@@ -590,6 +686,40 @@ mod tests {
590686
assert_eq!(a, world.get::<Below>(c).unwrap().0);
591687
}
592688

689+
#[test]
690+
fn entity_index_map() {
691+
#[derive(Component)]
692+
#[relationship(relationship_target = RelTarget)]
693+
struct Rel(Entity);
694+
695+
#[derive(Component)]
696+
#[relationship_target(relationship = Rel, linked_spawn)]
697+
struct RelTarget(EntityHashSet);
698+
699+
let mut world = World::new();
700+
let a = world.spawn_empty().id();
701+
let b = world.spawn_empty().id();
702+
let c = world.spawn_empty().id();
703+
704+
let d = world.spawn_empty().id();
705+
706+
world.entity_mut(a).add_related::<Rel>(&[b, c, d]);
707+
708+
let rel_target = world.get::<RelTarget>(a).unwrap();
709+
let collection = rel_target.collection();
710+
711+
// Insertions should maintain ordering
712+
assert!(collection.iter().eq(&[b, c, d]));
713+
714+
world.entity_mut(c).despawn();
715+
716+
let rel_target = world.get::<RelTarget>(a).unwrap();
717+
let collection = rel_target.collection();
718+
719+
// Removals should maintain ordering
720+
assert!(collection.iter().eq(&[b, d]));
721+
}
722+
593723
#[test]
594724
#[should_panic]
595725
fn one_to_one_relationship_shared_target() {
@@ -600,7 +730,6 @@ mod tests {
600730
#[derive(Component)]
601731
#[relationship_target(relationship = Above)]
602732
struct Below(Entity);
603-
604733
let mut world = World::new();
605734
let a = world.spawn_empty().id();
606735
let b = world.spawn_empty().id();

0 commit comments

Comments
 (0)