Path: blob/main/crates/bevy_ecs/src/relationship/relationship_source_collection.rs
6600 views
use alloc::collections::{btree_set, BTreeSet};1use core::{2hash::BuildHasher,3ops::{Deref, DerefMut},4};56use crate::entity::{Entity, EntityHashSet, EntityIndexSet};7use alloc::vec::Vec;8use indexmap::IndexSet;9use smallvec::SmallVec;1011/// The internal [`Entity`] collection used by a [`RelationshipTarget`](crate::relationship::RelationshipTarget) component.12/// This is not intended to be modified directly by users, as it could invalidate the correctness of relationships.13pub trait RelationshipSourceCollection {14/// The type of iterator returned by the `iter` method.15///16/// This is an associated type (rather than using a method that returns an opaque return-position impl trait)17/// to ensure that all methods and traits (like [`DoubleEndedIterator`]) of the underlying collection's iterator18/// are available to the user when implemented without unduly restricting the possible collections.19///20/// The [`SourceIter`](super::SourceIter) type alias can be helpful to reduce confusion when working with this associated type.21type SourceIter<'a>: Iterator<Item = Entity>22where23Self: 'a;2425/// Creates a new empty instance.26fn new() -> Self;2728/// Returns an instance with the given pre-allocated entity `capacity`.29///30/// Some collections will ignore the provided `capacity` and return a default instance.31fn with_capacity(capacity: usize) -> Self;3233/// Reserves capacity for at least `additional` more entities to be inserted.34///35/// Not all collections support this operation, in which case it is a no-op.36fn reserve(&mut self, additional: usize);3738/// Adds the given `entity` to the collection.39///40/// Returns whether the entity was added to the collection.41/// Mainly useful when dealing with collections that don't allow42/// multiple instances of the same entity ([`EntityHashSet`]).43fn add(&mut self, entity: Entity) -> bool;4445/// Removes the given `entity` from the collection.46///47/// Returns whether the collection actually contained48/// the entity.49fn remove(&mut self, entity: Entity) -> bool;5051/// Iterates all entities in the collection.52fn iter(&self) -> Self::SourceIter<'_>;5354/// Returns the current length of the collection.55fn len(&self) -> usize;5657/// Clears the collection.58fn clear(&mut self);5960/// Attempts to save memory by shrinking the capacity to fit the current length.61///62/// This operation is a no-op for collections that do not support it.63fn shrink_to_fit(&mut self);6465/// Returns true if the collection contains no entities.66#[inline]67fn is_empty(&self) -> bool {68self.len() == 069}7071/// For one-to-one relationships, returns the entity that should be removed before adding a new one.72/// Returns `None` for one-to-many relationships or when no entity needs to be removed.73fn source_to_remove_before_add(&self) -> Option<Entity> {74None75}7677/// Add multiple entities to collection at once.78///79/// May be faster than repeatedly calling [`Self::add`].80fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>);81}8283/// This trait signals that a [`RelationshipSourceCollection`] is ordered.84pub trait OrderedRelationshipSourceCollection: RelationshipSourceCollection {85/// Inserts the entity at a specific index.86/// If the index is too large, the entity will be added to the end of the collection.87fn insert(&mut self, index: usize, entity: Entity);88/// Removes the entity at the specified index if it exists.89fn remove_at(&mut self, index: usize) -> Option<Entity>;90/// Inserts the entity at a specific index.91/// This will never reorder other entities.92/// If the index is too large, the entity will be added to the end of the collection.93fn insert_stable(&mut self, index: usize, entity: Entity);94/// Removes the entity at the specified index if it exists.95/// This will never reorder other entities.96fn remove_at_stable(&mut self, index: usize) -> Option<Entity>;97/// Sorts the source collection.98fn sort(&mut self);99/// Inserts the entity at the proper place to maintain sorting.100fn insert_sorted(&mut self, entity: Entity);101102/// This places the most recently added entity at the particular index.103fn place_most_recent(&mut self, index: usize);104105/// This places the given entity at the particular index.106/// This will do nothing if the entity is not in the collection.107/// If the index is out of bounds, this will put the entity at the end.108fn place(&mut self, entity: Entity, index: usize);109110/// Adds the entity at index 0.111fn push_front(&mut self, entity: Entity) {112self.insert(0, entity);113}114115/// Adds the entity to the back of the collection.116fn push_back(&mut self, entity: Entity) {117self.insert(usize::MAX, entity);118}119120/// Removes the first entity.121fn pop_front(&mut self) -> Option<Entity> {122self.remove_at(0)123}124125/// Removes the last entity.126fn pop_back(&mut self) -> Option<Entity> {127if self.is_empty() {128None129} else {130self.remove_at(self.len() - 1)131}132}133}134135impl RelationshipSourceCollection for Vec<Entity> {136type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;137138fn new() -> Self {139Vec::new()140}141142fn reserve(&mut self, additional: usize) {143Vec::reserve(self, additional);144}145146fn with_capacity(capacity: usize) -> Self {147Vec::with_capacity(capacity)148}149150fn add(&mut self, entity: Entity) -> bool {151Vec::push(self, entity);152153true154}155156fn remove(&mut self, entity: Entity) -> bool {157if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {158Vec::remove(self, index);159return true;160}161162false163}164165fn iter(&self) -> Self::SourceIter<'_> {166<[Entity]>::iter(self).copied()167}168169fn len(&self) -> usize {170Vec::len(self)171}172173fn clear(&mut self) {174self.clear();175}176177fn shrink_to_fit(&mut self) {178Vec::shrink_to_fit(self);179}180181fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {182self.extend(entities);183}184}185186impl OrderedRelationshipSourceCollection for Vec<Entity> {187fn insert(&mut self, index: usize, entity: Entity) {188self.push(entity);189let len = self.len();190if index < len {191self.swap(index, len - 1);192}193}194195fn remove_at(&mut self, index: usize) -> Option<Entity> {196(index < self.len()).then(|| self.swap_remove(index))197}198199fn insert_stable(&mut self, index: usize, entity: Entity) {200if index < self.len() {201Vec::insert(self, index, entity);202} else {203self.push(entity);204}205}206207fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {208(index < self.len()).then(|| self.remove(index))209}210211fn sort(&mut self) {212self.sort_unstable();213}214215fn insert_sorted(&mut self, entity: Entity) {216let index = self.partition_point(|e| e <= &entity);217self.insert_stable(index, entity);218}219220fn place_most_recent(&mut self, index: usize) {221if let Some(entity) = self.pop() {222let index = index.min(self.len());223self.insert(index, entity);224}225}226227fn place(&mut self, entity: Entity, index: usize) {228if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {229let index = index.min(self.len());230Vec::remove(self, current);231self.insert(index, entity);232};233}234}235236impl RelationshipSourceCollection for EntityHashSet {237type SourceIter<'a> = core::iter::Copied<crate::entity::hash_set::Iter<'a>>;238239fn new() -> Self {240EntityHashSet::new()241}242243fn reserve(&mut self, additional: usize) {244self.0.reserve(additional);245}246247fn with_capacity(capacity: usize) -> Self {248EntityHashSet::with_capacity(capacity)249}250251fn add(&mut self, entity: Entity) -> bool {252self.insert(entity)253}254255fn remove(&mut self, entity: Entity) -> bool {256// We need to call the remove method on the underlying hash set,257// which takes its argument by reference258self.0.remove(&entity)259}260261fn iter(&self) -> Self::SourceIter<'_> {262self.iter().copied()263}264265fn len(&self) -> usize {266self.len()267}268269fn clear(&mut self) {270self.0.clear();271}272273fn shrink_to_fit(&mut self) {274self.0.shrink_to_fit();275}276277fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {278self.extend(entities);279}280}281282impl<const N: usize> RelationshipSourceCollection for SmallVec<[Entity; N]> {283type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;284285fn new() -> Self {286SmallVec::new()287}288289fn reserve(&mut self, additional: usize) {290SmallVec::reserve(self, additional);291}292293fn with_capacity(capacity: usize) -> Self {294SmallVec::with_capacity(capacity)295}296297fn add(&mut self, entity: Entity) -> bool {298SmallVec::push(self, entity);299300true301}302303fn remove(&mut self, entity: Entity) -> bool {304if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {305SmallVec::remove(self, index);306return true;307}308309false310}311312fn iter(&self) -> Self::SourceIter<'_> {313<[Entity]>::iter(self).copied()314}315316fn len(&self) -> usize {317SmallVec::len(self)318}319320fn clear(&mut self) {321self.clear();322}323324fn shrink_to_fit(&mut self) {325SmallVec::shrink_to_fit(self);326}327328fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {329self.extend(entities);330}331}332333impl RelationshipSourceCollection for Entity {334type SourceIter<'a> = core::option::IntoIter<Entity>;335336fn new() -> Self {337Entity::PLACEHOLDER338}339340fn reserve(&mut self, _: usize) {}341342fn with_capacity(_capacity: usize) -> Self {343Self::new()344}345346fn add(&mut self, entity: Entity) -> bool {347*self = entity;348true349}350351fn remove(&mut self, entity: Entity) -> bool {352if *self == entity {353*self = Entity::PLACEHOLDER;354355return true;356}357358false359}360361fn iter(&self) -> Self::SourceIter<'_> {362if *self == Entity::PLACEHOLDER {363None.into_iter()364} else {365Some(*self).into_iter()366}367}368369fn len(&self) -> usize {370if *self == Entity::PLACEHOLDER {371return 0;372}3731374}375376fn clear(&mut self) {377*self = Entity::PLACEHOLDER;378}379380fn shrink_to_fit(&mut self) {}381382fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {383for entity in entities {384*self = entity;385}386}387388fn source_to_remove_before_add(&self) -> Option<Entity> {389if *self != Entity::PLACEHOLDER {390Some(*self)391} else {392None393}394}395}396397impl<const N: usize> OrderedRelationshipSourceCollection for SmallVec<[Entity; N]> {398fn insert(&mut self, index: usize, entity: Entity) {399self.push(entity);400let len = self.len();401if index < len {402self.swap(index, len - 1);403}404}405406fn remove_at(&mut self, index: usize) -> Option<Entity> {407(index < self.len()).then(|| self.swap_remove(index))408}409410fn insert_stable(&mut self, index: usize, entity: Entity) {411if index < self.len() {412SmallVec::<[Entity; N]>::insert(self, index, entity);413} else {414self.push(entity);415}416}417418fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {419(index < self.len()).then(|| self.remove(index))420}421422fn sort(&mut self) {423self.sort_unstable();424}425426fn insert_sorted(&mut self, entity: Entity) {427let index = self.partition_point(|e| e <= &entity);428self.insert_stable(index, entity);429}430431fn place_most_recent(&mut self, index: usize) {432if let Some(entity) = self.pop() {433let index = index.min(self.len() - 1);434self.insert(index, entity);435}436}437438fn place(&mut self, entity: Entity, index: usize) {439if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {440// The len is at least 1, so the subtraction is safe.441let index = index.min(self.len() - 1);442SmallVec::<[Entity; N]>::remove(self, current);443self.insert(index, entity);444};445}446}447448impl<S: BuildHasher + Default> RelationshipSourceCollection for IndexSet<Entity, S> {449type SourceIter<'a>450= core::iter::Copied<indexmap::set::Iter<'a, Entity>>451where452S: 'a;453454fn new() -> Self {455IndexSet::default()456}457458fn reserve(&mut self, additional: usize) {459self.reserve(additional);460}461462fn with_capacity(capacity: usize) -> Self {463IndexSet::with_capacity_and_hasher(capacity, S::default())464}465466fn add(&mut self, entity: Entity) -> bool {467self.insert(entity)468}469470fn remove(&mut self, entity: Entity) -> bool {471self.shift_remove(&entity)472}473474fn iter(&self) -> Self::SourceIter<'_> {475self.iter().copied()476}477478fn len(&self) -> usize {479self.len()480}481482fn clear(&mut self) {483self.clear();484}485486fn shrink_to_fit(&mut self) {487self.shrink_to_fit();488}489490fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {491self.extend(entities);492}493}494495impl RelationshipSourceCollection for EntityIndexSet {496type SourceIter<'a> = core::iter::Copied<crate::entity::index_set::Iter<'a>>;497498fn new() -> Self {499EntityIndexSet::new()500}501502fn reserve(&mut self, additional: usize) {503self.deref_mut().reserve(additional);504}505506fn with_capacity(capacity: usize) -> Self {507EntityIndexSet::with_capacity(capacity)508}509510fn add(&mut self, entity: Entity) -> bool {511self.insert(entity)512}513514fn remove(&mut self, entity: Entity) -> bool {515self.deref_mut().shift_remove(&entity)516}517518fn iter(&self) -> Self::SourceIter<'_> {519self.iter().copied()520}521522fn len(&self) -> usize {523self.deref().len()524}525526fn clear(&mut self) {527self.deref_mut().clear();528}529530fn shrink_to_fit(&mut self) {531self.deref_mut().shrink_to_fit();532}533534fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {535self.extend(entities);536}537}538539impl RelationshipSourceCollection for BTreeSet<Entity> {540type SourceIter<'a> = core::iter::Copied<btree_set::Iter<'a, Entity>>;541542fn new() -> Self {543BTreeSet::new()544}545546fn with_capacity(_: usize) -> Self {547// BTreeSet doesn't have a capacity548Self::new()549}550551fn reserve(&mut self, _: usize) {552// BTreeSet doesn't have a capacity553}554555fn add(&mut self, entity: Entity) -> bool {556self.insert(entity)557}558559fn remove(&mut self, entity: Entity) -> bool {560self.remove(&entity)561}562563fn iter(&self) -> Self::SourceIter<'_> {564self.iter().copied()565}566567fn len(&self) -> usize {568self.len()569}570571fn clear(&mut self) {572self.clear();573}574575fn shrink_to_fit(&mut self) {576// BTreeSet doesn't have a capacity577}578579fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {580self.extend(entities);581}582}583584#[cfg(test)]585mod tests {586use super::*;587use crate::prelude::{Component, World};588use crate::relationship::RelationshipTarget;589590#[test]591fn vec_relationship_source_collection() {592#[derive(Component)]593#[relationship(relationship_target = RelTarget)]594struct Rel(Entity);595596#[derive(Component)]597#[relationship_target(relationship = Rel, linked_spawn)]598struct RelTarget(Vec<Entity>);599600let mut world = World::new();601let a = world.spawn_empty().id();602let b = world.spawn_empty().id();603604world.entity_mut(a).insert(Rel(b));605606let rel_target = world.get::<RelTarget>(b).unwrap();607let collection = rel_target.collection();608assert_eq!(collection, &alloc::vec!(a));609}610611#[test]612fn smallvec_relationship_source_collection() {613#[derive(Component)]614#[relationship(relationship_target = RelTarget)]615struct Rel(Entity);616617#[derive(Component)]618#[relationship_target(relationship = Rel, linked_spawn)]619struct RelTarget(SmallVec<[Entity; 4]>);620621let mut world = World::new();622let a = world.spawn_empty().id();623let b = world.spawn_empty().id();624625world.entity_mut(a).insert(Rel(b));626627let rel_target = world.get::<RelTarget>(b).unwrap();628let collection = rel_target.collection();629assert_eq!(collection, &SmallVec::from_buf([a]));630}631632#[test]633fn entity_relationship_source_collection() {634#[derive(Component)]635#[relationship(relationship_target = RelTarget)]636struct Rel(Entity);637638#[derive(Component)]639#[relationship_target(relationship = Rel)]640struct RelTarget(Entity);641642let mut world = World::new();643let a = world.spawn_empty().id();644let b = world.spawn_empty().id();645646world.entity_mut(a).insert(Rel(b));647648let rel_target = world.get::<RelTarget>(b).unwrap();649let collection = rel_target.collection();650assert_eq!(collection, &a);651}652653#[test]654fn one_to_one_relationships() {655#[derive(Component)]656#[relationship(relationship_target = Below)]657struct Above(Entity);658659#[derive(Component)]660#[relationship_target(relationship = Above)]661struct Below(Entity);662663let mut world = World::new();664let a = world.spawn_empty().id();665let b = world.spawn_empty().id();666667world.entity_mut(a).insert(Above(b));668assert_eq!(a, world.get::<Below>(b).unwrap().0);669670// Verify removing target removes relationship671world.entity_mut(b).remove::<Below>();672assert!(world.get::<Above>(a).is_none());673674// Verify removing relationship removes target675world.entity_mut(a).insert(Above(b));676world.entity_mut(a).remove::<Above>();677assert!(world.get::<Below>(b).is_none());678679// Actually - a is above c now! Verify relationship was updated correctly680let c = world.spawn_empty().id();681world.entity_mut(a).insert(Above(c));682assert!(world.get::<Below>(b).is_none());683assert_eq!(a, world.get::<Below>(c).unwrap().0);684}685686#[test]687fn entity_index_map() {688for add_before in [false, true] {689#[derive(Component)]690#[relationship(relationship_target = RelTarget)]691struct Rel(Entity);692693#[derive(Component)]694#[relationship_target(relationship = Rel, linked_spawn)]695struct RelTarget(Vec<Entity>);696697let mut world = World::new();698if add_before {699let _ = world.spawn_empty().id();700}701let a = world.spawn_empty().id();702let b = world.spawn_empty().id();703let c = world.spawn_empty().id();704let d = world.spawn_empty().id();705706world.entity_mut(a).add_related::<Rel>(&[b, c, d]);707708let rel_target = world.get::<RelTarget>(a).unwrap();709let collection = rel_target.collection();710711// Insertions should maintain ordering712assert!(collection.iter().eq([b, c, d]));713714world.entity_mut(c).despawn();715716let rel_target = world.get::<RelTarget>(a).unwrap();717let collection = rel_target.collection();718719// Removals should maintain ordering720assert!(collection.iter().eq([b, d]));721}722}723724#[test]725fn one_to_one_relationship_shared_target() {726#[derive(Component)]727#[relationship(relationship_target = Below)]728struct Above(Entity);729730#[derive(Component)]731#[relationship_target(relationship = Above)]732struct Below(Entity);733let mut world = World::new();734let a = world.spawn_empty().id();735let b = world.spawn_empty().id();736let c = world.spawn_empty().id();737738world.entity_mut(a).insert(Above(c));739world.entity_mut(b).insert(Above(c));740741// The original relationship (a -> c) should be removed and the new relationship (b -> c) should be established742assert!(743world.get::<Above>(a).is_none(),744"Original relationship should be removed"745);746assert_eq!(747world.get::<Above>(b).unwrap().0,748c,749"New relationship should be established"750);751assert_eq!(752world.get::<Below>(c).unwrap().0,753b,754"Target should point to new source"755);756}757758#[test]759fn one_to_one_relationship_reinsert() {760#[derive(Component)]761#[relationship(relationship_target = Below)]762struct Above(Entity);763764#[derive(Component)]765#[relationship_target(relationship = Above)]766struct Below(Entity);767768let mut world = World::new();769let a = world.spawn_empty().id();770let b = world.spawn_empty().id();771772world.entity_mut(a).insert(Above(b));773world.entity_mut(a).insert(Above(b));774}775}776777778