Path: blob/main/crates/bevy_ecs/src/entity/index_set.rs
6849 views
//! Contains the [`EntityIndexSet`] type, a [`IndexSet`] pre-configured to use [`EntityHash`] hashing.1//!2//! This module is a lightweight wrapper around `indexmap`'ss [`IndexSet`] that is more performant for [`Entity`] keys.34use core::{5cmp::Ordering,6fmt::{self, Debug, Formatter},7hash::BuildHasher,8hash::{Hash, Hasher},9iter::FusedIterator,10marker::PhantomData,11ops::{12BitAnd, BitOr, BitXor, Bound, Deref, DerefMut, Index, Range, RangeBounds, RangeFrom,13RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Sub,14},15ptr,16};1718use indexmap::set::{self, IndexSet};1920use super::{Entity, EntityHash, EntitySetIterator};2122use bevy_platform::prelude::Box;2324/// An [`IndexSet`] pre-configured to use [`EntityHash`] hashing.25#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]26#[derive(Debug, Clone, Default)]27pub struct EntityIndexSet(pub(crate) IndexSet<Entity, EntityHash>);2829impl EntityIndexSet {30/// Creates an empty `EntityIndexSet`.31///32/// Equivalent to [`IndexSet::with_hasher(EntityHash)`].33///34/// [`IndexSet::with_hasher(EntityHash)`]: IndexSet::with_hasher35pub const fn new() -> Self {36Self(IndexSet::with_hasher(EntityHash))37}3839/// Creates an empty `EntityIndexSet` with the specified capacity.40///41/// Equivalent to [`IndexSet::with_capacity_and_hasher(n, EntityHash)`].42///43/// [`IndexSet::with_capacity_and_hasher(n, EntityHash)`]: IndexSet::with_capacity_and_hasher44pub fn with_capacity(n: usize) -> Self {45Self(IndexSet::with_capacity_and_hasher(n, EntityHash))46}4748/// Returns the inner [`IndexSet`].49pub fn into_inner(self) -> IndexSet<Entity, EntityHash> {50self.051}5253/// Returns a slice of all the values in the set.54///55/// Equivalent to [`IndexSet::as_slice`].56pub fn as_slice(&self) -> &Slice {57// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.58unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }59}6061/// Clears the `IndexSet` in the given index range, returning those values62/// as a drain iterator.63///64/// Equivalent to [`IndexSet::drain`].65pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> Drain<'_> {66Drain(self.0.drain(range), PhantomData)67}6869/// Returns a slice of values in the given range of indices.70///71/// Equivalent to [`IndexSet::get_range`].72pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Slice> {73self.0.get_range(range).map(|slice|74// SAFETY: The source IndexSet uses EntityHash.75unsafe { Slice::from_slice_unchecked(slice) })76}7778/// Return an iterator over the values of the set, in their order.79///80/// Equivalent to [`IndexSet::iter`].81pub fn iter(&self) -> Iter<'_> {82Iter(self.0.iter(), PhantomData)83}8485/// Converts into a boxed slice of all the values in the set.86///87/// Equivalent to [`IndexSet::into_boxed_slice`].88pub fn into_boxed_slice(self) -> Box<Slice> {89// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.90unsafe { Slice::from_boxed_slice_unchecked(self.0.into_boxed_slice()) }91}92}9394impl Deref for EntityIndexSet {95type Target = IndexSet<Entity, EntityHash>;9697fn deref(&self) -> &Self::Target {98&self.099}100}101102impl DerefMut for EntityIndexSet {103fn deref_mut(&mut self) -> &mut Self::Target {104&mut self.0105}106}107108impl<'a> IntoIterator for &'a EntityIndexSet {109type Item = &'a Entity;110111type IntoIter = Iter<'a>;112113fn into_iter(self) -> Self::IntoIter {114Iter((&self.0).into_iter(), PhantomData)115}116}117118impl IntoIterator for EntityIndexSet {119type Item = Entity;120121type IntoIter = IntoIter;122123fn into_iter(self) -> Self::IntoIter {124IntoIter(self.0.into_iter(), PhantomData)125}126}127128impl BitAnd for &EntityIndexSet {129type Output = EntityIndexSet;130131fn bitand(self, rhs: Self) -> Self::Output {132EntityIndexSet(self.0.bitand(&rhs.0))133}134}135136impl BitOr for &EntityIndexSet {137type Output = EntityIndexSet;138139fn bitor(self, rhs: Self) -> Self::Output {140EntityIndexSet(self.0.bitor(&rhs.0))141}142}143144impl BitXor for &EntityIndexSet {145type Output = EntityIndexSet;146147fn bitxor(self, rhs: Self) -> Self::Output {148EntityIndexSet(self.0.bitxor(&rhs.0))149}150}151152impl Sub for &EntityIndexSet {153type Output = EntityIndexSet;154155fn sub(self, rhs: Self) -> Self::Output {156EntityIndexSet(self.0.sub(&rhs.0))157}158}159160impl<'a> Extend<&'a Entity> for EntityIndexSet {161fn extend<T: IntoIterator<Item = &'a Entity>>(&mut self, iter: T) {162self.0.extend(iter);163}164}165166impl Extend<Entity> for EntityIndexSet {167fn extend<T: IntoIterator<Item = Entity>>(&mut self, iter: T) {168self.0.extend(iter);169}170}171172impl<const N: usize> From<[Entity; N]> for EntityIndexSet {173fn from(value: [Entity; N]) -> Self {174Self(IndexSet::from_iter(value))175}176}177178impl FromIterator<Entity> for EntityIndexSet {179fn from_iter<I: IntoIterator<Item = Entity>>(iterable: I) -> Self {180Self(IndexSet::from_iter(iterable))181}182}183184impl<S2> PartialEq<IndexSet<Entity, S2>> for EntityIndexSet185where186S2: BuildHasher,187{188fn eq(&self, other: &IndexSet<Entity, S2>) -> bool {189self.0.eq(other)190}191}192193impl PartialEq for EntityIndexSet {194fn eq(&self, other: &EntityIndexSet) -> bool {195self.0.eq(other)196}197}198199impl Eq for EntityIndexSet {}200201impl Index<(Bound<usize>, Bound<usize>)> for EntityIndexSet {202type Output = Slice;203fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self::Output {204// SAFETY: The source IndexSet uses EntityHash.205unsafe { Slice::from_slice_unchecked(self.0.index(key)) }206}207}208209impl Index<Range<usize>> for EntityIndexSet {210type Output = Slice;211fn index(&self, key: Range<usize>) -> &Self::Output {212// SAFETY: The source IndexSet uses EntityHash.213unsafe { Slice::from_slice_unchecked(self.0.index(key)) }214}215}216217impl Index<RangeFrom<usize>> for EntityIndexSet {218type Output = Slice;219fn index(&self, key: RangeFrom<usize>) -> &Self::Output {220// SAFETY: The source IndexSet uses EntityHash.221unsafe { Slice::from_slice_unchecked(self.0.index(key)) }222}223}224225impl Index<RangeFull> for EntityIndexSet {226type Output = Slice;227fn index(&self, key: RangeFull) -> &Self::Output {228// SAFETY: The source IndexSet uses EntityHash.229unsafe { Slice::from_slice_unchecked(self.0.index(key)) }230}231}232233impl Index<RangeInclusive<usize>> for EntityIndexSet {234type Output = Slice;235fn index(&self, key: RangeInclusive<usize>) -> &Self::Output {236// SAFETY: The source IndexSet uses EntityHash.237unsafe { Slice::from_slice_unchecked(self.0.index(key)) }238}239}240241impl Index<RangeTo<usize>> for EntityIndexSet {242type Output = Slice;243fn index(&self, key: RangeTo<usize>) -> &Self::Output {244// SAFETY: The source IndexSet uses EntityHash.245unsafe { Slice::from_slice_unchecked(self.0.index(key)) }246}247}248249impl Index<RangeToInclusive<usize>> for EntityIndexSet {250type Output = Slice;251fn index(&self, key: RangeToInclusive<usize>) -> &Self::Output {252// SAFETY: The source IndexSet uses EntityHash.253unsafe { Slice::from_slice_unchecked(self.0.index(key)) }254}255}256257impl Index<usize> for EntityIndexSet {258type Output = Entity;259fn index(&self, key: usize) -> &Entity {260self.0.index(key)261}262}263264/// A dynamically-sized slice of values in an [`EntityIndexSet`].265///266/// Equivalent to an [`indexmap::set::Slice<V>`] whose source [`IndexSet`]267/// uses [`EntityHash`].268#[repr(transparent)]269pub struct Slice<S = EntityHash>(PhantomData<S>, set::Slice<Entity>);270271impl Slice {272/// Returns an empty slice.273///274/// Equivalent to [`set::Slice::new`].275pub const fn new<'a>() -> &'a Self {276// SAFETY: The source slice is empty.277unsafe { Self::from_slice_unchecked(set::Slice::new()) }278}279280/// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely.281///282/// # Safety283///284/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].285///286/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`287pub const unsafe fn from_slice_unchecked(slice: &set::Slice<Entity>) -> &Self {288// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.289unsafe { &*(ptr::from_ref(slice) as *const Self) }290}291292/// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely.293///294/// # Safety295///296/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].297///298/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`299pub const unsafe fn from_slice_unchecked_mut(slice: &mut set::Slice<Entity>) -> &mut Self {300// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.301unsafe { &mut *(ptr::from_mut(slice) as *mut Self) }302}303304/// Casts `self` to the inner slice.305pub const fn as_inner(&self) -> &set::Slice<Entity> {306&self.1307}308309/// Constructs a boxed [`entity::index_set::Slice`] from a boxed [`indexmap::set::Slice`] unsafely.310///311/// # Safety312///313/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].314///315/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`316pub unsafe fn from_boxed_slice_unchecked(slice: Box<set::Slice<Entity>>) -> Box<Self> {317// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.318unsafe { Box::from_raw(Box::into_raw(slice) as *mut Self) }319}320321/// Casts a reference to `self` to the inner slice.322#[expect(323clippy::borrowed_box,324reason = "We wish to access the Box API of the inner type, without consuming it."325)]326pub fn as_boxed_inner(self: &Box<Self>) -> &Box<set::Slice<Entity>> {327// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.328unsafe { &*(ptr::from_ref(self).cast::<Box<set::Slice<Entity>>>()) }329}330331/// Casts `self` to the inner slice.332pub fn into_boxed_inner(self: Box<Self>) -> Box<set::Slice<Entity>> {333// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.334unsafe { Box::from_raw(Box::into_raw(self) as *mut set::Slice<Entity>) }335}336337/// Returns a slice of values in the given range of indices.338///339/// Equivalent to [`set::Slice::get_range`].340pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Self> {341self.1.get_range(range).map(|slice|342// SAFETY: This a subslice of a valid slice.343unsafe { Self::from_slice_unchecked(slice) })344}345346/// Divides one slice into two at an index.347///348/// Equivalent to [`set::Slice::split_at`].349pub fn split_at(&self, index: usize) -> (&Self, &Self) {350let (slice_1, slice_2) = self.1.split_at(index);351// SAFETY: These are subslices of a valid slice.352unsafe {353(354Self::from_slice_unchecked(slice_1),355Self::from_slice_unchecked(slice_2),356)357}358}359360/// Returns the first value and the rest of the slice,361/// or `None` if it is empty.362///363/// Equivalent to [`set::Slice::split_first`].364pub fn split_first(&self) -> Option<(&Entity, &Self)> {365self.1.split_first().map(|(first, rest)| {366(367first,368// SAFETY: This a subslice of a valid slice.369unsafe { Self::from_slice_unchecked(rest) },370)371})372}373374/// Returns the last value and the rest of the slice,375/// or `None` if it is empty.376///377/// Equivalent to [`set::Slice::split_last`].378pub fn split_last(&self) -> Option<(&Entity, &Self)> {379self.1.split_last().map(|(last, rest)| {380(381last,382// SAFETY: This a subslice of a valid slice.383unsafe { Self::from_slice_unchecked(rest) },384)385})386}387388/// Return an iterator over the values of the set slice.389///390/// Equivalent to [`set::Slice::iter`].391pub fn iter(&self) -> Iter<'_> {392Iter(self.1.iter(), PhantomData)393}394}395396impl Deref for Slice {397type Target = set::Slice<Entity>;398399fn deref(&self) -> &Self::Target {400&self.1401}402}403404impl<'a> IntoIterator for &'a Slice {405type IntoIter = Iter<'a>;406type Item = &'a Entity;407408fn into_iter(self) -> Self::IntoIter {409self.iter()410}411}412413impl IntoIterator for Box<Slice> {414type IntoIter = IntoIter;415type Item = Entity;416417fn into_iter(self) -> Self::IntoIter {418IntoIter(self.into_boxed_inner().into_iter(), PhantomData)419}420}421422impl Clone for Box<Slice> {423fn clone(&self) -> Self {424// SAFETY: This is a clone of a valid slice.425unsafe { Slice::from_boxed_slice_unchecked(self.as_boxed_inner().clone()) }426}427}428429impl Default for &Slice {430fn default() -> Self {431// SAFETY: The source slice is empty.432unsafe { Slice::from_slice_unchecked(<&set::Slice<Entity>>::default()) }433}434}435436impl Default for Box<Slice> {437fn default() -> Self {438// SAFETY: The source slice is empty.439unsafe { Slice::from_boxed_slice_unchecked(<Box<set::Slice<Entity>>>::default()) }440}441}442443impl<V: Debug> Debug for Slice<V> {444fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {445f.debug_tuple("Slice")446.field(&self.0)447.field(&&self.1)448.finish()449}450}451452impl From<&Slice> for Box<Slice> {453fn from(value: &Slice) -> Self {454// SAFETY: This slice is a copy of a valid slice.455unsafe { Slice::from_boxed_slice_unchecked(value.1.into()) }456}457}458459impl Hash for Slice {460fn hash<H: Hasher>(&self, state: &mut H) {461self.1.hash(state);462}463}464465impl PartialOrd for Slice {466fn partial_cmp(&self, other: &Self) -> Option<Ordering> {467Some(self.cmp(other))468}469}470471impl Ord for Slice {472fn cmp(&self, other: &Self) -> Ordering {473self.1.cmp(other)474}475}476477impl PartialEq for Slice {478fn eq(&self, other: &Self) -> bool {479self.1 == other.1480}481}482483impl Eq for Slice {}484485impl Index<(Bound<usize>, Bound<usize>)> for Slice {486type Output = Self;487fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self {488// SAFETY: This a subslice of a valid slice.489unsafe { Self::from_slice_unchecked(self.1.index(key)) }490}491}492493impl Index<Range<usize>> for Slice {494type Output = Self;495fn index(&self, key: Range<usize>) -> &Self {496// SAFETY: This a subslice of a valid slice.497unsafe { Self::from_slice_unchecked(self.1.index(key)) }498}499}500501impl Index<RangeFrom<usize>> for Slice {502type Output = Slice;503fn index(&self, key: RangeFrom<usize>) -> &Self {504// SAFETY: This a subslice of a valid slice.505unsafe { Self::from_slice_unchecked(self.1.index(key)) }506}507}508509impl Index<RangeFull> for Slice {510type Output = Self;511fn index(&self, key: RangeFull) -> &Self {512// SAFETY: This a subslice of a valid slice.513unsafe { Self::from_slice_unchecked(self.1.index(key)) }514}515}516517impl Index<RangeInclusive<usize>> for Slice {518type Output = Self;519fn index(&self, key: RangeInclusive<usize>) -> &Self {520// SAFETY: This a subslice of a valid slice.521unsafe { Self::from_slice_unchecked(self.1.index(key)) }522}523}524525impl Index<RangeTo<usize>> for Slice {526type Output = Self;527fn index(&self, key: RangeTo<usize>) -> &Self {528// SAFETY: This a subslice of a valid slice.529unsafe { Self::from_slice_unchecked(self.1.index(key)) }530}531}532533impl Index<RangeToInclusive<usize>> for Slice {534type Output = Self;535fn index(&self, key: RangeToInclusive<usize>) -> &Self {536// SAFETY: This a subslice of a valid slice.537unsafe { Self::from_slice_unchecked(self.1.index(key)) }538}539}540541impl Index<usize> for Slice {542type Output = Entity;543fn index(&self, key: usize) -> &Entity {544self.1.index(key)545}546}547548/// An iterator over the items of an [`EntityIndexSet`].549///550/// This struct is created by the [`iter`] method on [`EntityIndexSet`]. See its documentation for more.551///552/// [`iter`]: EntityIndexSet::iter553pub struct Iter<'a, S = EntityHash>(set::Iter<'a, Entity>, PhantomData<S>);554555impl<'a> Iter<'a> {556/// Returns the inner [`Iter`](set::Iter).557pub fn into_inner(self) -> set::Iter<'a, Entity> {558self.0559}560561/// Returns a slice of the remaining entries in the iterator.562///563/// Equivalent to [`set::Iter::as_slice`].564pub fn as_slice(&self) -> &Slice {565// SAFETY: The source IndexSet uses EntityHash.566unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }567}568}569570impl<'a> Deref for Iter<'a> {571type Target = set::Iter<'a, Entity>;572573fn deref(&self) -> &Self::Target {574&self.0575}576}577578impl<'a> Iterator for Iter<'a> {579type Item = &'a Entity;580581fn next(&mut self) -> Option<Self::Item> {582self.0.next()583}584}585586impl DoubleEndedIterator for Iter<'_> {587fn next_back(&mut self) -> Option<Self::Item> {588self.0.next_back()589}590}591592impl ExactSizeIterator for Iter<'_> {}593594impl FusedIterator for Iter<'_> {}595596impl Clone for Iter<'_> {597fn clone(&self) -> Self {598Self(self.0.clone(), PhantomData)599}600}601602impl Debug for Iter<'_> {603fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {604f.debug_tuple("Iter").field(&self.0).field(&self.1).finish()605}606}607608impl Default for Iter<'_> {609fn default() -> Self {610Self(Default::default(), PhantomData)611}612}613614// SAFETY: Iter stems from a correctly behaving `IndexSet<Entity, EntityHash>`.615unsafe impl EntitySetIterator for Iter<'_> {}616617/// Owning iterator over the items of an [`EntityIndexSet`].618///619/// This struct is created by the [`into_iter`] method on [`EntityIndexSet`] (provided by the [`IntoIterator`] trait). See its documentation for more.620///621/// [`into_iter`]: EntityIndexSet::into_iter622pub struct IntoIter<S = EntityHash>(set::IntoIter<Entity>, PhantomData<S>);623624impl IntoIter {625/// Returns the inner [`IntoIter`](set::IntoIter).626pub fn into_inner(self) -> set::IntoIter<Entity> {627self.0628}629630/// Returns a slice of the remaining entries in the iterator.631///632/// Equivalent to [`set::IntoIter::as_slice`].633pub fn as_slice(&self) -> &Slice {634// SAFETY: The source IndexSet uses EntityHash.635unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }636}637}638639impl Deref for IntoIter {640type Target = set::IntoIter<Entity>;641642fn deref(&self) -> &Self::Target {643&self.0644}645}646647impl Iterator for IntoIter {648type Item = Entity;649650fn next(&mut self) -> Option<Self::Item> {651self.0.next()652}653}654655impl DoubleEndedIterator for IntoIter {656fn next_back(&mut self) -> Option<Self::Item> {657self.0.next_back()658}659}660661impl ExactSizeIterator for IntoIter {}662663impl FusedIterator for IntoIter {}664665impl Clone for IntoIter {666fn clone(&self) -> Self {667Self(self.0.clone(), PhantomData)668}669}670671impl Debug for IntoIter {672fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {673f.debug_tuple("IntoIter")674.field(&self.0)675.field(&self.1)676.finish()677}678}679680impl Default for IntoIter {681fn default() -> Self {682Self(Default::default(), PhantomData)683}684}685686// SAFETY: IntoIter stems from a correctly behaving `IndexSet<Entity, EntityHash>`.687unsafe impl EntitySetIterator for IntoIter {}688689/// A draining iterator over the items of an [`EntityIndexSet`].690///691/// This struct is created by the [`drain`] method on [`EntityIndexSet`]. See its documentation for more.692///693/// [`drain`]: EntityIndexSet::drain694pub struct Drain<'a, S = EntityHash>(set::Drain<'a, Entity>, PhantomData<S>);695696impl<'a> Drain<'a> {697/// Returns the inner [`Drain`](set::Drain).698pub fn into_inner(self) -> set::Drain<'a, Entity> {699self.0700}701702/// Returns a slice of the remaining entries in the iterator.$703///704/// Equivalent to [`set::Drain::as_slice`].705pub fn as_slice(&self) -> &Slice {706// SAFETY: The source IndexSet uses EntityHash.707unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }708}709}710711impl<'a> Deref for Drain<'a> {712type Target = set::Drain<'a, Entity>;713714fn deref(&self) -> &Self::Target {715&self.0716}717}718719impl<'a> Iterator for Drain<'a> {720type Item = Entity;721722fn next(&mut self) -> Option<Self::Item> {723self.0.next()724}725}726727impl DoubleEndedIterator for Drain<'_> {728fn next_back(&mut self) -> Option<Self::Item> {729self.0.next_back()730}731}732733impl ExactSizeIterator for Drain<'_> {}734735impl FusedIterator for Drain<'_> {}736737impl Debug for Drain<'_> {738fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {739f.debug_tuple("Drain")740.field(&self.0)741.field(&self.1)742.finish()743}744}745746// SAFETY: Drain stems from a correctly behaving `IndexSet<Entity, EntityHash>`.747unsafe impl EntitySetIterator for Drain<'_> {}748749// SAFETY: Difference stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.750unsafe impl EntitySetIterator for set::Difference<'_, Entity, EntityHash> {}751752// SAFETY: Intersection stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.753unsafe impl EntitySetIterator for set::Intersection<'_, Entity, EntityHash> {}754755// SAFETY: SymmetricDifference stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.756unsafe impl EntitySetIterator for set::SymmetricDifference<'_, Entity, EntityHash, EntityHash> {}757758// SAFETY: Union stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.759unsafe impl EntitySetIterator for set::Union<'_, Entity, EntityHash> {}760761// SAFETY: Splice stems from a correctly behaving `IndexSet<Entity, EntityHash>`s.762unsafe impl<I: Iterator<Item = Entity>> EntitySetIterator763for set::Splice<'_, I, Entity, EntityHash>764{765}766767768