 569e2ac80f
			
		
	
	
		569e2ac80f
		
			
		
	
	
	
	
		
			
			# Objective Closes #9955. Use the same interface for all "pure" builder types: taking and returning `Self` (and not `&mut Self`). ## Solution Changed `DynamicSceneBuilder`, `SceneFilter` and `TableBuilder` to take and return `Self`. ## Changelog ### Changed - `DynamicSceneBuilder` and `SceneBuilder` methods in `bevy_ecs` now take and return `Self`. ## Migration guide When using `bevy_ecs::DynamicSceneBuilder` and `bevy_ecs::SceneBuilder`, instead of binding the builder to a variable, directly use it. Methods on those types now consume `Self`, so you will need to re-bind the builder if you don't `build` it immediately. Before: ```rust let mut scene_builder = DynamicSceneBuilder::from_world(&world); let scene = scene_builder.extract_entity(a).extract_entity(b).build(); ``` After: ```rust let scene = DynamicSceneBuilder::from_world(&world) .extract_entity(a) .extract_entity(b) .build(); ```
		
			
				
	
	
		
			958 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			958 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::{
 | |
|     component::{ComponentId, ComponentInfo, ComponentTicks, Components, Tick, TickCells},
 | |
|     entity::Entity,
 | |
|     query::DebugCheckedUnwrap,
 | |
|     storage::{blob_vec::BlobVec, ImmutableSparseSet, SparseSet},
 | |
| };
 | |
| use bevy_ptr::{OwningPtr, Ptr, PtrMut, UnsafeCellDeref};
 | |
| use bevy_utils::HashMap;
 | |
| use std::alloc::Layout;
 | |
| use std::{
 | |
|     cell::UnsafeCell,
 | |
|     ops::{Index, IndexMut},
 | |
| };
 | |
| 
 | |
| /// An opaque unique ID for a [`Table`] within a [`World`].
 | |
| ///
 | |
| /// Can be used with [`Tables::get`] to fetch the corresponding
 | |
| /// table.
 | |
| ///
 | |
| /// Each [`Archetype`] always points to a table via [`Archetype::table_id`].
 | |
| /// Multiple archetypes can point to the same table so long as the components
 | |
| /// stored in the table are identical, but do not share the same sparse set
 | |
| /// components.
 | |
| ///
 | |
| /// [`World`]: crate::world::World
 | |
| /// [`Archetype`]: crate::archetype::Archetype
 | |
| /// [`Archetype::table_id`]: crate::archetype::Archetype::table_id
 | |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | |
| // SAFETY: Must be repr(transparent) due to the safety requirements on EntityLocation
 | |
| #[repr(transparent)]
 | |
| pub struct TableId(u32);
 | |
| 
 | |
| impl TableId {
 | |
|     pub(crate) const INVALID: TableId = TableId(u32::MAX);
 | |
| 
 | |
|     /// Creates a new [`TableId`].
 | |
|     ///
 | |
|     /// `index` *must* be retrieved from calling [`TableId::index`] on a `TableId` you got
 | |
|     /// from a table of a given [`World`] or the created ID may be invalid.
 | |
|     ///
 | |
|     /// [`World`]: crate::world::World
 | |
|     #[inline]
 | |
|     pub fn new(index: usize) -> Self {
 | |
|         TableId(index as u32)
 | |
|     }
 | |
| 
 | |
|     /// Gets the underlying table index from the ID.
 | |
|     #[inline]
 | |
|     pub fn index(self) -> usize {
 | |
|         self.0 as usize
 | |
|     }
 | |
| 
 | |
|     /// The [`TableId`] of the [`Table`] without any components.
 | |
|     #[inline]
 | |
|     pub const fn empty() -> TableId {
 | |
|         TableId(0)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A opaque newtype for rows in [`Table`]s. Specifies a single row in a specific table.
 | |
| ///
 | |
| /// Values of this type are retrievable from [`Archetype::entity_table_row`] and can be
 | |
| /// used alongside [`Archetype::table_id`] to fetch the exact table and row where an
 | |
| /// [`Entity`]'s
 | |
| ///
 | |
| /// Values of this type are only valid so long as entities have not moved around.
 | |
| /// Adding and removing components from an entity, or despawning it will invalidate
 | |
| /// potentially any table row in the table the entity was previously stored in. Users
 | |
| /// should *always* fetch the appropriate row from the entity's [`Archetype`] before
 | |
| /// fetching the entity's components.
 | |
| ///
 | |
| /// [`Archetype`]: crate::archetype::Archetype
 | |
| /// [`Archetype::entity_table_row`]: crate::archetype::Archetype::entity_table_row
 | |
| /// [`Archetype::table_id`]: crate::archetype::Archetype::table_id
 | |
| /// [`Entity`]: crate::entity::Entity
 | |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | |
| // SAFETY: Must be repr(transparent) due to the safety requirements on EntityLocation
 | |
| #[repr(transparent)]
 | |
| pub struct TableRow(u32);
 | |
| 
 | |
| impl TableRow {
 | |
|     pub(crate) const INVALID: TableRow = TableRow(u32::MAX);
 | |
| 
 | |
|     /// Creates a `TableRow`.
 | |
|     #[inline]
 | |
|     pub const fn new(index: usize) -> Self {
 | |
|         Self(index as u32)
 | |
|     }
 | |
| 
 | |
|     /// Gets the index of the row.
 | |
|     #[inline]
 | |
|     pub const fn index(self) -> usize {
 | |
|         self.0 as usize
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A type-erased contiguous container for data of a homogeneous type.
 | |
| ///
 | |
| /// Conceptually, a [`Column`] is very similar to a type-erased `Vec<T>`.
 | |
| /// It also stores the change detection ticks for its components, kept in two separate
 | |
| /// contiguous buffers internally. An element shares its data across these buffers by using the
 | |
| /// same index (i.e. the entity at row 3 has it's data at index 3 and its change detection ticks at
 | |
| /// index 3). A slice to these contiguous blocks of memory can be fetched
 | |
| /// via [`Column::get_data_slice`], [`Column::get_added_ticks_slice`], and
 | |
| /// [`Column::get_changed_ticks_slice`].
 | |
| ///
 | |
| /// Like many other low-level storage types, [`Column`] has a limited and highly unsafe
 | |
| /// interface. It's highly advised to use higher level types and their safe abstractions
 | |
| /// instead of working directly with [`Column`].
 | |
| #[derive(Debug)]
 | |
| pub struct Column {
 | |
|     data: BlobVec,
 | |
|     added_ticks: Vec<UnsafeCell<Tick>>,
 | |
|     changed_ticks: Vec<UnsafeCell<Tick>>,
 | |
| }
 | |
| 
 | |
| impl Column {
 | |
|     /// Constructs a new [`Column`], configured with a component's layout and an initial `capacity`.
 | |
|     #[inline]
 | |
|     pub(crate) fn with_capacity(component_info: &ComponentInfo, capacity: usize) -> Self {
 | |
|         Column {
 | |
|             // SAFETY: component_info.drop() is valid for the types that will be inserted.
 | |
|             data: unsafe { BlobVec::new(component_info.layout(), component_info.drop(), capacity) },
 | |
|             added_ticks: Vec::with_capacity(capacity),
 | |
|             changed_ticks: Vec::with_capacity(capacity),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Fetches the [`Layout`] for the underlying type.
 | |
|     #[inline]
 | |
|     pub fn item_layout(&self) -> Layout {
 | |
|         self.data.layout()
 | |
|     }
 | |
| 
 | |
|     /// Writes component data to the column at given row.
 | |
|     /// Assumes the slot is uninitialized, drop is not called.
 | |
|     /// To overwrite existing initialized value, use `replace` instead.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// Assumes data has already been allocated for the given row.
 | |
|     #[inline]
 | |
|     pub(crate) unsafe fn initialize(&mut self, row: TableRow, data: OwningPtr<'_>, tick: Tick) {
 | |
|         debug_assert!(row.index() < self.len());
 | |
|         self.data.initialize_unchecked(row.index(), data);
 | |
|         *self.added_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
 | |
|         *self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
 | |
|     }
 | |
| 
 | |
|     /// Writes component data to the column at given row.
 | |
|     /// Assumes the slot is initialized, calls drop.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// Assumes data has already been allocated for the given row.
 | |
|     #[inline]
 | |
|     pub(crate) unsafe fn replace(&mut self, row: TableRow, data: OwningPtr<'_>, change_tick: Tick) {
 | |
|         debug_assert!(row.index() < self.len());
 | |
|         self.data.replace_unchecked(row.index(), data);
 | |
|         *self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = change_tick;
 | |
|     }
 | |
| 
 | |
|     /// Writes component data to the column at given row.
 | |
|     /// Assumes the slot is initialized, calls drop.
 | |
|     /// Does not update the Component's ticks.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// Assumes data has already been allocated for the given row.
 | |
|     #[inline]
 | |
|     pub(crate) unsafe fn replace_untracked(&mut self, row: TableRow, data: OwningPtr<'_>) {
 | |
|         debug_assert!(row.index() < self.len());
 | |
|         self.data.replace_unchecked(row.index(), data);
 | |
|     }
 | |
| 
 | |
|     /// Gets the current number of elements stored in the column.
 | |
|     #[inline]
 | |
|     pub fn len(&self) -> usize {
 | |
|         self.data.len()
 | |
|     }
 | |
| 
 | |
|     /// Checks if the column is empty. Returns `true` if there are no elements, `false` otherwise.
 | |
|     #[inline]
 | |
|     pub fn is_empty(&self) -> bool {
 | |
|         self.data.is_empty()
 | |
|     }
 | |
| 
 | |
|     /// Removes an element from the [`Column`].
 | |
|     ///
 | |
|     /// - The value will be dropped if it implements [`Drop`].
 | |
|     /// - This does not preserve ordering, but is O(1).
 | |
|     /// - This does not do any bounds checking.
 | |
|     /// - The element is replaced with the last element in the [`Column`].
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be within the range `[0, self.len())`.
 | |
|     ///
 | |
|     /// [`Drop`]: std::ops::Drop
 | |
|     #[inline]
 | |
|     pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) {
 | |
|         self.data.swap_remove_and_drop_unchecked(row.index());
 | |
|         self.added_ticks.swap_remove(row.index());
 | |
|         self.changed_ticks.swap_remove(row.index());
 | |
|     }
 | |
| 
 | |
|     /// Removes an element from the [`Column`] and returns it and its change detection ticks.
 | |
|     /// This does not preserve ordering, but is O(1).
 | |
|     ///
 | |
|     /// The element is replaced with the last element in the [`Column`].
 | |
|     ///
 | |
|     /// It is the caller's responsibility to ensure that the removed value is dropped or used.
 | |
|     /// Failure to do so may result in resources not being released (i.e. files handles not being
 | |
|     /// released, memory leaks, etc.)
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     #[inline]
 | |
|     #[must_use = "The returned pointer should be used to drop the removed component"]
 | |
|     pub(crate) fn swap_remove_and_forget(
 | |
|         &mut self,
 | |
|         row: TableRow,
 | |
|     ) -> Option<(OwningPtr<'_>, ComponentTicks)> {
 | |
|         (row.index() < self.data.len()).then(|| {
 | |
|             // SAFETY: The row was length checked before this.
 | |
|             let data = unsafe { self.data.swap_remove_and_forget_unchecked(row.index()) };
 | |
|             let added = self.added_ticks.swap_remove(row.index()).into_inner();
 | |
|             let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
 | |
|             (data, ComponentTicks { added, changed })
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     /// Removes an element from the [`Column`] and returns it and its change detection ticks.
 | |
|     /// This does not preserve ordering, but is O(1). Unlike [`Column::swap_remove_and_forget`]
 | |
|     /// this does not do any bounds checking.
 | |
|     ///
 | |
|     /// The element is replaced with the last element in the [`Column`].
 | |
|     ///
 | |
|     /// It's the caller's responsibility to ensure that the removed value is dropped or used.
 | |
|     /// Failure to do so may result in resources not being released (i.e. files handles not being
 | |
|     /// released, memory leaks, etc.)
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be within the range `[0, self.len())`.
 | |
|     #[inline]
 | |
|     #[must_use = "The returned pointer should be used to dropped the removed component"]
 | |
|     pub(crate) unsafe fn swap_remove_and_forget_unchecked(
 | |
|         &mut self,
 | |
|         row: TableRow,
 | |
|     ) -> (OwningPtr<'_>, ComponentTicks) {
 | |
|         let data = self.data.swap_remove_and_forget_unchecked(row.index());
 | |
|         let added = self.added_ticks.swap_remove(row.index()).into_inner();
 | |
|         let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
 | |
|         (data, ComponentTicks { added, changed })
 | |
|     }
 | |
| 
 | |
|     /// Removes the element from `other` at `src_row` and inserts it
 | |
|     /// into the current column to initialize the values at `dst_row`.
 | |
|     /// Does not do any bounds checking.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     ///  - `other` must have the same data layout as `self`
 | |
|     ///  - `src_row` must be in bounds for `other`
 | |
|     ///  - `dst_row` must be in bounds for `self`
 | |
|     ///  - `other[src_row]` must be initialized to a valid value.
 | |
|     ///  - `self[dst_row]` must not be initialized yet.
 | |
|     #[inline]
 | |
|     pub(crate) unsafe fn initialize_from_unchecked(
 | |
|         &mut self,
 | |
|         other: &mut Column,
 | |
|         src_row: TableRow,
 | |
|         dst_row: TableRow,
 | |
|     ) {
 | |
|         debug_assert!(self.data.layout() == other.data.layout());
 | |
|         let ptr = self.data.get_unchecked_mut(dst_row.index());
 | |
|         other.data.swap_remove_unchecked(src_row.index(), ptr);
 | |
|         *self.added_ticks.get_unchecked_mut(dst_row.index()) =
 | |
|             other.added_ticks.swap_remove(src_row.index());
 | |
|         *self.changed_ticks.get_unchecked_mut(dst_row.index()) =
 | |
|             other.changed_ticks.swap_remove(src_row.index());
 | |
|     }
 | |
| 
 | |
|     /// Pushes a new value onto the end of the [`Column`].
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `ptr` must point to valid data of this column's component type
 | |
|     pub(crate) unsafe fn push(&mut self, ptr: OwningPtr<'_>, ticks: ComponentTicks) {
 | |
|         self.data.push(ptr);
 | |
|         self.added_ticks.push(UnsafeCell::new(ticks.added));
 | |
|         self.changed_ticks.push(UnsafeCell::new(ticks.changed));
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     pub(crate) fn reserve_exact(&mut self, additional: usize) {
 | |
|         self.data.reserve_exact(additional);
 | |
|         self.added_ticks.reserve_exact(additional);
 | |
|         self.changed_ticks.reserve_exact(additional);
 | |
|     }
 | |
| 
 | |
|     /// Fetches the data pointer to the first element of the [`Column`].
 | |
|     ///
 | |
|     /// The pointer is type erased, so using this function to fetch anything
 | |
|     /// other than the first element will require computing the offset using
 | |
|     /// [`Column::item_layout`].
 | |
|     #[inline]
 | |
|     pub fn get_data_ptr(&self) -> Ptr<'_> {
 | |
|         self.data.get_ptr()
 | |
|     }
 | |
| 
 | |
|     /// Fetches the slice to the [`Column`]'s data cast to a given type.
 | |
|     ///
 | |
|     /// Note: The values stored within are [`UnsafeCell`].
 | |
|     /// Users of this API must ensure that accesses to each individual element
 | |
|     /// adhere to the safety invariants of [`UnsafeCell`].
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// The type `T` must be the type of the items in this column.
 | |
|     ///
 | |
|     /// [`UnsafeCell`]: std::cell::UnsafeCell
 | |
|     pub unsafe fn get_data_slice<T>(&self) -> &[UnsafeCell<T>] {
 | |
|         self.data.get_slice()
 | |
|     }
 | |
| 
 | |
|     /// Fetches the slice to the [`Column`]'s "added" change detection ticks.
 | |
|     ///
 | |
|     /// Note: The values stored within are [`UnsafeCell`].
 | |
|     /// Users of this API must ensure that accesses to each individual element
 | |
|     /// adhere to the safety invariants of [`UnsafeCell`].
 | |
|     ///
 | |
|     /// [`UnsafeCell`]: std::cell::UnsafeCell
 | |
|     #[inline]
 | |
|     pub fn get_added_ticks_slice(&self) -> &[UnsafeCell<Tick>] {
 | |
|         &self.added_ticks
 | |
|     }
 | |
| 
 | |
|     /// Fetches the slice to the [`Column`]'s "changed" change detection ticks.
 | |
|     ///
 | |
|     /// Note: The values stored within are [`UnsafeCell`].
 | |
|     /// Users of this API must ensure that accesses to each individual element
 | |
|     /// adhere to the safety invariants of [`UnsafeCell`].
 | |
|     ///
 | |
|     /// [`UnsafeCell`]: std::cell::UnsafeCell
 | |
|     #[inline]
 | |
|     pub fn get_changed_ticks_slice(&self) -> &[UnsafeCell<Tick>] {
 | |
|         &self.changed_ticks
 | |
|     }
 | |
| 
 | |
|     /// Fetches a reference to the data and change detection ticks at `row`.
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     #[inline]
 | |
|     pub fn get(&self, row: TableRow) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | |
|         (row.index() < self.data.len())
 | |
|             // SAFETY: The row is length checked before fetching the pointer. This is being
 | |
|             // accessed through a read-only reference to the column.
 | |
|             .then(|| unsafe {
 | |
|                 (
 | |
|                     self.data.get_unchecked(row.index()),
 | |
|                     TickCells {
 | |
|                         added: self.added_ticks.get_unchecked(row.index()),
 | |
|                         changed: self.changed_ticks.get_unchecked(row.index()),
 | |
|                     },
 | |
|                 )
 | |
|             })
 | |
|     }
 | |
| 
 | |
|     /// Fetches a read-only reference to the data at `row`.
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     #[inline]
 | |
|     pub fn get_data(&self, row: TableRow) -> Option<Ptr<'_>> {
 | |
|         // SAFETY: The row is length checked before fetching the pointer. This is being
 | |
|         // accessed through a read-only reference to the column.
 | |
|         (row.index() < self.data.len()).then(|| unsafe { self.data.get_unchecked(row.index()) })
 | |
|     }
 | |
| 
 | |
|     /// Fetches a read-only reference to the data at `row`. Unlike [`Column::get`] this does not
 | |
|     /// do any bounds checking.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `row` must be within the range `[0, self.len())`.
 | |
|     /// - no other mutable reference to the data of the same row can exist at the same time
 | |
|     #[inline]
 | |
|     pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
 | |
|         debug_assert!(row.index() < self.data.len());
 | |
|         self.data.get_unchecked(row.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches a mutable reference to the data at `row`.
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     #[inline]
 | |
|     pub fn get_data_mut(&mut self, row: TableRow) -> Option<PtrMut<'_>> {
 | |
|         // SAFETY: The row is length checked before fetching the pointer. This is being
 | |
|         // accessed through an exclusive reference to the column.
 | |
|         (row.index() < self.data.len()).then(|| unsafe { self.data.get_unchecked_mut(row.index()) })
 | |
|     }
 | |
| 
 | |
|     /// Fetches a mutable reference to the data at `row`. Unlike [`Column::get_data_mut`] this does not
 | |
|     /// do any bounds checking.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - index must be in-bounds
 | |
|     /// - no other reference to the data of the same row can exist at the same time
 | |
|     #[inline]
 | |
|     pub(crate) unsafe fn get_data_unchecked_mut(&mut self, row: TableRow) -> PtrMut<'_> {
 | |
|         debug_assert!(row.index() < self.data.len());
 | |
|         self.data.get_unchecked_mut(row.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches the "added" change detection tick for the value at `row`.
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     ///
 | |
|     /// Note: The values stored within are [`UnsafeCell`].
 | |
|     /// Users of this API must ensure that accesses to each individual element
 | |
|     /// adhere to the safety invariants of [`UnsafeCell`].
 | |
|     ///
 | |
|     /// [`UnsafeCell`]: std::cell::UnsafeCell
 | |
|     #[inline]
 | |
|     pub fn get_added_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
 | |
|         self.added_ticks.get(row.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches the "changed" change detection tick for the value at `row`.
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     ///
 | |
|     /// Note: The values stored within are [`UnsafeCell`].
 | |
|     /// Users of this API must ensure that accesses to each individual element
 | |
|     /// adhere to the safety invariants of [`UnsafeCell`].
 | |
|     ///
 | |
|     /// [`UnsafeCell`]: std::cell::UnsafeCell
 | |
|     #[inline]
 | |
|     pub fn get_changed_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
 | |
|         self.changed_ticks.get(row.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches the change detection ticks for the value at `row`.
 | |
|     ///
 | |
|     /// Returns `None` if `row` is out of bounds.
 | |
|     #[inline]
 | |
|     pub fn get_ticks(&self, row: TableRow) -> Option<ComponentTicks> {
 | |
|         if row.index() < self.data.len() {
 | |
|             // SAFETY: The size of the column has already been checked.
 | |
|             Some(unsafe { self.get_ticks_unchecked(row) })
 | |
|         } else {
 | |
|             None
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Fetches the "added" change detection tick for the value at `row`. Unlike [`Column::get_added_tick`]
 | |
|     /// this function does not do any bounds checking.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be within the range `[0, self.len())`.
 | |
|     #[inline]
 | |
|     pub unsafe fn get_added_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
 | |
|         debug_assert!(row.index() < self.added_ticks.len());
 | |
|         self.added_ticks.get_unchecked(row.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches the "changed" change detection tick for the value at `row`. Unlike [`Column::get_changed_tick`]
 | |
|     /// this function does not do any bounds checking.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be within the range `[0, self.len())`.
 | |
|     #[inline]
 | |
|     pub unsafe fn get_changed_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
 | |
|         debug_assert!(row.index() < self.changed_ticks.len());
 | |
|         self.changed_ticks.get_unchecked(row.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches the change detection ticks for the value at `row`. Unlike [`Column::get_ticks`]
 | |
|     /// this function does not do any bounds checking.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be within the range `[0, self.len())`.
 | |
|     #[inline]
 | |
|     pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
 | |
|         debug_assert!(row.index() < self.added_ticks.len());
 | |
|         debug_assert!(row.index() < self.changed_ticks.len());
 | |
|         ComponentTicks {
 | |
|             added: self.added_ticks.get_unchecked(row.index()).read(),
 | |
|             changed: self.changed_ticks.get_unchecked(row.index()).read(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Clears the column, removing all values.
 | |
|     ///
 | |
|     /// Note that this function has no effect on the allocated capacity of the [`Column`]>
 | |
|     pub fn clear(&mut self) {
 | |
|         self.data.clear();
 | |
|         self.added_ticks.clear();
 | |
|         self.changed_ticks.clear();
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
 | |
|         for component_ticks in &mut self.added_ticks {
 | |
|             component_ticks.get_mut().check_tick(change_tick);
 | |
|         }
 | |
|         for component_ticks in &mut self.changed_ticks {
 | |
|             component_ticks.get_mut().check_tick(change_tick);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A builder type for constructing [`Table`]s.
 | |
| ///
 | |
| ///  - Use [`with_capacity`] to initialize the builder.
 | |
| ///  - Repeatedly call [`add_column`] to add columns for components.
 | |
| ///  - Finalize with [`build`] to get the constructed [`Table`].
 | |
| ///
 | |
| /// [`with_capacity`]: Self::with_capacity
 | |
| /// [`add_column`]: Self::add_column
 | |
| /// [`build`]: Self::build
 | |
| pub(crate) struct TableBuilder {
 | |
|     columns: SparseSet<ComponentId, Column>,
 | |
|     capacity: usize,
 | |
| }
 | |
| 
 | |
| impl TableBuilder {
 | |
|     /// Creates a blank [`Table`], allocating space for `column_capacity` columns
 | |
|     /// with the capacity to hold `capacity` entities worth of components each.
 | |
|     pub fn with_capacity(capacity: usize, column_capacity: usize) -> Self {
 | |
|         Self {
 | |
|             columns: SparseSet::with_capacity(column_capacity),
 | |
|             capacity,
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #[must_use]
 | |
|     pub fn add_column(mut self, component_info: &ComponentInfo) -> Self {
 | |
|         self.columns.insert(
 | |
|             component_info.id(),
 | |
|             Column::with_capacity(component_info, self.capacity),
 | |
|         );
 | |
|         self
 | |
|     }
 | |
| 
 | |
|     #[must_use]
 | |
|     pub fn build(self) -> Table {
 | |
|         Table {
 | |
|             columns: self.columns.into_immutable(),
 | |
|             entities: Vec::with_capacity(self.capacity),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A column-oriented [structure-of-arrays] based storage for [`Component`]s of entities
 | |
| /// in a [`World`].
 | |
| ///
 | |
| /// Conceptually, a `Table` can be thought of as an `HashMap<ComponentId, Column>`, where
 | |
| /// each [`Column`] is a type-erased `Vec<T: Component>`. Each row corresponds to a single entity
 | |
| /// (i.e. index 3 in Column A and index 3 in Column B point to different components on the same
 | |
| /// entity). Fetching components from a table involves fetching the associated column for a
 | |
| /// component type (via its [`ComponentId`]), then fetching the entity's row within that column.
 | |
| ///
 | |
| /// [structure-of-arrays]: https://en.wikipedia.org/wiki/AoS_and_SoA#Structure_of_arrays
 | |
| /// [`Component`]: crate::component::Component
 | |
| /// [`World`]: crate::world::World
 | |
| pub struct Table {
 | |
|     columns: ImmutableSparseSet<ComponentId, Column>,
 | |
|     entities: Vec<Entity>,
 | |
| }
 | |
| 
 | |
| impl Table {
 | |
|     /// Fetches a read-only slice of the entities stored within the [`Table`].
 | |
|     #[inline]
 | |
|     pub fn entities(&self) -> &[Entity] {
 | |
|         &self.entities
 | |
|     }
 | |
| 
 | |
|     /// Removes the entity at the given row and returns the entity swapped in to replace it (if an
 | |
|     /// entity was swapped in)
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be in-bounds
 | |
|     pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) -> Option<Entity> {
 | |
|         for column in self.columns.values_mut() {
 | |
|             column.swap_remove_unchecked(row);
 | |
|         }
 | |
|         let is_last = row.index() == self.entities.len() - 1;
 | |
|         self.entities.swap_remove(row.index());
 | |
|         if is_last {
 | |
|             None
 | |
|         } else {
 | |
|             Some(self.entities[row.index()])
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Moves the `row` column values to `new_table`, for the columns shared between both tables.
 | |
|     /// Returns the index of the new row in `new_table` and the entity in this table swapped in
 | |
|     /// to replace it (if an entity was swapped in). missing columns will be "forgotten". It is
 | |
|     /// the caller's responsibility to drop them.  Failure to do so may result in resources not
 | |
|     /// being released (i.e. files handles not being released, memory leaks, etc.)
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// Row must be in-bounds
 | |
|     pub(crate) unsafe fn move_to_and_forget_missing_unchecked(
 | |
|         &mut self,
 | |
|         row: TableRow,
 | |
|         new_table: &mut Table,
 | |
|     ) -> TableMoveResult {
 | |
|         debug_assert!(row.index() < self.entity_count());
 | |
|         let is_last = row.index() == self.entities.len() - 1;
 | |
|         let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
 | |
|         for (component_id, column) in self.columns.iter_mut() {
 | |
|             if let Some(new_column) = new_table.get_column_mut(*component_id) {
 | |
|                 new_column.initialize_from_unchecked(column, row, new_row);
 | |
|             } else {
 | |
|                 // It's the caller's responsibility to drop these cases.
 | |
|                 let (_, _) = column.swap_remove_and_forget_unchecked(row);
 | |
|             }
 | |
|         }
 | |
|         TableMoveResult {
 | |
|             new_row,
 | |
|             swapped_entity: if is_last {
 | |
|                 None
 | |
|             } else {
 | |
|                 Some(self.entities[row.index()])
 | |
|             },
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Moves the `row` column values to `new_table`, for the columns shared between both tables.
 | |
|     /// Returns the index of the new row in `new_table` and the entity in this table swapped in
 | |
|     /// to replace it (if an entity was swapped in).
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// row must be in-bounds
 | |
|     pub(crate) unsafe fn move_to_and_drop_missing_unchecked(
 | |
|         &mut self,
 | |
|         row: TableRow,
 | |
|         new_table: &mut Table,
 | |
|     ) -> TableMoveResult {
 | |
|         debug_assert!(row.index() < self.entity_count());
 | |
|         let is_last = row.index() == self.entities.len() - 1;
 | |
|         let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
 | |
|         for (component_id, column) in self.columns.iter_mut() {
 | |
|             if let Some(new_column) = new_table.get_column_mut(*component_id) {
 | |
|                 new_column.initialize_from_unchecked(column, row, new_row);
 | |
|             } else {
 | |
|                 column.swap_remove_unchecked(row);
 | |
|             }
 | |
|         }
 | |
|         TableMoveResult {
 | |
|             new_row,
 | |
|             swapped_entity: if is_last {
 | |
|                 None
 | |
|             } else {
 | |
|                 Some(self.entities[row.index()])
 | |
|             },
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Moves the `row` column values to `new_table`, for the columns shared between both tables.
 | |
|     /// Returns the index of the new row in `new_table` and the entity in this table swapped in
 | |
|     /// to replace it (if an entity was swapped in).
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `row` must be in-bounds. `new_table` must contain every component this table has
 | |
|     pub(crate) unsafe fn move_to_superset_unchecked(
 | |
|         &mut self,
 | |
|         row: TableRow,
 | |
|         new_table: &mut Table,
 | |
|     ) -> TableMoveResult {
 | |
|         debug_assert!(row.index() < self.entity_count());
 | |
|         let is_last = row.index() == self.entities.len() - 1;
 | |
|         let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
 | |
|         for (component_id, column) in self.columns.iter_mut() {
 | |
|             new_table
 | |
|                 .get_column_mut(*component_id)
 | |
|                 .debug_checked_unwrap()
 | |
|                 .initialize_from_unchecked(column, row, new_row);
 | |
|         }
 | |
|         TableMoveResult {
 | |
|             new_row,
 | |
|             swapped_entity: if is_last {
 | |
|                 None
 | |
|             } else {
 | |
|                 Some(self.entities[row.index()])
 | |
|             },
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Fetches a read-only reference to the [`Column`] for a given [`Component`] within the
 | |
|     /// table.
 | |
|     ///
 | |
|     /// Returns `None` if the corresponding component does not belong to the table.
 | |
|     ///
 | |
|     /// [`Component`]: crate::component::Component
 | |
|     #[inline]
 | |
|     pub fn get_column(&self, component_id: ComponentId) -> Option<&Column> {
 | |
|         self.columns.get(component_id)
 | |
|     }
 | |
| 
 | |
|     /// Fetches a mutable reference to the [`Column`] for a given [`Component`] within the
 | |
|     /// table.
 | |
|     ///
 | |
|     /// Returns `None` if the corresponding component does not belong to the table.
 | |
|     ///
 | |
|     /// [`Component`]: crate::component::Component
 | |
|     #[inline]
 | |
|     pub(crate) fn get_column_mut(&mut self, component_id: ComponentId) -> Option<&mut Column> {
 | |
|         self.columns.get_mut(component_id)
 | |
|     }
 | |
| 
 | |
|     /// Checks if the table contains a [`Column`] for a given [`Component`].
 | |
|     ///
 | |
|     /// Returns `true` if the column is present, `false` otherwise.
 | |
|     ///
 | |
|     /// [`Component`]: crate::component::Component
 | |
|     #[inline]
 | |
|     pub fn has_column(&self, component_id: ComponentId) -> bool {
 | |
|         self.columns.contains(component_id)
 | |
|     }
 | |
| 
 | |
|     /// Reserves `additional` elements worth of capacity within the table.
 | |
|     pub(crate) fn reserve(&mut self, additional: usize) {
 | |
|         if self.entities.capacity() - self.entities.len() < additional {
 | |
|             self.entities.reserve(additional);
 | |
| 
 | |
|             // use entities vector capacity as driving capacity for all related allocations
 | |
|             let new_capacity = self.entities.capacity();
 | |
| 
 | |
|             for column in self.columns.values_mut() {
 | |
|                 column.reserve_exact(new_capacity - column.len());
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Allocates space for a new entity
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// the allocated row must be written to immediately with valid values in each column
 | |
|     pub(crate) unsafe fn allocate(&mut self, entity: Entity) -> TableRow {
 | |
|         self.reserve(1);
 | |
|         let index = self.entities.len();
 | |
|         self.entities.push(entity);
 | |
|         for column in self.columns.values_mut() {
 | |
|             column.data.set_len(self.entities.len());
 | |
|             column.added_ticks.push(UnsafeCell::new(Tick::new(0)));
 | |
|             column.changed_ticks.push(UnsafeCell::new(Tick::new(0)));
 | |
|         }
 | |
|         TableRow::new(index)
 | |
|     }
 | |
| 
 | |
|     /// Gets the number of entities currently being stored in the table.
 | |
|     #[inline]
 | |
|     pub fn entity_count(&self) -> usize {
 | |
|         self.entities.len()
 | |
|     }
 | |
| 
 | |
|     /// Gets the number of components being stored in the table.
 | |
|     #[inline]
 | |
|     pub fn component_count(&self) -> usize {
 | |
|         self.columns.len()
 | |
|     }
 | |
| 
 | |
|     /// Gets the maximum number of entities the table can currently store
 | |
|     /// without reallocating the underlying memory.
 | |
|     #[inline]
 | |
|     pub fn entity_capacity(&self) -> usize {
 | |
|         self.entities.capacity()
 | |
|     }
 | |
| 
 | |
|     /// Checks if the [`Table`] is empty or not.
 | |
|     ///
 | |
|     /// Returns `true` if the table contains no entities, `false` otherwise.
 | |
|     #[inline]
 | |
|     pub fn is_empty(&self) -> bool {
 | |
|         self.entities.is_empty()
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
 | |
|         for column in self.columns.values_mut() {
 | |
|             column.check_change_ticks(change_tick);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Iterates over the [`Column`]s of the [`Table`].
 | |
|     pub fn iter(&self) -> impl Iterator<Item = &Column> {
 | |
|         self.columns.values()
 | |
|     }
 | |
| 
 | |
|     /// Clears all of the stored components in the [`Table`].
 | |
|     pub(crate) fn clear(&mut self) {
 | |
|         self.entities.clear();
 | |
|         for column in self.columns.values_mut() {
 | |
|             column.clear();
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A collection of [`Table`] storages, indexed by [`TableId`]
 | |
| ///
 | |
| /// Can be accessed via [`Storages`](crate::storage::Storages)
 | |
| pub struct Tables {
 | |
|     tables: Vec<Table>,
 | |
|     table_ids: HashMap<Vec<ComponentId>, TableId>,
 | |
| }
 | |
| 
 | |
| impl Default for Tables {
 | |
|     fn default() -> Self {
 | |
|         let empty_table = TableBuilder::with_capacity(0, 0).build();
 | |
|         Tables {
 | |
|             tables: vec![empty_table],
 | |
|             table_ids: HashMap::default(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub(crate) struct TableMoveResult {
 | |
|     pub swapped_entity: Option<Entity>,
 | |
|     pub new_row: TableRow,
 | |
| }
 | |
| 
 | |
| impl Tables {
 | |
|     /// Returns the number of [`Table`]s this collection contains
 | |
|     #[inline]
 | |
|     pub fn len(&self) -> usize {
 | |
|         self.tables.len()
 | |
|     }
 | |
| 
 | |
|     /// Returns true if this collection contains no [`Table`]s
 | |
|     #[inline]
 | |
|     pub fn is_empty(&self) -> bool {
 | |
|         self.tables.is_empty()
 | |
|     }
 | |
| 
 | |
|     /// Fetches a [`Table`] by its [`TableId`].
 | |
|     ///
 | |
|     /// Returns `None` if `id` is invalid.
 | |
|     #[inline]
 | |
|     pub fn get(&self, id: TableId) -> Option<&Table> {
 | |
|         self.tables.get(id.index())
 | |
|     }
 | |
| 
 | |
|     /// Fetches mutable references to two different [`Table`]s.
 | |
|     ///
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `a` and `b` are equal.
 | |
|     #[inline]
 | |
|     pub(crate) fn get_2_mut(&mut self, a: TableId, b: TableId) -> (&mut Table, &mut Table) {
 | |
|         if a.index() > b.index() {
 | |
|             let (b_slice, a_slice) = self.tables.split_at_mut(a.index());
 | |
|             (&mut a_slice[0], &mut b_slice[b.index()])
 | |
|         } else {
 | |
|             let (a_slice, b_slice) = self.tables.split_at_mut(b.index());
 | |
|             (&mut a_slice[a.index()], &mut b_slice[0])
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Attempts to fetch a table based on the provided components,
 | |
|     /// creating and returning a new [`Table`] if one did not already exist.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `component_ids` must contain components that exist in `components`
 | |
|     pub(crate) unsafe fn get_id_or_insert(
 | |
|         &mut self,
 | |
|         component_ids: &[ComponentId],
 | |
|         components: &Components,
 | |
|     ) -> TableId {
 | |
|         let tables = &mut self.tables;
 | |
|         let (_key, value) = self
 | |
|             .table_ids
 | |
|             .raw_entry_mut()
 | |
|             .from_key(component_ids)
 | |
|             .or_insert_with(|| {
 | |
|                 let mut table = TableBuilder::with_capacity(0, component_ids.len());
 | |
|                 for component_id in component_ids {
 | |
|                     table = table.add_column(components.get_info_unchecked(*component_id));
 | |
|                 }
 | |
|                 tables.push(table.build());
 | |
|                 (component_ids.to_vec(), TableId::new(tables.len() - 1))
 | |
|             });
 | |
| 
 | |
|         *value
 | |
|     }
 | |
| 
 | |
|     /// Iterates through all of the tables stored within in [`TableId`] order.
 | |
|     pub fn iter(&self) -> std::slice::Iter<'_, Table> {
 | |
|         self.tables.iter()
 | |
|     }
 | |
| 
 | |
|     /// Clears all data from all [`Table`]s stored within.
 | |
|     pub(crate) fn clear(&mut self) {
 | |
|         for table in &mut self.tables {
 | |
|             table.clear();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
 | |
|         for table in &mut self.tables {
 | |
|             table.check_change_ticks(change_tick);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Index<TableId> for Tables {
 | |
|     type Output = Table;
 | |
| 
 | |
|     #[inline]
 | |
|     fn index(&self, index: TableId) -> &Self::Output {
 | |
|         &self.tables[index.index()]
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl IndexMut<TableId> for Tables {
 | |
|     #[inline]
 | |
|     fn index_mut(&mut self, index: TableId) -> &mut Self::Output {
 | |
|         &mut self.tables[index.index()]
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(test)]
 | |
| mod tests {
 | |
|     use crate as bevy_ecs;
 | |
|     use crate::component::Component;
 | |
|     use crate::ptr::OwningPtr;
 | |
|     use crate::storage::Storages;
 | |
|     use crate::{
 | |
|         component::{Components, Tick},
 | |
|         entity::Entity,
 | |
|         storage::{TableBuilder, TableRow},
 | |
|     };
 | |
|     #[derive(Component)]
 | |
|     struct W<T>(T);
 | |
| 
 | |
|     #[test]
 | |
|     fn table() {
 | |
|         let mut components = Components::default();
 | |
|         let mut storages = Storages::default();
 | |
|         let component_id = components.init_component::<W<TableRow>>(&mut storages);
 | |
|         let columns = &[component_id];
 | |
|         let mut table = TableBuilder::with_capacity(0, columns.len())
 | |
|             .add_column(components.get_info(component_id).unwrap())
 | |
|             .build();
 | |
|         let entities = (0..200).map(Entity::from_raw).collect::<Vec<_>>();
 | |
|         for entity in &entities {
 | |
|             // SAFETY: we allocate and immediately set data afterwards
 | |
|             unsafe {
 | |
|                 let row = table.allocate(*entity);
 | |
|                 let value: W<TableRow> = W(row);
 | |
|                 OwningPtr::make(value, |value_ptr| {
 | |
|                     table.get_column_mut(component_id).unwrap().initialize(
 | |
|                         row,
 | |
|                         value_ptr,
 | |
|                         Tick::new(0),
 | |
|                     );
 | |
|                 });
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         assert_eq!(table.entity_capacity(), 256);
 | |
|         assert_eq!(table.entity_count(), 200);
 | |
|     }
 | |
| }
 |