diff --git a/crates/bevy_ecs/src/entity/index_map.rs b/crates/bevy_ecs/src/entity/index_map.rs index 7207740ce8..de174ae3c8 100644 --- a/crates/bevy_ecs/src/entity/index_map.rs +++ b/crates/bevy_ecs/src/entity/index_map.rs @@ -3,19 +3,26 @@ //! This module is a lightweight wrapper around `indexmap`'s [`IndexMap`] that is more performant for [`Entity`] keys. use core::{ + cmp::Ordering, fmt::{self, Debug, Formatter}, - hash::BuildHasher, + hash::{BuildHasher, Hash, Hasher}, iter::FusedIterator, marker::PhantomData, - ops::{Deref, DerefMut, Index, IndexMut, RangeBounds}, + ops::{ + Bound, Deref, DerefMut, Index, IndexMut, Range, RangeBounds, RangeFrom, RangeFull, + RangeInclusive, RangeTo, RangeToInclusive, + }, + ptr, }; #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; -use indexmap::map::{self, IndexMap}; +use indexmap::map::{self, IndexMap, IntoValues, ValuesMut}; use super::{Entity, EntityHash, EntitySetIterator, TrustedEntityBorrow}; +use bevy_platform_support::prelude::Box; + /// A [`IndexMap`] pre-configured to use [`EntityHash`] hashing. #[cfg_attr(feature = "bevy_reflect", derive(Reflect))] #[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))] @@ -46,6 +53,48 @@ impl EntityIndexMap { self.0 } + /// Returns a slice of all the key-value pairs in the map. + /// + /// Equivalent to [`IndexMap::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } + + /// Returns a mutable slice of all the key-value pairs in the map. + /// + /// Equivalent to [`IndexMap::as_mut_slice`]. + pub fn as_mut_slice(&mut self) -> &mut Slice { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { Slice::from_slice_unchecked_mut(self.0.as_mut_slice()) } + } + + /// Converts into a boxed slice of all the key-value pairs in the map. + /// + /// Equivalent to [`IndexMap::into_boxed_slice`]. + pub fn into_boxed_slice(self) -> Box> { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { Slice::from_boxed_slice_unchecked(self.0.into_boxed_slice()) } + } + + /// Returns a slice of key-value pairs in the given range of indices. + /// + /// Equivalent to [`IndexMap::get_range`]. + pub fn get_range>(&self, range: R) -> Option<&Slice> { + self.0.get_range(range).map(|slice| + // SAFETY: EntityIndexSetSlice is a transparent wrapper around indexmap::set::Slice. + unsafe { Slice::from_slice_unchecked(slice) }) + } + + /// Returns a mutable slice of key-value pairs in the given range of indices. + /// + /// Equivalent to [`IndexMap::get_range_mut`]. + pub fn get_range_mut>(&mut self, range: R) -> Option<&mut Slice> { + self.0.get_range_mut(range).map(|slice| + // SAFETY: EntityIndexSetSlice is a transparent wrapper around indexmap::set::Slice. + unsafe { Slice::from_slice_unchecked_mut(slice) }) + } + /// Return an iterator over the key-value pairs of the map, in their order. /// /// Equivalent to [`IndexMap::iter`]. @@ -134,6 +183,62 @@ impl Index<&Q> for EntityIndexMap { } } +impl Index<(Bound, Bound)> for EntityIndexMap { + type Output = Slice; + fn index(&self, key: (Bound, Bound)) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexMap { + type Output = Slice; + fn index(&self, key: Range) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexMap { + type Output = Slice; + fn index(&self, key: RangeFrom) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index for EntityIndexMap { + type Output = Slice; + fn index(&self, key: RangeFull) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexMap { + type Output = Slice; + fn index(&self, key: RangeInclusive) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexMap { + type Output = Slice; + fn index(&self, key: RangeTo) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexMap { + type Output = Slice; + fn index(&self, key: RangeToInclusive) -> &Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + impl Index for EntityIndexMap { type Output = V; fn index(&self, key: usize) -> &V { @@ -147,6 +252,55 @@ impl IndexMut<&Q> for EntityIndexMap { } } +impl IndexMut<(Bound, Bound)> for EntityIndexMap { + fn index_mut(&mut self, key: (Bound, Bound)) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + +impl IndexMut> for EntityIndexMap { + fn index_mut(&mut self, key: Range) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + +impl IndexMut> for EntityIndexMap { + fn index_mut(&mut self, key: RangeFrom) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + +impl IndexMut for EntityIndexMap { + fn index_mut(&mut self, key: RangeFull) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + +impl IndexMut> for EntityIndexMap { + fn index_mut(&mut self, key: RangeInclusive) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + +impl IndexMut> for EntityIndexMap { + fn index_mut(&mut self, key: RangeTo) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + +impl IndexMut> for EntityIndexMap { + fn index_mut(&mut self, key: RangeToInclusive) -> &mut Self::Output { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.index_mut(key)) } + } +} + impl IndexMut for EntityIndexMap { fn index_mut(&mut self, key: usize) -> &mut V { self.0.index_mut(key) @@ -201,6 +355,476 @@ where impl Eq for EntityIndexMap {} +/// A dynamically-sized slice of key-value pairs in an [`EntityIndexMap`]. +/// +/// Equivalent to an [`indexmap::map::Slice`] whose source [`IndexMap`] +/// uses [`EntityHash`]. +#[repr(transparent)] +pub struct Slice(PhantomData, map::Slice); + +impl Slice { + /// Returns an empty slice. + /// + /// Equivalent to [`map::Slice::new`]. + pub const fn new<'a>() -> &'a Self { + // SAFETY: The source slice is empty. + unsafe { Self::from_slice_unchecked(map::Slice::new()) } + } + + /// Returns an empty mutable slice. + /// + /// Equivalent to [`map::Slice::new_mut`]. + pub fn new_mut<'a>() -> &'a mut Self { + // SAFETY: The source slice is empty. + unsafe { Self::from_slice_unchecked_mut(map::Slice::new_mut()) } + } + + /// Constructs a [`entity::index_map::Slice`] from a [`indexmap::map::Slice`] unsafely. + /// + /// # Safety + /// + /// `slice` must stem from an [`IndexMap`] using [`EntityHash`]. + /// + /// [`entity::index_map::Slice`]: `crate::entity::index_map::Slice` + pub const unsafe fn from_slice_unchecked(slice: &map::Slice) -> &Self { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { &*(ptr::from_ref(slice) as *const Self) } + } + + /// Constructs a [`entity::index_map::Slice`] from a [`indexmap::map::Slice`] unsafely. + /// + /// # Safety + /// + /// `slice` must stem from an [`IndexMap`] using [`EntityHash`]. + /// + /// [`entity::index_map::Slice`]: `crate::entity::index_map::Slice` + pub const unsafe fn from_slice_unchecked_mut(slice: &mut map::Slice) -> &mut Self { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { &mut *(ptr::from_mut(slice) as *mut Self) } + } + + /// Casts `self` to the inner slice. + pub const fn as_inner(&self) -> &map::Slice { + &self.1 + } + + /// Constructs a boxed [`entity::index_map::Slice`] from a boxed [`indexmap::map::Slice`] unsafely. + /// + /// # Safety + /// + /// `slice` must stem from an [`IndexMap`] using [`EntityHash`]. + /// + /// [`entity::index_map::Slice`]: `crate::entity::index_map::Slice` + pub unsafe fn from_boxed_slice_unchecked(slice: Box>) -> Box { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { Box::from_raw(Box::into_raw(slice) as *mut Self) } + } + + /// Casts a reference to `self` to the inner slice. + #[expect( + clippy::borrowed_box, + reason = "We wish to access the Box API of the inner type, without consuming it." + )] + pub fn as_boxed_inner(self: &Box) -> &Box> { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { &*(ptr::from_ref(self).cast::>>()) } + } + + /// Casts `self` to the inner slice. + pub fn into_boxed_inner(self: Box) -> Box> { + // SAFETY: Slice is a transparent wrapper around indexmap::map::Slice. + unsafe { Box::from_raw(Box::into_raw(self) as *mut map::Slice) } + } + + /// Get a key-value pair by index, with mutable access to the value. + /// + /// Equivalent to [`map::Slice::get_index_mut`]. + pub fn get_index_mut(&mut self, index: usize) -> Option<(&Entity, &mut V)> { + self.1.get_index_mut(index) + } + + /// Returns a slice of key-value pairs in the given range of indices. + /// + /// Equivalent to [`map::Slice::get_range`]. + pub fn get_range>(&self, range: R) -> Option<&Self> { + self.1.get_range(range).map(|slice| + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(slice) }) + } + + /// Returns a mutable slice of key-value pairs in the given range of indices. + /// + /// Equivalent to [`map::Slice::get_range_mut`]. + pub fn get_range_mut>(&mut self, range: R) -> Option<&mut Self> { + self.1.get_range_mut(range).map(|slice| + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(slice) }) + } + + /// Get the first key-value pair, with mutable access to the value. + /// + /// Equivalent to [`map::Slice::first_mut`]. + pub fn first_mut(&mut self) -> Option<(&Entity, &mut V)> { + self.1.first_mut() + } + + /// Get the last key-value pair, with mutable access to the value. + /// + /// Equivalent to [`map::Slice::last_mut`]. + pub fn last_mut(&mut self) -> Option<(&Entity, &mut V)> { + self.1.last_mut() + } + + /// Divides one slice into two at an index. + /// + /// Equivalent to [`map::Slice::split_at`]. + pub fn split_at(&self, index: usize) -> (&Self, &Self) { + let (slice_1, slice_2) = self.1.split_at(index); + // SAFETY: These are subslices of a valid slice. + unsafe { + ( + Self::from_slice_unchecked(slice_1), + Self::from_slice_unchecked(slice_2), + ) + } + } + + /// Divides one mutable slice into two at an index. + /// + /// Equivalent to [`map::Slice::split_at_mut`]. + pub fn split_at_mut(&mut self, index: usize) -> (&mut Self, &mut Self) { + let (slice_1, slice_2) = self.1.split_at_mut(index); + // SAFETY: These are subslices of a valid slice. + unsafe { + ( + Self::from_slice_unchecked_mut(slice_1), + Self::from_slice_unchecked_mut(slice_2), + ) + } + } + + /// Returns the first key-value pair and the rest of the slice, + /// or `None` if it is empty. + /// + /// Equivalent to [`map::Slice::split_first`]. + pub fn split_first(&self) -> Option<((&Entity, &V), &Self)> { + self.1.split_first().map(|(first, rest)| { + ( + first, + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(rest) }, + ) + }) + } + + /// Returns the first key-value pair and the rest of the slice, + /// with mutable access to the value, or `None` if it is empty. + /// + /// Equivalent to [`map::Slice::split_first_mut`]. + pub fn split_first_mut(&mut self) -> Option<((&Entity, &mut V), &mut Self)> { + self.1.split_first_mut().map(|(first, rest)| { + ( + first, + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(rest) }, + ) + }) + } + + /// Returns the last key-value pair and the rest of the slice, + /// or `None` if it is empty. + /// + /// Equivalent to [`map::Slice::split_last`]. + pub fn split_last(&self) -> Option<((&Entity, &V), &Self)> { + self.1.split_last().map(|(last, rest)| { + ( + last, + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(rest) }, + ) + }) + } + + /// Returns the last key-value pair and the rest of the slice, + /// with mutable access to the value, or `None` if it is empty. + /// + /// Equivalent to [`map::Slice::split_last_mut`]. + pub fn split_last_mut(&mut self) -> Option<((&Entity, &mut V), &mut Self)> { + self.1.split_last_mut().map(|(last, rest)| { + ( + last, + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(rest) }, + ) + }) + } + + /// Return an iterator over the key-value pairs of the map slice. + /// + /// Equivalent to [`map::Slice::iter`]. + pub fn iter(&self) -> Iter<'_, V> { + Iter(self.1.iter(), PhantomData) + } + + /// Return an iterator over the key-value pairs of the map slice. + /// + /// Equivalent to [`map::Slice::iter_mut`]. + pub fn iter_mut(&mut self) -> IterMut<'_, V> { + IterMut(self.1.iter_mut(), PhantomData) + } + + /// Return an iterator over the keys of the map slice. + /// + /// Equivalent to [`map::Slice::keys`]. + pub fn keys(&self) -> Keys<'_, V> { + Keys(self.1.keys(), PhantomData) + } + + /// Return an owning iterator over the keys of the map slice. + /// + /// Equivalent to [`map::Slice::into_keys`]. + pub fn into_keys(self: Box) -> IntoKeys { + IntoKeys(self.into_boxed_inner().into_keys(), PhantomData) + } + + /// Return an iterator over mutable references to the the values of the map slice. + /// + /// Equivalent to [`map::Slice::values_mut`]. + pub fn values_mut(&mut self) -> ValuesMut<'_, Entity, V> { + self.1.values_mut() + } + + /// Return an owning iterator over the values of the map slice. + /// + /// Equivalent to [`map::Slice::into_values`]. + pub fn into_values(self: Box) -> IntoValues { + self.into_boxed_inner().into_values() + } +} + +impl Deref for Slice { + type Target = map::Slice; + + fn deref(&self) -> &Self::Target { + &self.1 + } +} + +impl Debug for Slice { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_tuple("Slice") + .field(&self.0) + .field(&&self.1) + .finish() + } +} + +impl Clone for Box> { + fn clone(&self) -> Self { + // SAFETY: This a clone of a valid slice. + unsafe { Slice::from_boxed_slice_unchecked(self.as_boxed_inner().clone()) } + } +} + +impl Default for &Slice { + fn default() -> Self { + // SAFETY: The source slice is empty. + unsafe { Slice::from_slice_unchecked(<&map::Slice>::default()) } + } +} + +impl Default for &mut Slice { + fn default() -> Self { + // SAFETY: The source slice is empty. + unsafe { Slice::from_slice_unchecked_mut(<&mut map::Slice>::default()) } + } +} + +impl Default for Box> { + fn default() -> Self { + // SAFETY: The source slice is empty. + unsafe { Slice::from_boxed_slice_unchecked(>>::default()) } + } +} + +impl From<&Slice> for Box> { + fn from(value: &Slice) -> Self { + // SAFETY: This slice is a copy of a valid slice. + unsafe { Slice::from_boxed_slice_unchecked(value.1.into()) } + } +} + +impl Hash for Slice { + fn hash(&self, state: &mut H) { + self.1.hash(state); + } +} + +impl<'a, V> IntoIterator for &'a Slice { + type Item = (&'a Entity, &'a V); + type IntoIter = Iter<'a, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter(self.1.iter(), PhantomData) + } +} + +impl<'a, V> IntoIterator for &'a mut Slice { + type Item = (&'a Entity, &'a mut V); + type IntoIter = IterMut<'a, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut(self.1.iter_mut(), PhantomData) + } +} + +impl IntoIterator for Box> { + type Item = (Entity, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter(self.into_boxed_inner().into_iter(), PhantomData) + } +} + +impl PartialOrd for Slice { + fn partial_cmp(&self, other: &Self) -> Option { + self.1.partial_cmp(&other.1) + } +} + +impl Ord for Slice { + fn cmp(&self, other: &Self) -> Ordering { + self.1.cmp(other) + } +} + +impl PartialEq for Slice { + fn eq(&self, other: &Self) -> bool { + self.1 == other.1 + } +} + +impl Eq for Slice {} + +impl Index<(Bound, Bound)> for Slice { + type Output = Self; + fn index(&self, key: (Bound, Bound)) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: Range) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeFrom) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index for Slice { + type Output = Self; + fn index(&self, key: RangeFull) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeInclusive) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeTo) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeToInclusive) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index for Slice { + type Output = V; + fn index(&self, key: usize) -> &V { + self.1.index(key) + } +} + +impl IndexMut<(Bound, Bound)> for Slice { + fn index_mut(&mut self, key: (Bound, Bound)) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut> for Slice { + fn index_mut(&mut self, key: Range) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut> for Slice { + fn index_mut(&mut self, key: RangeFrom) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut for Slice { + fn index_mut(&mut self, key: RangeFull) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut> for Slice { + fn index_mut(&mut self, key: RangeInclusive) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut> for Slice { + fn index_mut(&mut self, key: RangeTo) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut> for Slice { + fn index_mut(&mut self, key: RangeToInclusive) -> &mut Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked_mut(self.1.index_mut(key)) } + } +} + +impl IndexMut for Slice { + fn index_mut(&mut self, key: usize) -> &mut V { + self.1.index_mut(key) + } +} + /// An iterator over the entries of an [`EntityIndexMap`]. /// /// This `struct` is created by the [`EntityIndexMap::iter`] method. @@ -212,6 +836,14 @@ impl<'a, V> Iter<'a, V> { pub fn into_inner(self) -> map::Iter<'a, Entity, V> { self.0 } + + /// Returns a slice of the remaining entries in the iterator. + /// + /// Equivalent to [`map::Iter::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } } impl<'a, V> Deref for Iter<'a, V> { @@ -269,6 +901,22 @@ impl<'a, V> IterMut<'a, V> { pub fn into_inner(self) -> map::IterMut<'a, Entity, V> { self.0 } + + /// Returns a slice of the remaining entries in the iterator. + /// + /// Equivalent to [`map::IterMut::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } + + /// Returns a mutable slice of the remaining entries in the iterator. + /// + /// Equivalent to [`map::IterMut::into_slice`]. + pub fn into_slice(self) -> &'a mut Slice { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.into_slice()) } + } } impl<'a, V> Deref for IterMut<'a, V> { @@ -323,6 +971,22 @@ impl IntoIter { pub fn into_inner(self) -> map::IntoIter { self.0 } + + /// Returns a slice of the remaining entries in the iterator. + /// + /// Equivalent to [`map::IntoIter::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } + + /// Returns a mutable slice of the remaining entries in the iterator. + /// + /// Equivalent to [`map::IntoIter::as_mut_slice`]. + pub fn as_mut_slice(&mut self) -> &mut Slice { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked_mut(self.0.as_mut_slice()) } + } } impl Deref for IntoIter { @@ -383,6 +1047,14 @@ impl<'a, V> Drain<'a, V> { pub fn into_inner(self) -> map::Drain<'a, Entity, V> { self.0 } + + /// Returns a slice of the remaining entries in the iterator. + /// + /// Equivalent to [`map::Drain::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexMap uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } } impl<'a, V> Deref for Drain<'a, V> { diff --git a/crates/bevy_ecs/src/entity/index_set.rs b/crates/bevy_ecs/src/entity/index_set.rs index b7cb5f82ea..1af46994f6 100644 --- a/crates/bevy_ecs/src/entity/index_set.rs +++ b/crates/bevy_ecs/src/entity/index_set.rs @@ -3,17 +3,25 @@ //! This module is a lightweight wrapper around `indexmap`'ss [`IndexSet`] that is more performant for [`Entity`] keys. use core::{ + cmp::Ordering, fmt::{self, Debug, Formatter}, hash::BuildHasher, + hash::{Hash, Hasher}, iter::FusedIterator, marker::PhantomData, - ops::{BitAnd, BitOr, BitXor, Deref, DerefMut, Index, RangeBounds, Sub}, + ops::{ + BitAnd, BitOr, BitXor, Bound, Deref, DerefMut, Index, Range, RangeBounds, RangeFrom, + RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Sub, + }, + ptr, }; use indexmap::set::{self, IndexSet}; use super::{Entity, EntityHash, EntitySetIterator}; +use bevy_platform_support::prelude::Box; + /// An [`IndexSet`] pre-configured to use [`EntityHash`] hashing. #[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))] #[derive(Debug, Clone, Default)] @@ -43,6 +51,14 @@ impl EntityIndexSet { self.0 } + /// Returns a slice of all the values in the set. + /// + /// Equivalent to [`IndexSet::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } + /// Clears the `IndexSet` in the given index range, returning those values /// as a drain iterator. /// @@ -51,12 +67,29 @@ impl EntityIndexSet { Drain(self.0.drain(range), PhantomData) } + /// Returns a slice of values in the given range of indices. + /// + /// Equivalent to [`IndexSet::get_range`]. + pub fn get_range>(&self, range: R) -> Option<&Slice> { + self.0.get_range(range).map(|slice| + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(slice) }) + } + /// Return an iterator over the values of the set, in their order. /// /// Equivalent to [`IndexSet::iter`]. pub fn iter(&self) -> Iter<'_> { Iter(self.0.iter(), PhantomData) } + + /// Converts into a boxed slice of all the values in the set. + /// + /// Equivalent to [`IndexSet::into_boxed_slice`]. + pub fn into_boxed_slice(self) -> Box { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { Slice::from_boxed_slice_unchecked(self.0.into_boxed_slice()) } + } } impl Deref for EntityIndexSet { @@ -166,6 +199,62 @@ impl PartialEq for EntityIndexSet { impl Eq for EntityIndexSet {} +impl Index<(Bound, Bound)> for EntityIndexSet { + type Output = Slice; + fn index(&self, key: (Bound, Bound)) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexSet { + type Output = Slice; + fn index(&self, key: Range) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexSet { + type Output = Slice; + fn index(&self, key: RangeFrom) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index for EntityIndexSet { + type Output = Slice; + fn index(&self, key: RangeFull) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexSet { + type Output = Slice; + fn index(&self, key: RangeInclusive) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexSet { + type Output = Slice; + fn index(&self, key: RangeTo) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + +impl Index> for EntityIndexSet { + type Output = Slice; + fn index(&self, key: RangeToInclusive) -> &Self::Output { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.index(key)) } + } +} + impl Index for EntityIndexSet { type Output = Entity; fn index(&self, key: usize) -> &Entity { @@ -173,6 +262,290 @@ impl Index for EntityIndexSet { } } +/// A dynamically-sized slice of values in an [`EntityIndexSet`]. +/// +/// Equivalent to an [`indexmap::set::Slice`] whose source [`IndexSet`] +/// uses [`EntityHash`]. +#[repr(transparent)] +pub struct Slice(PhantomData, set::Slice); + +impl Slice { + /// Returns an empty slice. + /// + /// Equivalent to [`set::Slice::new`]. + pub const fn new<'a>() -> &'a Self { + // SAFETY: The source slice is empty. + unsafe { Self::from_slice_unchecked(set::Slice::new()) } + } + + /// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely. + /// + /// # Safety + /// + /// `slice` must stem from an [`IndexSet`] using [`EntityHash`]. + /// + /// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice` + pub const unsafe fn from_slice_unchecked(slice: &set::Slice) -> &Self { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { &*(ptr::from_ref(slice) as *const Self) } + } + + /// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely. + /// + /// # Safety + /// + /// `slice` must stem from an [`IndexSet`] using [`EntityHash`]. + /// + /// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice` + pub const unsafe fn from_slice_unchecked_mut(slice: &mut set::Slice) -> &mut Self { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { &mut *(ptr::from_mut(slice) as *mut Self) } + } + + /// Casts `self` to the inner slice. + pub const fn as_inner(&self) -> &set::Slice { + &self.1 + } + + /// Constructs a boxed [`entity::index_set::Slice`] from a boxed [`indexmap::set::Slice`] unsafely. + /// + /// # Safety + /// + /// `slice` must stem from an [`IndexSet`] using [`EntityHash`]. + /// + /// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice` + pub unsafe fn from_boxed_slice_unchecked(slice: Box>) -> Box { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { Box::from_raw(Box::into_raw(slice) as *mut Self) } + } + + /// Casts a reference to `self` to the inner slice. + #[expect( + clippy::borrowed_box, + reason = "We wish to access the Box API of the inner type, without consuming it." + )] + pub fn as_boxed_inner(self: &Box) -> &Box> { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { &*(ptr::from_ref(self).cast::>>()) } + } + + /// Casts `self` to the inner slice. + pub fn into_boxed_inner(self: Box) -> Box> { + // SAFETY: Slice is a transparent wrapper around indexmap::set::Slice. + unsafe { Box::from_raw(Box::into_raw(self) as *mut set::Slice) } + } + + /// Returns a slice of values in the given range of indices. + /// + /// Equivalent to [`set::Slice::get_range`]. + pub fn get_range>(&self, range: R) -> Option<&Self> { + self.1.get_range(range).map(|slice| + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(slice) }) + } + + /// Divides one slice into two at an index. + /// + /// Equivalent to [`set::Slice::split_at`]. + pub fn split_at(&self, index: usize) -> (&Self, &Self) { + let (slice_1, slice_2) = self.1.split_at(index); + // SAFETY: These are subslices of a valid slice. + unsafe { + ( + Self::from_slice_unchecked(slice_1), + Self::from_slice_unchecked(slice_2), + ) + } + } + + /// Returns the first value and the rest of the slice, + /// or `None` if it is empty. + /// + /// Equivalent to [`set::Slice::split_first`]. + pub fn split_first(&self) -> Option<(&Entity, &Self)> { + self.1.split_first().map(|(first, rest)| { + ( + first, + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(rest) }, + ) + }) + } + + /// Returns the last value and the rest of the slice, + /// or `None` if it is empty. + /// + /// Equivalent to [`set::Slice::split_last`]. + pub fn split_last(&self) -> Option<(&Entity, &Self)> { + self.1.split_last().map(|(last, rest)| { + ( + last, + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(rest) }, + ) + }) + } + + /// Return an iterator over the values of the set slice. + /// + /// Equivalent to [`set::Slice::iter`]. + pub fn iter(&self) -> Iter<'_> { + Iter(self.1.iter(), PhantomData) + } +} + +impl Deref for Slice { + type Target = set::Slice; + + fn deref(&self) -> &Self::Target { + &self.1 + } +} + +impl<'a> IntoIterator for &'a Slice { + type IntoIter = Iter<'a>; + type Item = &'a Entity; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Box { + type IntoIter = IntoIter; + type Item = Entity; + + fn into_iter(self) -> Self::IntoIter { + IntoIter(self.into_boxed_inner().into_iter(), PhantomData) + } +} + +impl Clone for Box { + fn clone(&self) -> Self { + // SAFETY: This is a clone of a valid slice. + unsafe { Slice::from_boxed_slice_unchecked(self.as_boxed_inner().clone()) } + } +} + +impl Default for &Slice { + fn default() -> Self { + // SAFETY: The source slice is empty. + unsafe { Slice::from_slice_unchecked(<&set::Slice>::default()) } + } +} + +impl Default for Box { + fn default() -> Self { + // SAFETY: The source slice is empty. + unsafe { Slice::from_boxed_slice_unchecked(>>::default()) } + } +} + +impl Debug for Slice { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_tuple("Slice") + .field(&self.0) + .field(&&self.1) + .finish() + } +} + +impl From<&Slice> for Box { + fn from(value: &Slice) -> Self { + // SAFETY: This slice is a copy of a valid slice. + unsafe { Slice::from_boxed_slice_unchecked(value.1.into()) } + } +} + +impl Hash for Slice { + fn hash(&self, state: &mut H) { + self.1.hash(state); + } +} + +impl PartialOrd for Slice { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Slice { + fn cmp(&self, other: &Self) -> Ordering { + self.1.cmp(other) + } +} + +impl PartialEq for Slice { + fn eq(&self, other: &Self) -> bool { + self.1 == other.1 + } +} + +impl Eq for Slice {} + +impl Index<(Bound, Bound)> for Slice { + type Output = Self; + fn index(&self, key: (Bound, Bound)) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: Range) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Slice; + fn index(&self, key: RangeFrom) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index for Slice { + type Output = Self; + fn index(&self, key: RangeFull) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeInclusive) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeTo) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index> for Slice { + type Output = Self; + fn index(&self, key: RangeToInclusive) -> &Self { + // SAFETY: This a subslice of a valid slice. + unsafe { Self::from_slice_unchecked(self.1.index(key)) } + } +} + +impl Index for Slice { + type Output = Entity; + fn index(&self, key: usize) -> &Entity { + self.1.index(key) + } +} + /// An iterator over the items of an [`EntityIndexSet`]. /// /// This struct is created by the [`iter`] method on [`EntityIndexSet`]. See its documentation for more. @@ -185,6 +558,14 @@ impl<'a> Iter<'a> { pub fn into_inner(self) -> set::Iter<'a, Entity> { self.0 } + + /// Returns a slice of the remaining entries in the iterator. + /// + /// Equivalent to [`set::Iter::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } } impl<'a> Deref for Iter<'a> { @@ -246,6 +627,14 @@ impl IntoIter { pub fn into_inner(self) -> set::IntoIter { self.0 } + + /// Returns a slice of the remaining entries in the iterator. + /// + /// Equivalent to [`set::IntoIter::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } } impl Deref for IntoIter { @@ -310,6 +699,14 @@ impl<'a> Drain<'a> { pub fn into_inner(self) -> set::Drain<'a, Entity> { self.0 } + + /// Returns a slice of the remaining entries in the iterator.$ + /// + /// Equivalent to [`set::Drain::as_slice`]. + pub fn as_slice(&self) -> &Slice { + // SAFETY: The source IndexSet uses EntityHash. + unsafe { Slice::from_slice_unchecked(self.0.as_slice()) } + } } impl<'a> Deref for Drain<'a> {