Newtype ArchetypeRow and TableRow (#4878)
# Objective Prevent future unsoundness that was seen in #6623. ## Solution Newtype both indexes in `Archetype` and `Table` as `ArchetypeRow` and `TableRow`. This avoids weird numerical manipulation on the indices, and can be stored and treated opaquely. Also enforces the source and destination of where these indices at a type level. --- ## Changelog Changed: `Archetype` indices and `Table` rows have been newtyped as `ArchetypeRow` and `TableRow`.
This commit is contained in:
		
							parent
							
								
									a3f203b504
								
							
						
					
					
						commit
						530be10e72
					
				@ -283,7 +283,7 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
 | 
				
			|||||||
                unsafe fn fetch<'__w>(
 | 
					                unsafe fn fetch<'__w>(
 | 
				
			||||||
                    _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
 | 
					                    _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
 | 
				
			||||||
                    _entity: #path::entity::Entity,
 | 
					                    _entity: #path::entity::Entity,
 | 
				
			||||||
                    _table_row: usize
 | 
					                    _table_row: #path::storage::TableRow,
 | 
				
			||||||
                ) -> <Self as #path::query::WorldQuery>::Item<'__w> {
 | 
					                ) -> <Self as #path::query::WorldQuery>::Item<'__w> {
 | 
				
			||||||
                    Self::Item {
 | 
					                    Self::Item {
 | 
				
			||||||
                        #(#field_idents: <#field_types>::fetch(&mut _fetch.#field_idents, _entity, _table_row),)*
 | 
					                        #(#field_idents: <#field_types>::fetch(&mut _fetch.#field_idents, _entity, _table_row),)*
 | 
				
			||||||
@ -296,7 +296,7 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
 | 
				
			|||||||
                unsafe fn filter_fetch<'__w>(
 | 
					                unsafe fn filter_fetch<'__w>(
 | 
				
			||||||
                    _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
 | 
					                    _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
 | 
				
			||||||
                    _entity: #path::entity::Entity,
 | 
					                    _entity: #path::entity::Entity,
 | 
				
			||||||
                    _table_row: usize
 | 
					                    _table_row: #path::storage::TableRow,
 | 
				
			||||||
                ) -> bool {
 | 
					                ) -> bool {
 | 
				
			||||||
                    true #(&& <#field_types>::filter_fetch(&mut _fetch.#field_idents, _entity, _table_row))*
 | 
					                    true #(&& <#field_types>::filter_fetch(&mut _fetch.#field_idents, _entity, _table_row))*
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ use crate::{
 | 
				
			|||||||
    bundle::BundleId,
 | 
					    bundle::BundleId,
 | 
				
			||||||
    component::{ComponentId, StorageType},
 | 
					    component::{ComponentId, StorageType},
 | 
				
			||||||
    entity::{Entity, EntityLocation},
 | 
					    entity::{Entity, EntityLocation},
 | 
				
			||||||
    storage::{ImmutableSparseSet, SparseArray, SparseSet, SparseSetIndex, TableId},
 | 
					    storage::{ImmutableSparseSet, SparseArray, SparseSet, SparseSetIndex, TableId, TableRow},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    collections::HashMap,
 | 
					    collections::HashMap,
 | 
				
			||||||
@ -31,6 +31,33 @@ use std::{
 | 
				
			|||||||
    ops::{Index, IndexMut},
 | 
					    ops::{Index, IndexMut},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// An opaque location within a [`Archetype`].
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This can be used in conjunction with [`ArchetypeId`] to find the exact location
 | 
				
			||||||
 | 
					/// of an [`Entity`] within a [`World`]. An entity's archetype and index can be
 | 
				
			||||||
 | 
					/// retrieved via [`Entities::get`].
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// [`World`]: crate::world::World
 | 
				
			||||||
 | 
					/// [`Entities::get`]: crate::entity::Entities
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone, Eq, PartialEq)]
 | 
				
			||||||
 | 
					#[repr(transparent)]
 | 
				
			||||||
 | 
					pub struct ArchetypeRow(usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ArchetypeRow {
 | 
				
			||||||
 | 
					    pub const INVALID: ArchetypeRow = ArchetypeRow(usize::MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Creates a `ArchetypeRow`.
 | 
				
			||||||
 | 
					    pub const fn new(index: usize) -> Self {
 | 
				
			||||||
 | 
					        Self(index)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Gets the index of the row.
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub const fn index(self) -> usize {
 | 
				
			||||||
 | 
					        self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// An opaque unique ID for a single [`Archetype`] within a [`World`].
 | 
					/// An opaque unique ID for a single [`Archetype`] within a [`World`].
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Archetype IDs are only valid for a given World, and are not globally unique.
 | 
					/// Archetype IDs are only valid for a given World, and are not globally unique.
 | 
				
			||||||
@ -226,7 +253,7 @@ impl Edges {
 | 
				
			|||||||
/// Metadata about an [`Entity`] in a [`Archetype`].
 | 
					/// Metadata about an [`Entity`] in a [`Archetype`].
 | 
				
			||||||
pub struct ArchetypeEntity {
 | 
					pub struct ArchetypeEntity {
 | 
				
			||||||
    entity: Entity,
 | 
					    entity: Entity,
 | 
				
			||||||
    table_row: usize,
 | 
					    table_row: TableRow,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ArchetypeEntity {
 | 
					impl ArchetypeEntity {
 | 
				
			||||||
@ -240,14 +267,14 @@ impl ArchetypeEntity {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// [`Table`]: crate::storage::Table
 | 
					    /// [`Table`]: crate::storage::Table
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub const fn table_row(&self) -> usize {
 | 
					    pub const fn table_row(&self) -> TableRow {
 | 
				
			||||||
        self.table_row
 | 
					        self.table_row
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) struct ArchetypeSwapRemoveResult {
 | 
					pub(crate) struct ArchetypeSwapRemoveResult {
 | 
				
			||||||
    pub(crate) swapped_entity: Option<Entity>,
 | 
					    pub(crate) swapped_entity: Option<Entity>,
 | 
				
			||||||
    pub(crate) table_row: usize,
 | 
					    pub(crate) table_row: TableRow,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Internal metadata for a [`Component`] within a given [`Archetype`].
 | 
					/// Internal metadata for a [`Component`] within a given [`Archetype`].
 | 
				
			||||||
@ -380,18 +407,18 @@ impl Archetype {
 | 
				
			|||||||
    /// Fetches the row in the [`Table`] where the components for the entity at `index`
 | 
					    /// Fetches the row in the [`Table`] where the components for the entity at `index`
 | 
				
			||||||
    /// is stored.
 | 
					    /// is stored.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// An entity's archetype index can be fetched from [`EntityLocation::index`], which
 | 
					    /// An entity's archetype index can be fetched from [`EntityLocation::archetype_row`], which
 | 
				
			||||||
    /// can be retrieved from [`Entities::get`].
 | 
					    /// can be retrieved from [`Entities::get`].
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    /// This function will panic if `index >= self.len()`.
 | 
					    /// This function will panic if `index >= self.len()`.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// [`Table`]: crate::storage::Table
 | 
					    /// [`Table`]: crate::storage::Table
 | 
				
			||||||
    /// [`EntityLocation`]: crate::entity::EntityLocation::index
 | 
					    /// [`EntityLocation`]: crate::entity::EntityLocation::archetype_row
 | 
				
			||||||
    /// [`Entities::get`]: crate::entity::Entities::get
 | 
					    /// [`Entities::get`]: crate::entity::Entities::get
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn entity_table_row(&self, index: usize) -> usize {
 | 
					    pub fn entity_table_row(&self, index: ArchetypeRow) -> TableRow {
 | 
				
			||||||
        self.entities[index].table_row
 | 
					        self.entities[index.0].table_row
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Updates if the components for the entity at `index` can be found
 | 
					    /// Updates if the components for the entity at `index` can be found
 | 
				
			||||||
@ -400,8 +427,8 @@ impl Archetype {
 | 
				
			|||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    /// This function will panic if `index >= self.len()`.
 | 
					    /// This function will panic if `index >= self.len()`.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) fn set_entity_table_row(&mut self, index: usize, table_row: usize) {
 | 
					    pub(crate) fn set_entity_table_row(&mut self, index: ArchetypeRow, table_row: TableRow) {
 | 
				
			||||||
        self.entities[index].table_row = table_row;
 | 
					        self.entities[index.0].table_row = table_row;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Allocates an entity to the archetype.
 | 
					    /// Allocates an entity to the archetype.
 | 
				
			||||||
@ -409,12 +436,16 @@ impl Archetype {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// valid component values must be immediately written to the relevant storages
 | 
					    /// valid component values must be immediately written to the relevant storages
 | 
				
			||||||
    /// `table_row` must be valid
 | 
					    /// `table_row` must be valid
 | 
				
			||||||
    pub(crate) unsafe fn allocate(&mut self, entity: Entity, table_row: usize) -> EntityLocation {
 | 
					    pub(crate) unsafe fn allocate(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        entity: Entity,
 | 
				
			||||||
 | 
					        table_row: TableRow,
 | 
				
			||||||
 | 
					    ) -> EntityLocation {
 | 
				
			||||||
        self.entities.push(ArchetypeEntity { entity, table_row });
 | 
					        self.entities.push(ArchetypeEntity { entity, table_row });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        EntityLocation {
 | 
					        EntityLocation {
 | 
				
			||||||
            archetype_id: self.id,
 | 
					            archetype_id: self.id,
 | 
				
			||||||
            index: self.entities.len() - 1,
 | 
					            archetype_row: ArchetypeRow(self.entities.len() - 1),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -427,14 +458,14 @@ impl Archetype {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Panics
 | 
					    /// # Panics
 | 
				
			||||||
    /// This function will panic if `index >= self.len()`
 | 
					    /// This function will panic if `index >= self.len()`
 | 
				
			||||||
    pub(crate) fn swap_remove(&mut self, index: usize) -> ArchetypeSwapRemoveResult {
 | 
					    pub(crate) fn swap_remove(&mut self, index: ArchetypeRow) -> ArchetypeSwapRemoveResult {
 | 
				
			||||||
        let is_last = index == self.entities.len() - 1;
 | 
					        let is_last = index.0 == self.entities.len() - 1;
 | 
				
			||||||
        let entity = self.entities.swap_remove(index);
 | 
					        let entity = self.entities.swap_remove(index.0);
 | 
				
			||||||
        ArchetypeSwapRemoveResult {
 | 
					        ArchetypeSwapRemoveResult {
 | 
				
			||||||
            swapped_entity: if is_last {
 | 
					            swapped_entity: if is_last {
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                Some(self.entities[index].entity)
 | 
					                Some(self.entities[index.0].entity)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            table_row: entity.table_row,
 | 
					            table_row: entity.table_row,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -6,12 +6,12 @@ pub use bevy_ecs_macros::Bundle;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    archetype::{
 | 
					    archetype::{
 | 
				
			||||||
        Archetype, ArchetypeId, Archetypes, BundleComponentStatus, ComponentStatus,
 | 
					        Archetype, ArchetypeId, ArchetypeRow, Archetypes, BundleComponentStatus, ComponentStatus,
 | 
				
			||||||
        SpawnBundleStatus,
 | 
					        SpawnBundleStatus,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    component::{Component, ComponentId, Components, StorageType, Tick},
 | 
					    component::{Component, ComponentId, Components, StorageType, Tick},
 | 
				
			||||||
    entity::{Entities, Entity, EntityLocation},
 | 
					    entity::{Entities, Entity, EntityLocation},
 | 
				
			||||||
    storage::{SparseSetIndex, SparseSets, Storages, Table},
 | 
					    storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_ecs_macros::all_tuples;
 | 
					use bevy_ecs_macros::all_tuples;
 | 
				
			||||||
use bevy_ptr::OwningPtr;
 | 
					use bevy_ptr::OwningPtr;
 | 
				
			||||||
@ -379,7 +379,7 @@ impl BundleInfo {
 | 
				
			|||||||
        sparse_sets: &mut SparseSets,
 | 
					        sparse_sets: &mut SparseSets,
 | 
				
			||||||
        bundle_component_status: &S,
 | 
					        bundle_component_status: &S,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        table_row: usize,
 | 
					        table_row: TableRow,
 | 
				
			||||||
        change_tick: u32,
 | 
					        change_tick: u32,
 | 
				
			||||||
        bundle: T,
 | 
					        bundle: T,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
@ -518,17 +518,17 @@ pub(crate) enum InsertBundleResult<'a> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl<'a, 'b> BundleInserter<'a, 'b> {
 | 
					impl<'a, 'b> BundleInserter<'a, 'b> {
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// `entity` must currently exist in the source archetype for this inserter. `archetype_index`
 | 
					    /// `entity` must currently exist in the source archetype for this inserter. `archetype_row`
 | 
				
			||||||
    /// must be `entity`'s location in the archetype. `T` must match this [`BundleInfo`]'s type
 | 
					    /// must be `entity`'s location in the archetype. `T` must match this [`BundleInfo`]'s type
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub unsafe fn insert<T: Bundle>(
 | 
					    pub unsafe fn insert<T: Bundle>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        archetype_index: usize,
 | 
					        archetype_row: ArchetypeRow,
 | 
				
			||||||
        bundle: T,
 | 
					        bundle: T,
 | 
				
			||||||
    ) -> EntityLocation {
 | 
					    ) -> EntityLocation {
 | 
				
			||||||
        let location = EntityLocation {
 | 
					        let location = EntityLocation {
 | 
				
			||||||
            index: archetype_index,
 | 
					            archetype_row,
 | 
				
			||||||
            archetype_id: self.archetype.id(),
 | 
					            archetype_id: self.archetype.id(),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        match &mut self.result {
 | 
					        match &mut self.result {
 | 
				
			||||||
@ -544,14 +544,14 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
 | 
				
			|||||||
                    self.sparse_sets,
 | 
					                    self.sparse_sets,
 | 
				
			||||||
                    add_bundle,
 | 
					                    add_bundle,
 | 
				
			||||||
                    entity,
 | 
					                    entity,
 | 
				
			||||||
                    self.archetype.entity_table_row(archetype_index),
 | 
					                    self.archetype.entity_table_row(archetype_row),
 | 
				
			||||||
                    self.change_tick,
 | 
					                    self.change_tick,
 | 
				
			||||||
                    bundle,
 | 
					                    bundle,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                location
 | 
					                location
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            InsertBundleResult::NewArchetypeSameTable { new_archetype } => {
 | 
					            InsertBundleResult::NewArchetypeSameTable { new_archetype } => {
 | 
				
			||||||
                let result = self.archetype.swap_remove(location.index);
 | 
					                let result = self.archetype.swap_remove(location.archetype_row);
 | 
				
			||||||
                if let Some(swapped_entity) = result.swapped_entity {
 | 
					                if let Some(swapped_entity) = result.swapped_entity {
 | 
				
			||||||
                    self.entities.set(swapped_entity.index(), location);
 | 
					                    self.entities.set(swapped_entity.index(), location);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -579,7 +579,7 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
 | 
				
			|||||||
                new_archetype,
 | 
					                new_archetype,
 | 
				
			||||||
                new_table,
 | 
					                new_table,
 | 
				
			||||||
            } => {
 | 
					            } => {
 | 
				
			||||||
                let result = self.archetype.swap_remove(location.index);
 | 
					                let result = self.archetype.swap_remove(location.archetype_row);
 | 
				
			||||||
                if let Some(swapped_entity) = result.swapped_entity {
 | 
					                if let Some(swapped_entity) = result.swapped_entity {
 | 
				
			||||||
                    self.entities.set(swapped_entity.index(), location);
 | 
					                    self.entities.set(swapped_entity.index(), location);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -607,7 +607,7 @@ impl<'a, 'b> BundleInserter<'a, 'b> {
 | 
				
			|||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    swapped_archetype
 | 
					                    swapped_archetype
 | 
				
			||||||
                        .set_entity_table_row(swapped_location.index, result.table_row);
 | 
					                        .set_entity_table_row(swapped_location.archetype_row, result.table_row);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // PERF: this could be looked up during Inserter construction and stored (but borrowing makes this nasty)
 | 
					                // PERF: this could be looked up during Inserter construction and stored (but borrowing makes this nasty)
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,10 @@ mod map_entities;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub use map_entities::*;
 | 
					pub use map_entities::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{archetype::ArchetypeId, storage::SparseSetIndex};
 | 
					use crate::{
 | 
				
			||||||
 | 
					    archetype::{ArchetypeId, ArchetypeRow},
 | 
				
			||||||
 | 
					    storage::SparseSetIndex,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use std::{convert::TryFrom, fmt, mem, sync::atomic::Ordering};
 | 
					use std::{convert::TryFrom, fmt, mem, sync::atomic::Ordering};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -727,7 +730,7 @@ impl EntityMeta {
 | 
				
			|||||||
        generation: 0,
 | 
					        generation: 0,
 | 
				
			||||||
        location: EntityLocation {
 | 
					        location: EntityLocation {
 | 
				
			||||||
            archetype_id: ArchetypeId::INVALID,
 | 
					            archetype_id: ArchetypeId::INVALID,
 | 
				
			||||||
            index: usize::MAX, // dummy value, to be filled in
 | 
					            archetype_row: ArchetypeRow::INVALID, // dummy value, to be filled in
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -740,7 +743,7 @@ pub struct EntityLocation {
 | 
				
			|||||||
    pub archetype_id: ArchetypeId,
 | 
					    pub archetype_id: ArchetypeId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The index of the entity in the archetype
 | 
					    /// The index of the entity in the archetype
 | 
				
			||||||
    pub index: usize,
 | 
					    pub archetype_row: ArchetypeRow,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ use crate::{
 | 
				
			|||||||
    component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType, Tick},
 | 
					    component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType, Tick},
 | 
				
			||||||
    entity::Entity,
 | 
					    entity::Entity,
 | 
				
			||||||
    query::{Access, DebugCheckedUnwrap, FilteredAccess},
 | 
					    query::{Access, DebugCheckedUnwrap, FilteredAccess},
 | 
				
			||||||
    storage::{ComponentSparseSet, Table},
 | 
					    storage::{ComponentSparseSet, Table, TableRow},
 | 
				
			||||||
    world::{Mut, World},
 | 
					    world::{Mut, World},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_ecs_macros::all_tuples;
 | 
					use bevy_ecs_macros::all_tuples;
 | 
				
			||||||
@ -342,7 +342,7 @@ pub unsafe trait WorldQuery {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// While calling this method on its own cannot cause UB it is marked `unsafe` as the caller must ensure
 | 
					    /// While calling this method on its own cannot cause UB it is marked `unsafe` as the caller must ensure
 | 
				
			||||||
    /// that the returned value is not used in any way that would cause two `QueryItem<Self>` for the same
 | 
					    /// that the returned value is not used in any way that would cause two `QueryItem<Self>` for the same
 | 
				
			||||||
    /// `archetype_index` or `table_row` to be alive at the same time.
 | 
					    /// `archetype_row` or `table_row` to be alive at the same time.
 | 
				
			||||||
    unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w>;
 | 
					    unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Returns true if (and only if) every table of every archetype matched by this fetch contains
 | 
					    /// Returns true if (and only if) every table of every archetype matched by this fetch contains
 | 
				
			||||||
@ -395,7 +395,7 @@ pub unsafe trait WorldQuery {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        fetch: &mut Self::Fetch<'w>,
 | 
					        fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        table_row: usize,
 | 
					        table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w>;
 | 
					    ) -> Self::Item<'w>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
@ -404,7 +404,11 @@ pub unsafe trait WorldQuery {
 | 
				
			|||||||
    /// `table_row` must be in the range of the current table and archetype.
 | 
					    /// `table_row` must be in the range of the current table and archetype.
 | 
				
			||||||
    #[allow(unused_variables)]
 | 
					    #[allow(unused_variables)]
 | 
				
			||||||
    #[inline(always)]
 | 
					    #[inline(always)]
 | 
				
			||||||
    unsafe fn filter_fetch(fetch: &mut Self::Fetch<'_>, entity: Entity, table_row: usize) -> bool {
 | 
					    unsafe fn filter_fetch(
 | 
				
			||||||
 | 
					        fetch: &mut Self::Fetch<'_>,
 | 
				
			||||||
 | 
					        entity: Entity,
 | 
				
			||||||
 | 
					        table_row: TableRow,
 | 
				
			||||||
 | 
					    ) -> bool {
 | 
				
			||||||
        true
 | 
					        true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -484,7 +488,7 @@ unsafe impl WorldQuery for Entity {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        _fetch: &mut Self::Fetch<'w>,
 | 
					        _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        _table_row: usize,
 | 
					        _table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
        entity
 | 
					        entity
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -595,13 +599,13 @@ unsafe impl<T: Component> WorldQuery for &T {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        fetch: &mut Self::Fetch<'w>,
 | 
					        fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        table_row: usize,
 | 
					        table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
        match T::Storage::STORAGE_TYPE {
 | 
					        match T::Storage::STORAGE_TYPE {
 | 
				
			||||||
            StorageType::Table => fetch
 | 
					            StorageType::Table => fetch
 | 
				
			||||||
                .table_components
 | 
					                .table_components
 | 
				
			||||||
                .debug_checked_unwrap()
 | 
					                .debug_checked_unwrap()
 | 
				
			||||||
                .get(table_row)
 | 
					                .get(table_row.index())
 | 
				
			||||||
                .deref(),
 | 
					                .deref(),
 | 
				
			||||||
            StorageType::SparseSet => fetch
 | 
					            StorageType::SparseSet => fetch
 | 
				
			||||||
                .sparse_set
 | 
					                .sparse_set
 | 
				
			||||||
@ -743,17 +747,17 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        fetch: &mut Self::Fetch<'w>,
 | 
					        fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        table_row: usize,
 | 
					        table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
        match T::Storage::STORAGE_TYPE {
 | 
					        match T::Storage::STORAGE_TYPE {
 | 
				
			||||||
            StorageType::Table => {
 | 
					            StorageType::Table => {
 | 
				
			||||||
                let (table_components, added_ticks, changed_ticks) =
 | 
					                let (table_components, added_ticks, changed_ticks) =
 | 
				
			||||||
                    fetch.table_data.debug_checked_unwrap();
 | 
					                    fetch.table_data.debug_checked_unwrap();
 | 
				
			||||||
                Mut {
 | 
					                Mut {
 | 
				
			||||||
                    value: table_components.get(table_row).deref_mut(),
 | 
					                    value: table_components.get(table_row.index()).deref_mut(),
 | 
				
			||||||
                    ticks: Ticks {
 | 
					                    ticks: Ticks {
 | 
				
			||||||
                        added: added_ticks.get(table_row).deref_mut(),
 | 
					                        added: added_ticks.get(table_row.index()).deref_mut(),
 | 
				
			||||||
                        changed: changed_ticks.get(table_row).deref_mut(),
 | 
					                        changed: changed_ticks.get(table_row.index()).deref_mut(),
 | 
				
			||||||
                        change_tick: fetch.change_tick,
 | 
					                        change_tick: fetch.change_tick,
 | 
				
			||||||
                        last_change_tick: fetch.last_change_tick,
 | 
					                        last_change_tick: fetch.last_change_tick,
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
@ -872,7 +876,7 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        fetch: &mut Self::Fetch<'w>,
 | 
					        fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        table_row: usize,
 | 
					        table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
        fetch
 | 
					        fetch
 | 
				
			||||||
            .matches
 | 
					            .matches
 | 
				
			||||||
@ -1082,7 +1086,7 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        fetch: &mut Self::Fetch<'w>,
 | 
					        fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        entity: Entity,
 | 
					        entity: Entity,
 | 
				
			||||||
        table_row: usize,
 | 
					        table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
        match T::Storage::STORAGE_TYPE {
 | 
					        match T::Storage::STORAGE_TYPE {
 | 
				
			||||||
            StorageType::Table => ChangeTrackers {
 | 
					            StorageType::Table => ChangeTrackers {
 | 
				
			||||||
@ -1091,12 +1095,12 @@ unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
 | 
				
			|||||||
                        added: fetch
 | 
					                        added: fetch
 | 
				
			||||||
                            .table_added
 | 
					                            .table_added
 | 
				
			||||||
                            .debug_checked_unwrap()
 | 
					                            .debug_checked_unwrap()
 | 
				
			||||||
                            .get(table_row)
 | 
					                            .get(table_row.index())
 | 
				
			||||||
                            .read(),
 | 
					                            .read(),
 | 
				
			||||||
                        changed: fetch
 | 
					                        changed: fetch
 | 
				
			||||||
                            .table_changed
 | 
					                            .table_changed
 | 
				
			||||||
                            .debug_checked_unwrap()
 | 
					                            .debug_checked_unwrap()
 | 
				
			||||||
                            .get(table_row)
 | 
					                            .get(table_row.index())
 | 
				
			||||||
                            .read(),
 | 
					                            .read(),
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@ -1210,7 +1214,7 @@ macro_rules! impl_tuple_fetch {
 | 
				
			|||||||
            unsafe fn fetch<'w>(
 | 
					            unsafe fn fetch<'w>(
 | 
				
			||||||
                _fetch: &mut Self::Fetch<'w>,
 | 
					                _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                _entity: Entity,
 | 
					                _entity: Entity,
 | 
				
			||||||
                _table_row: usize
 | 
					                _table_row: TableRow
 | 
				
			||||||
            ) -> Self::Item<'w> {
 | 
					            ) -> Self::Item<'w> {
 | 
				
			||||||
                let ($($name,)*) = _fetch;
 | 
					                let ($($name,)*) = _fetch;
 | 
				
			||||||
                ($($name::fetch($name, _entity, _table_row),)*)
 | 
					                ($($name::fetch($name, _entity, _table_row),)*)
 | 
				
			||||||
@ -1220,7 +1224,7 @@ macro_rules! impl_tuple_fetch {
 | 
				
			|||||||
            unsafe fn filter_fetch<'w>(
 | 
					            unsafe fn filter_fetch<'w>(
 | 
				
			||||||
                _fetch: &mut Self::Fetch<'w>,
 | 
					                _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                _entity: Entity,
 | 
					                _entity: Entity,
 | 
				
			||||||
                _table_row: usize
 | 
					                _table_row: TableRow
 | 
				
			||||||
            ) -> bool {
 | 
					            ) -> bool {
 | 
				
			||||||
                let ($($name,)*) = _fetch;
 | 
					                let ($($name,)*) = _fetch;
 | 
				
			||||||
                true $(&& $name::filter_fetch($name, _entity, _table_row))*
 | 
					                true $(&& $name::filter_fetch($name, _entity, _table_row))*
 | 
				
			||||||
@ -1329,7 +1333,7 @@ macro_rules! impl_anytuple_fetch {
 | 
				
			|||||||
            unsafe fn fetch<'w>(
 | 
					            unsafe fn fetch<'w>(
 | 
				
			||||||
                _fetch: &mut Self::Fetch<'w>,
 | 
					                _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                _entity: Entity,
 | 
					                _entity: Entity,
 | 
				
			||||||
                _table_row: usize
 | 
					                _table_row: TableRow
 | 
				
			||||||
            ) -> Self::Item<'w> {
 | 
					            ) -> Self::Item<'w> {
 | 
				
			||||||
                let ($($name,)*) = _fetch;
 | 
					                let ($($name,)*) = _fetch;
 | 
				
			||||||
                ($(
 | 
					                ($(
 | 
				
			||||||
@ -1443,7 +1447,7 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        _fetch: &mut Self::Fetch<'w>,
 | 
					        _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        _entity: Entity,
 | 
					        _entity: Entity,
 | 
				
			||||||
        _table_row: usize,
 | 
					        _table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ use crate::{
 | 
				
			|||||||
    component::{Component, ComponentId, ComponentStorage, StorageType, Tick},
 | 
					    component::{Component, ComponentId, ComponentStorage, StorageType, Tick},
 | 
				
			||||||
    entity::Entity,
 | 
					    entity::Entity,
 | 
				
			||||||
    query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
 | 
					    query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
 | 
				
			||||||
    storage::{Column, ComponentSparseSet, Table},
 | 
					    storage::{Column, ComponentSparseSet, Table, TableRow},
 | 
				
			||||||
    world::World,
 | 
					    world::World,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_ecs_macros::all_tuples;
 | 
					use bevy_ecs_macros::all_tuples;
 | 
				
			||||||
@ -85,7 +85,7 @@ unsafe impl<T: Component> WorldQuery for With<T> {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        _fetch: &mut Self::Fetch<'w>,
 | 
					        _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        _entity: Entity,
 | 
					        _entity: Entity,
 | 
				
			||||||
        _table_row: usize,
 | 
					        _table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -187,7 +187,7 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
 | 
				
			|||||||
    unsafe fn fetch<'w>(
 | 
					    unsafe fn fetch<'w>(
 | 
				
			||||||
        _fetch: &mut Self::Fetch<'w>,
 | 
					        _fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
        _entity: Entity,
 | 
					        _entity: Entity,
 | 
				
			||||||
        _table_row: usize,
 | 
					        _table_row: TableRow,
 | 
				
			||||||
    ) -> Self::Item<'w> {
 | 
					    ) -> Self::Item<'w> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -330,7 +330,7 @@ macro_rules! impl_query_filter_tuple {
 | 
				
			|||||||
            unsafe fn fetch<'w>(
 | 
					            unsafe fn fetch<'w>(
 | 
				
			||||||
                fetch: &mut Self::Fetch<'w>,
 | 
					                fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                _entity: Entity,
 | 
					                _entity: Entity,
 | 
				
			||||||
                _table_row: usize
 | 
					                _table_row: TableRow
 | 
				
			||||||
            ) -> Self::Item<'w> {
 | 
					            ) -> Self::Item<'w> {
 | 
				
			||||||
                let ($($filter,)*) = fetch;
 | 
					                let ($($filter,)*) = fetch;
 | 
				
			||||||
                false $(|| ($filter.matches && $filter::filter_fetch(&mut $filter.fetch, _entity, _table_row)))*
 | 
					                false $(|| ($filter.matches && $filter::filter_fetch(&mut $filter.fetch, _entity, _table_row)))*
 | 
				
			||||||
@ -340,7 +340,7 @@ macro_rules! impl_query_filter_tuple {
 | 
				
			|||||||
            unsafe fn filter_fetch<'w>(
 | 
					            unsafe fn filter_fetch<'w>(
 | 
				
			||||||
                fetch: &mut Self::Fetch<'w>,
 | 
					                fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                entity: Entity,
 | 
					                entity: Entity,
 | 
				
			||||||
                table_row: usize
 | 
					                table_row: TableRow
 | 
				
			||||||
            ) -> bool {
 | 
					            ) -> bool {
 | 
				
			||||||
                Self::fetch(fetch, entity, table_row)
 | 
					                Self::fetch(fetch, entity, table_row)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -500,14 +500,14 @@ macro_rules! impl_tick_filter {
 | 
				
			|||||||
            unsafe fn fetch<'w>(
 | 
					            unsafe fn fetch<'w>(
 | 
				
			||||||
                fetch: &mut Self::Fetch<'w>,
 | 
					                fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                entity: Entity,
 | 
					                entity: Entity,
 | 
				
			||||||
                table_row: usize
 | 
					                table_row: TableRow
 | 
				
			||||||
            ) -> Self::Item<'w> {
 | 
					            ) -> Self::Item<'w> {
 | 
				
			||||||
                match T::Storage::STORAGE_TYPE {
 | 
					                match T::Storage::STORAGE_TYPE {
 | 
				
			||||||
                    StorageType::Table => {
 | 
					                    StorageType::Table => {
 | 
				
			||||||
                        fetch
 | 
					                        fetch
 | 
				
			||||||
                            .table_ticks
 | 
					                            .table_ticks
 | 
				
			||||||
                            .debug_checked_unwrap()
 | 
					                            .debug_checked_unwrap()
 | 
				
			||||||
                            .get(table_row)
 | 
					                            .get(table_row.index())
 | 
				
			||||||
                            .deref()
 | 
					                            .deref()
 | 
				
			||||||
                            .is_older_than(fetch.last_change_tick, fetch.change_tick)
 | 
					                            .is_older_than(fetch.last_change_tick, fetch.change_tick)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -527,7 +527,7 @@ macro_rules! impl_tick_filter {
 | 
				
			|||||||
            unsafe fn filter_fetch<'w>(
 | 
					            unsafe fn filter_fetch<'w>(
 | 
				
			||||||
                fetch: &mut Self::Fetch<'w>,
 | 
					                fetch: &mut Self::Fetch<'w>,
 | 
				
			||||||
                entity: Entity,
 | 
					                entity: Entity,
 | 
				
			||||||
                table_row: usize
 | 
					                table_row: TableRow
 | 
				
			||||||
            ) -> bool {
 | 
					            ) -> bool {
 | 
				
			||||||
                Self::fetch(fetch, entity, table_row)
 | 
					                Self::fetch(fetch, entity, table_row)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ use crate::{
 | 
				
			|||||||
    entity::{Entities, Entity},
 | 
					    entity::{Entities, Entity},
 | 
				
			||||||
    prelude::World,
 | 
					    prelude::World,
 | 
				
			||||||
    query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
 | 
					    query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
 | 
				
			||||||
    storage::{TableId, Tables},
 | 
					    storage::{TableId, TableRow, Tables},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use std::{borrow::Borrow, iter::FusedIterator, marker::PhantomData, mem::MaybeUninit};
 | 
					use std::{borrow::Borrow, iter::FusedIterator, marker::PhantomData, mem::MaybeUninit};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -170,11 +170,11 @@ where
 | 
				
			|||||||
                table,
 | 
					                table,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let table_row = archetype.entity_table_row(location.index);
 | 
					            let table_row = archetype.entity_table_row(location.archetype_row);
 | 
				
			||||||
            // SAFETY: set_archetype was called prior.
 | 
					            // SAFETY: set_archetype was called prior.
 | 
				
			||||||
            // `location.index` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
 | 
					            // `location.archetype_row` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
 | 
				
			||||||
            if F::filter_fetch(&mut self.filter, entity, table_row) {
 | 
					            if F::filter_fetch(&mut self.filter, entity, table_row) {
 | 
				
			||||||
                // SAFETY: set_archetype was called prior, `location.index` is an archetype index in range of the current archetype
 | 
					                // SAFETY: set_archetype was called prior, `location.archetype_row` is an archetype index in range of the current archetype
 | 
				
			||||||
                return Some(Q::fetch(&mut self.fetch, entity, table_row));
 | 
					                return Some(Q::fetch(&mut self.fetch, entity, table_row));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -464,7 +464,7 @@ struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
 | 
				
			|||||||
    // length of the table table or length of the archetype, depending on whether both `Q`'s and `F`'s fetches are dense
 | 
					    // length of the table table or length of the archetype, depending on whether both `Q`'s and `F`'s fetches are dense
 | 
				
			||||||
    current_len: usize,
 | 
					    current_len: usize,
 | 
				
			||||||
    // either table row or archetype index, depending on whether both `Q`'s and `F`'s fetches are dense
 | 
					    // either table row or archetype index, depending on whether both `Q`'s and `F`'s fetches are dense
 | 
				
			||||||
    current_index: usize,
 | 
					    current_row: usize,
 | 
				
			||||||
    phantom: PhantomData<Q>,
 | 
					    phantom: PhantomData<Q>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -474,7 +474,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// While calling this method on its own cannot cause UB it is marked `unsafe` as the caller must ensure
 | 
					    /// While calling this method on its own cannot cause UB it is marked `unsafe` as the caller must ensure
 | 
				
			||||||
    /// that the returned value is not used in any way that would cause two `QueryItem<Q>` for the same
 | 
					    /// that the returned value is not used in any way that would cause two `QueryItem<Q>` for the same
 | 
				
			||||||
    /// `archetype_index` or `table_row` to be alive at the same time.
 | 
					    /// `archetype_row` or `table_row` to be alive at the same time.
 | 
				
			||||||
    unsafe fn clone_cursor(&self) -> Self {
 | 
					    unsafe fn clone_cursor(&self) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            table_id_iter: self.table_id_iter.clone(),
 | 
					            table_id_iter: self.table_id_iter.clone(),
 | 
				
			||||||
@ -485,7 +485,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
            fetch: Q::clone_fetch(&self.fetch),
 | 
					            fetch: Q::clone_fetch(&self.fetch),
 | 
				
			||||||
            filter: F::clone_fetch(&self.filter),
 | 
					            filter: F::clone_fetch(&self.filter),
 | 
				
			||||||
            current_len: self.current_len,
 | 
					            current_len: self.current_len,
 | 
				
			||||||
            current_index: self.current_index,
 | 
					            current_row: self.current_row,
 | 
				
			||||||
            phantom: PhantomData,
 | 
					            phantom: PhantomData,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -533,7 +533,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
            table_id_iter: query_state.matched_table_ids.iter(),
 | 
					            table_id_iter: query_state.matched_table_ids.iter(),
 | 
				
			||||||
            archetype_id_iter: query_state.matched_archetype_ids.iter(),
 | 
					            archetype_id_iter: query_state.matched_archetype_ids.iter(),
 | 
				
			||||||
            current_len: 0,
 | 
					            current_len: 0,
 | 
				
			||||||
            current_index: 0,
 | 
					            current_row: 0,
 | 
				
			||||||
            phantom: PhantomData,
 | 
					            phantom: PhantomData,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -541,11 +541,11 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
    /// retrieve item returned from most recent `next` call again.
 | 
					    /// retrieve item returned from most recent `next` call again.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    unsafe fn peek_last(&mut self) -> Option<Q::Item<'w>> {
 | 
					    unsafe fn peek_last(&mut self) -> Option<Q::Item<'w>> {
 | 
				
			||||||
        if self.current_index > 0 {
 | 
					        if self.current_row > 0 {
 | 
				
			||||||
            let index = self.current_index - 1;
 | 
					            let index = self.current_row - 1;
 | 
				
			||||||
            if Self::IS_DENSE {
 | 
					            if Self::IS_DENSE {
 | 
				
			||||||
                let entity = self.table_entities.get_unchecked(index);
 | 
					                let entity = self.table_entities.get_unchecked(index);
 | 
				
			||||||
                Some(Q::fetch(&mut self.fetch, *entity, index))
 | 
					                Some(Q::fetch(&mut self.fetch, *entity, TableRow::new(index)))
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                let archetype_entity = self.archetype_entities.get_unchecked(index);
 | 
					                let archetype_entity = self.archetype_entities.get_unchecked(index);
 | 
				
			||||||
                Some(Q::fetch(
 | 
					                Some(Q::fetch(
 | 
				
			||||||
@ -571,7 +571,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
            let ids = self.archetype_id_iter.clone();
 | 
					            let ids = self.archetype_id_iter.clone();
 | 
				
			||||||
            ids.map(|id| archetypes[*id].len()).sum()
 | 
					            ids.map(|id| archetypes[*id].len()).sum()
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        remaining_matched + self.current_len - self.current_index
 | 
					        remaining_matched + self.current_len - self.current_row
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
 | 
					    // NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
 | 
				
			||||||
@ -590,7 +590,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
        if Self::IS_DENSE {
 | 
					        if Self::IS_DENSE {
 | 
				
			||||||
            loop {
 | 
					            loop {
 | 
				
			||||||
                // we are on the beginning of the query, or finished processing a table, so skip to the next
 | 
					                // we are on the beginning of the query, or finished processing a table, so skip to the next
 | 
				
			||||||
                if self.current_index == self.current_len {
 | 
					                if self.current_row == self.current_len {
 | 
				
			||||||
                    let table_id = self.table_id_iter.next()?;
 | 
					                    let table_id = self.table_id_iter.next()?;
 | 
				
			||||||
                    let table = tables.get(*table_id).debug_checked_unwrap();
 | 
					                    let table = tables.get(*table_id).debug_checked_unwrap();
 | 
				
			||||||
                    // SAFETY: `table` is from the world that `fetch/filter` were created for,
 | 
					                    // SAFETY: `table` is from the world that `fetch/filter` were created for,
 | 
				
			||||||
@ -599,28 +599,29 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
                    F::set_table(&mut self.filter, &query_state.filter_state, table);
 | 
					                    F::set_table(&mut self.filter, &query_state.filter_state, table);
 | 
				
			||||||
                    self.table_entities = table.entities();
 | 
					                    self.table_entities = table.entities();
 | 
				
			||||||
                    self.current_len = table.entity_count();
 | 
					                    self.current_len = table.entity_count();
 | 
				
			||||||
                    self.current_index = 0;
 | 
					                    self.current_row = 0;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // SAFETY: set_table was called prior.
 | 
					                // SAFETY: set_table was called prior.
 | 
				
			||||||
                // `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
 | 
					                // `current_row` is a table row in range of the current table, because if it was not, then the if above would have been executed.
 | 
				
			||||||
                let entity = self.table_entities.get_unchecked(self.current_index);
 | 
					                let entity = self.table_entities.get_unchecked(self.current_row);
 | 
				
			||||||
                if !F::filter_fetch(&mut self.filter, *entity, self.current_index) {
 | 
					                let row = TableRow::new(self.current_row);
 | 
				
			||||||
                    self.current_index += 1;
 | 
					                if !F::filter_fetch(&mut self.filter, *entity, row) {
 | 
				
			||||||
 | 
					                    self.current_row += 1;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // SAFETY: set_table was called prior.
 | 
					                // SAFETY: set_table was called prior.
 | 
				
			||||||
                // `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
 | 
					                // `current_row` is a table row in range of the current table, because if it was not, then the if above would have been executed.
 | 
				
			||||||
                let item = Q::fetch(&mut self.fetch, *entity, self.current_index);
 | 
					                let item = Q::fetch(&mut self.fetch, *entity, row);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.current_index += 1;
 | 
					                self.current_row += 1;
 | 
				
			||||||
                return Some(item);
 | 
					                return Some(item);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            loop {
 | 
					            loop {
 | 
				
			||||||
                if self.current_index == self.current_len {
 | 
					                if self.current_row == self.current_len {
 | 
				
			||||||
                    let archetype_id = self.archetype_id_iter.next()?;
 | 
					                    let archetype_id = self.archetype_id_iter.next()?;
 | 
				
			||||||
                    let archetype = archetypes.get(*archetype_id).debug_checked_unwrap();
 | 
					                    let archetype = archetypes.get(*archetype_id).debug_checked_unwrap();
 | 
				
			||||||
                    // SAFETY: `archetype` and `tables` are from the world that `fetch/filter` were created for,
 | 
					                    // SAFETY: `archetype` and `tables` are from the world that `fetch/filter` were created for,
 | 
				
			||||||
@ -635,30 +636,30 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
 | 
				
			|||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    self.archetype_entities = archetype.entities();
 | 
					                    self.archetype_entities = archetype.entities();
 | 
				
			||||||
                    self.current_len = archetype.len();
 | 
					                    self.current_len = archetype.len();
 | 
				
			||||||
                    self.current_index = 0;
 | 
					                    self.current_row = 0;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // SAFETY: set_archetype was called prior.
 | 
					                // SAFETY: set_archetype was called prior.
 | 
				
			||||||
                // `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
 | 
					                // `current_row` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
 | 
				
			||||||
                let archetype_entity = self.archetype_entities.get_unchecked(self.current_index);
 | 
					                let archetype_entity = self.archetype_entities.get_unchecked(self.current_row);
 | 
				
			||||||
                if !F::filter_fetch(
 | 
					                if !F::filter_fetch(
 | 
				
			||||||
                    &mut self.filter,
 | 
					                    &mut self.filter,
 | 
				
			||||||
                    archetype_entity.entity(),
 | 
					                    archetype_entity.entity(),
 | 
				
			||||||
                    archetype_entity.table_row(),
 | 
					                    archetype_entity.table_row(),
 | 
				
			||||||
                ) {
 | 
					                ) {
 | 
				
			||||||
                    self.current_index += 1;
 | 
					                    self.current_row += 1;
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // SAFETY: set_archetype was called prior, `current_index` is an archetype index in range of the current archetype
 | 
					                // SAFETY: set_archetype was called prior, `current_row` is an archetype index in range of the current archetype
 | 
				
			||||||
                // `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
 | 
					                // `current_row` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
 | 
				
			||||||
                let item = Q::fetch(
 | 
					                let item = Q::fetch(
 | 
				
			||||||
                    &mut self.fetch,
 | 
					                    &mut self.fetch,
 | 
				
			||||||
                    archetype_entity.entity(),
 | 
					                    archetype_entity.entity(),
 | 
				
			||||||
                    archetype_entity.table_row(),
 | 
					                    archetype_entity.table_row(),
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                self.current_index += 1;
 | 
					                self.current_row += 1;
 | 
				
			||||||
                return Some(item);
 | 
					                return Some(item);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ use crate::{
 | 
				
			|||||||
    query::{
 | 
					    query::{
 | 
				
			||||||
        Access, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery,
 | 
					        Access, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    storage::TableId,
 | 
					    storage::{TableId, TableRow},
 | 
				
			||||||
    world::{World, WorldId},
 | 
					    world::{World, WorldId},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_tasks::ComputeTaskPool;
 | 
					use bevy_tasks::ComputeTaskPool;
 | 
				
			||||||
@ -408,7 +408,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
 | 
				
			|||||||
        let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
 | 
					        let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
 | 
				
			||||||
        let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
 | 
					        let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let table_row = archetype.entity_table_row(location.index);
 | 
					        let table_row = archetype.entity_table_row(location.archetype_row);
 | 
				
			||||||
        let table = world
 | 
					        let table = world
 | 
				
			||||||
            .storages()
 | 
					            .storages()
 | 
				
			||||||
            .tables
 | 
					            .tables
 | 
				
			||||||
@ -928,6 +928,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
 | 
				
			|||||||
                let entities = table.entities();
 | 
					                let entities = table.entities();
 | 
				
			||||||
                for row in 0..table.entity_count() {
 | 
					                for row in 0..table.entity_count() {
 | 
				
			||||||
                    let entity = entities.get_unchecked(row);
 | 
					                    let entity = entities.get_unchecked(row);
 | 
				
			||||||
 | 
					                    let row = TableRow::new(row);
 | 
				
			||||||
                    if !F::filter_fetch(&mut filter, *entity, row) {
 | 
					                    if !F::filter_fetch(&mut filter, *entity, row) {
 | 
				
			||||||
                        continue;
 | 
					                        continue;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -1022,6 +1023,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
 | 
				
			|||||||
                            F::set_table(&mut filter, &self.filter_state, table);
 | 
					                            F::set_table(&mut filter, &self.filter_state, table);
 | 
				
			||||||
                            for row in offset..offset + len {
 | 
					                            for row in offset..offset + len {
 | 
				
			||||||
                                let entity = entities.get_unchecked(row);
 | 
					                                let entity = entities.get_unchecked(row);
 | 
				
			||||||
 | 
					                                let row = TableRow::new(row);
 | 
				
			||||||
                                if !F::filter_fetch(&mut filter, *entity, row) {
 | 
					                                if !F::filter_fetch(&mut filter, *entity, row) {
 | 
				
			||||||
                                    continue;
 | 
					                                    continue;
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
@ -1074,8 +1076,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
 | 
				
			|||||||
                            F::set_archetype(&mut filter, &self.filter_state, archetype, table);
 | 
					                            F::set_archetype(&mut filter, &self.filter_state, archetype, table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            let entities = archetype.entities();
 | 
					                            let entities = archetype.entities();
 | 
				
			||||||
                            for archetype_index in offset..offset + len {
 | 
					                            for archetype_row in offset..offset + len {
 | 
				
			||||||
                                let archetype_entity = entities.get_unchecked(archetype_index);
 | 
					                                let archetype_entity = entities.get_unchecked(archetype_row);
 | 
				
			||||||
                                if !F::filter_fetch(
 | 
					                                if !F::filter_fetch(
 | 
				
			||||||
                                    &mut filter,
 | 
					                                    &mut filter,
 | 
				
			||||||
                                    archetype_entity.entity(),
 | 
					                                    archetype_entity.entity(),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
use crate::archetype::ArchetypeComponentId;
 | 
					use crate::archetype::ArchetypeComponentId;
 | 
				
			||||||
use crate::component::{ComponentId, ComponentTicks, Components, TickCells};
 | 
					use crate::component::{ComponentId, ComponentTicks, Components, TickCells};
 | 
				
			||||||
use crate::storage::{Column, SparseSet};
 | 
					use crate::storage::{Column, SparseSet, TableRow};
 | 
				
			||||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
 | 
					use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The type-erased backing storage and metadata for a single resource within a [`World`].
 | 
					/// The type-erased backing storage and metadata for a single resource within a [`World`].
 | 
				
			||||||
@ -12,6 +12,9 @@ pub struct ResourceData {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ResourceData {
 | 
					impl ResourceData {
 | 
				
			||||||
 | 
					    /// The only row in the underlying column.
 | 
				
			||||||
 | 
					    const ROW: TableRow = TableRow::new(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Returns true if the resource is populated.
 | 
					    /// Returns true if the resource is populated.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn is_present(&self) -> bool {
 | 
					    pub fn is_present(&self) -> bool {
 | 
				
			||||||
@ -27,18 +30,18 @@ impl ResourceData {
 | 
				
			|||||||
    /// Gets a read-only pointer to the underlying resource, if available.
 | 
					    /// Gets a read-only pointer to the underlying resource, if available.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_data(&self) -> Option<Ptr<'_>> {
 | 
					    pub fn get_data(&self) -> Option<Ptr<'_>> {
 | 
				
			||||||
        self.column.get_data(0)
 | 
					        self.column.get_data(Self::ROW)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Gets a read-only reference to the change ticks of the underlying resource, if available.
 | 
					    /// Gets a read-only reference to the change ticks of the underlying resource, if available.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_ticks(&self) -> Option<ComponentTicks> {
 | 
					    pub fn get_ticks(&self) -> Option<ComponentTicks> {
 | 
				
			||||||
        self.column.get_ticks(0)
 | 
					        self.column.get_ticks(Self::ROW)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) fn get_with_ticks(&self) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | 
					    pub(crate) fn get_with_ticks(&self) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | 
				
			||||||
        self.column.get(0)
 | 
					        self.column.get(Self::ROW)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Inserts a value into the resource. If a value is already present
 | 
					    /// Inserts a value into the resource. If a value is already present
 | 
				
			||||||
@ -54,7 +57,7 @@ impl ResourceData {
 | 
				
			|||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) unsafe fn insert(&mut self, value: OwningPtr<'_>, change_tick: u32) {
 | 
					    pub(crate) unsafe fn insert(&mut self, value: OwningPtr<'_>, change_tick: u32) {
 | 
				
			||||||
        if self.is_present() {
 | 
					        if self.is_present() {
 | 
				
			||||||
            self.column.replace(0, value, change_tick);
 | 
					            self.column.replace(Self::ROW, value, change_tick);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            self.column.push(value, ComponentTicks::new(change_tick));
 | 
					            self.column.push(value, ComponentTicks::new(change_tick));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -77,9 +80,12 @@ impl ResourceData {
 | 
				
			|||||||
        change_ticks: ComponentTicks,
 | 
					        change_ticks: ComponentTicks,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        if self.is_present() {
 | 
					        if self.is_present() {
 | 
				
			||||||
            self.column.replace_untracked(0, value);
 | 
					            self.column.replace_untracked(Self::ROW, value);
 | 
				
			||||||
            *self.column.get_added_ticks_unchecked(0).deref_mut() = change_ticks.added;
 | 
					            *self.column.get_added_ticks_unchecked(Self::ROW).deref_mut() = change_ticks.added;
 | 
				
			||||||
            *self.column.get_changed_ticks_unchecked(0).deref_mut() = change_ticks.changed;
 | 
					            *self
 | 
				
			||||||
 | 
					                .column
 | 
				
			||||||
 | 
					                .get_changed_ticks_unchecked(Self::ROW)
 | 
				
			||||||
 | 
					                .deref_mut() = change_ticks.changed;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            self.column.push(value, change_ticks);
 | 
					            self.column.push(value, change_ticks);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -97,7 +103,7 @@ impl ResourceData {
 | 
				
			|||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    #[must_use = "The returned pointer to the removed component should be used or dropped"]
 | 
					    #[must_use = "The returned pointer to the removed component should be used or dropped"]
 | 
				
			||||||
    pub(crate) unsafe fn remove(&mut self) -> Option<(OwningPtr<'_>, ComponentTicks)> {
 | 
					    pub(crate) unsafe fn remove(&mut self) -> Option<(OwningPtr<'_>, ComponentTicks)> {
 | 
				
			||||||
        self.column.swap_remove_and_forget(0)
 | 
					        self.column.swap_remove_and_forget(Self::ROW)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Removes a value from the resource, if present, and drops it.
 | 
					    /// Removes a value from the resource, if present, and drops it.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    component::{ComponentId, ComponentInfo, ComponentTicks, Tick, TickCells},
 | 
					    component::{ComponentId, ComponentInfo, ComponentTicks, Tick, TickCells},
 | 
				
			||||||
    entity::Entity,
 | 
					    entity::Entity,
 | 
				
			||||||
    storage::Column,
 | 
					    storage::{Column, TableRow},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_ptr::{OwningPtr, Ptr};
 | 
					use bevy_ptr::{OwningPtr, Ptr};
 | 
				
			||||||
use std::{cell::UnsafeCell, hash::Hash, marker::PhantomData};
 | 
					use std::{cell::UnsafeCell, hash::Hash, marker::PhantomData};
 | 
				
			||||||
@ -147,7 +147,8 @@ impl ComponentSparseSet {
 | 
				
			|||||||
        if let Some(&dense_index) = self.sparse.get(entity.index()) {
 | 
					        if let Some(&dense_index) = self.sparse.get(entity.index()) {
 | 
				
			||||||
            #[cfg(debug_assertions)]
 | 
					            #[cfg(debug_assertions)]
 | 
				
			||||||
            assert_eq!(entity, self.entities[dense_index as usize]);
 | 
					            assert_eq!(entity, self.entities[dense_index as usize]);
 | 
				
			||||||
            self.dense.replace(dense_index as usize, value, change_tick);
 | 
					            self.dense
 | 
				
			||||||
 | 
					                .replace(TableRow::new(dense_index as usize), value, change_tick);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            let dense_index = self.dense.len();
 | 
					            let dense_index = self.dense.len();
 | 
				
			||||||
            self.dense.push(value, ComponentTicks::new(change_tick));
 | 
					            self.dense.push(value, ComponentTicks::new(change_tick));
 | 
				
			||||||
@ -180,19 +181,19 @@ impl ComponentSparseSet {
 | 
				
			|||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
 | 
					    pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
 | 
				
			||||||
        self.sparse.get(entity.index()).map(|dense_index| {
 | 
					        self.sparse.get(entity.index()).map(|dense_index| {
 | 
				
			||||||
            let dense_index = *dense_index as usize;
 | 
					            let dense_index = (*dense_index) as usize;
 | 
				
			||||||
            #[cfg(debug_assertions)]
 | 
					            #[cfg(debug_assertions)]
 | 
				
			||||||
            assert_eq!(entity, self.entities[dense_index]);
 | 
					            assert_eq!(entity, self.entities[dense_index]);
 | 
				
			||||||
            // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
					            // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
				
			||||||
            unsafe { self.dense.get_data_unchecked(dense_index) }
 | 
					            unsafe { self.dense.get_data_unchecked(TableRow::new(dense_index)) }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_with_ticks(&self, entity: Entity) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | 
					    pub fn get_with_ticks(&self, entity: Entity) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | 
				
			||||||
        let dense_index = *self.sparse.get(entity.index())? as usize;
 | 
					        let dense_index = TableRow::new(*self.sparse.get(entity.index())? as usize);
 | 
				
			||||||
        #[cfg(debug_assertions)]
 | 
					        #[cfg(debug_assertions)]
 | 
				
			||||||
        assert_eq!(entity, self.entities[dense_index]);
 | 
					        assert_eq!(entity, self.entities[dense_index.index()]);
 | 
				
			||||||
        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
					        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            Some((
 | 
					            Some((
 | 
				
			||||||
@ -211,7 +212,12 @@ impl ComponentSparseSet {
 | 
				
			|||||||
        #[cfg(debug_assertions)]
 | 
					        #[cfg(debug_assertions)]
 | 
				
			||||||
        assert_eq!(entity, self.entities[dense_index]);
 | 
					        assert_eq!(entity, self.entities[dense_index]);
 | 
				
			||||||
        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
					        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
				
			||||||
        unsafe { Some(self.dense.get_added_ticks_unchecked(dense_index)) }
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            Some(
 | 
				
			||||||
 | 
					                self.dense
 | 
				
			||||||
 | 
					                    .get_added_ticks_unchecked(TableRow::new(dense_index)),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
@ -220,7 +226,12 @@ impl ComponentSparseSet {
 | 
				
			|||||||
        #[cfg(debug_assertions)]
 | 
					        #[cfg(debug_assertions)]
 | 
				
			||||||
        assert_eq!(entity, self.entities[dense_index]);
 | 
					        assert_eq!(entity, self.entities[dense_index]);
 | 
				
			||||||
        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
					        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
				
			||||||
        unsafe { Some(self.dense.get_changed_ticks_unchecked(dense_index)) }
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            Some(
 | 
				
			||||||
 | 
					                self.dense
 | 
				
			||||||
 | 
					                    .get_changed_ticks_unchecked(TableRow::new(dense_index)),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
@ -229,7 +240,7 @@ impl ComponentSparseSet {
 | 
				
			|||||||
        #[cfg(debug_assertions)]
 | 
					        #[cfg(debug_assertions)]
 | 
				
			||||||
        assert_eq!(entity, self.entities[dense_index]);
 | 
					        assert_eq!(entity, self.entities[dense_index]);
 | 
				
			||||||
        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
					        // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
				
			||||||
        unsafe { Some(self.dense.get_ticks_unchecked(dense_index)) }
 | 
					        unsafe { Some(self.dense.get_ticks_unchecked(TableRow::new(dense_index))) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
 | 
					    /// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
 | 
				
			||||||
@ -243,7 +254,10 @@ impl ComponentSparseSet {
 | 
				
			|||||||
            self.entities.swap_remove(dense_index);
 | 
					            self.entities.swap_remove(dense_index);
 | 
				
			||||||
            let is_last = dense_index == self.dense.len() - 1;
 | 
					            let is_last = dense_index == self.dense.len() - 1;
 | 
				
			||||||
            // SAFETY: dense_index was just removed from `sparse`, which ensures that it is valid
 | 
					            // SAFETY: dense_index was just removed from `sparse`, which ensures that it is valid
 | 
				
			||||||
            let (value, _) = unsafe { self.dense.swap_remove_and_forget_unchecked(dense_index) };
 | 
					            let (value, _) = unsafe {
 | 
				
			||||||
 | 
					                self.dense
 | 
				
			||||||
 | 
					                    .swap_remove_and_forget_unchecked(TableRow::new(dense_index))
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
            if !is_last {
 | 
					            if !is_last {
 | 
				
			||||||
                let swapped_entity = self.entities[dense_index];
 | 
					                let swapped_entity = self.entities[dense_index];
 | 
				
			||||||
                #[cfg(not(debug_assertions))]
 | 
					                #[cfg(not(debug_assertions))]
 | 
				
			||||||
@ -264,7 +278,7 @@ impl ComponentSparseSet {
 | 
				
			|||||||
            self.entities.swap_remove(dense_index);
 | 
					            self.entities.swap_remove(dense_index);
 | 
				
			||||||
            let is_last = dense_index == self.dense.len() - 1;
 | 
					            let is_last = dense_index == self.dense.len() - 1;
 | 
				
			||||||
            // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
					            // SAFETY: if the sparse index points to something in the dense vec, it exists
 | 
				
			||||||
            unsafe { self.dense.swap_remove_unchecked(dense_index) }
 | 
					            unsafe { self.dense.swap_remove_unchecked(TableRow::new(dense_index)) }
 | 
				
			||||||
            if !is_last {
 | 
					            if !is_last {
 | 
				
			||||||
                let swapped_entity = self.entities[dense_index];
 | 
					                let swapped_entity = self.entities[dense_index];
 | 
				
			||||||
                #[cfg(not(debug_assertions))]
 | 
					                #[cfg(not(debug_assertions))]
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,39 @@ impl TableId {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A opaque newtype for rows in [`Table`]s. Specifies a single row in a specific table.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Values of this type are retreivable 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 approripate 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)]
 | 
				
			||||||
 | 
					pub struct TableRow(usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TableRow {
 | 
				
			||||||
 | 
					    /// Creates a `TableRow`.
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub const fn new(index: usize) -> Self {
 | 
				
			||||||
 | 
					        Self(index)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Gets the index of the row.
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub const fn index(self) -> usize {
 | 
				
			||||||
 | 
					        self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Column {
 | 
					pub struct Column {
 | 
				
			||||||
    data: BlobVec,
 | 
					    data: BlobVec,
 | 
				
			||||||
@ -62,11 +95,11 @@ impl Column {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// Assumes data has already been allocated for the given row.
 | 
					    /// Assumes data has already been allocated for the given row.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) unsafe fn initialize(&mut self, row: usize, data: OwningPtr<'_>, tick: Tick) {
 | 
					    pub(crate) unsafe fn initialize(&mut self, row: TableRow, data: OwningPtr<'_>, tick: Tick) {
 | 
				
			||||||
        debug_assert!(row < self.len());
 | 
					        debug_assert!(row.index() < self.len());
 | 
				
			||||||
        self.data.initialize_unchecked(row, data);
 | 
					        self.data.initialize_unchecked(row.index(), data);
 | 
				
			||||||
        *self.added_ticks.get_unchecked_mut(row).get_mut() = tick;
 | 
					        *self.added_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
 | 
				
			||||||
        *self.changed_ticks.get_unchecked_mut(row).get_mut() = tick;
 | 
					        *self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Writes component data to the column at given row.
 | 
					    /// Writes component data to the column at given row.
 | 
				
			||||||
@ -75,11 +108,11 @@ impl Column {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// Assumes data has already been allocated for the given row.
 | 
					    /// Assumes data has already been allocated for the given row.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) unsafe fn replace(&mut self, row: usize, data: OwningPtr<'_>, change_tick: u32) {
 | 
					    pub(crate) unsafe fn replace(&mut self, row: TableRow, data: OwningPtr<'_>, change_tick: u32) {
 | 
				
			||||||
        debug_assert!(row < self.len());
 | 
					        debug_assert!(row.index() < self.len());
 | 
				
			||||||
        self.data.replace_unchecked(row, data);
 | 
					        self.data.replace_unchecked(row.index(), data);
 | 
				
			||||||
        self.changed_ticks
 | 
					        self.changed_ticks
 | 
				
			||||||
            .get_unchecked_mut(row)
 | 
					            .get_unchecked_mut(row.index())
 | 
				
			||||||
            .get_mut()
 | 
					            .get_mut()
 | 
				
			||||||
            .set_changed(change_tick);
 | 
					            .set_changed(change_tick);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -91,9 +124,9 @@ impl Column {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// Assumes data has already been allocated for the given row.
 | 
					    /// Assumes data has already been allocated for the given row.
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) unsafe fn replace_untracked(&mut self, row: usize, data: OwningPtr<'_>) {
 | 
					    pub(crate) unsafe fn replace_untracked(&mut self, row: TableRow, data: OwningPtr<'_>) {
 | 
				
			||||||
        debug_assert!(row < self.len());
 | 
					        debug_assert!(row.index() < self.len());
 | 
				
			||||||
        self.data.replace_unchecked(row, data);
 | 
					        self.data.replace_unchecked(row.index(), data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
@ -109,23 +142,23 @@ impl Column {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// index must be in-bounds
 | 
					    /// index must be in-bounds
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: usize) {
 | 
					    pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) {
 | 
				
			||||||
        self.data.swap_remove_and_drop_unchecked(row);
 | 
					        self.data.swap_remove_and_drop_unchecked(row.index());
 | 
				
			||||||
        self.added_ticks.swap_remove(row);
 | 
					        self.added_ticks.swap_remove(row.index());
 | 
				
			||||||
        self.changed_ticks.swap_remove(row);
 | 
					        self.changed_ticks.swap_remove(row.index());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    #[must_use = "The returned pointer should be used to drop the removed component"]
 | 
					    #[must_use = "The returned pointer should be used to drop the removed component"]
 | 
				
			||||||
    pub(crate) fn swap_remove_and_forget(
 | 
					    pub(crate) fn swap_remove_and_forget(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        row: usize,
 | 
					        row: TableRow,
 | 
				
			||||||
    ) -> Option<(OwningPtr<'_>, ComponentTicks)> {
 | 
					    ) -> Option<(OwningPtr<'_>, ComponentTicks)> {
 | 
				
			||||||
        (row < self.data.len()).then(|| {
 | 
					        (row.index() < self.data.len()).then(|| {
 | 
				
			||||||
            // SAFETY: The row was length checked before this.
 | 
					            // SAFETY: The row was length checked before this.
 | 
				
			||||||
            let data = unsafe { self.data.swap_remove_and_forget_unchecked(row) };
 | 
					            let data = unsafe { self.data.swap_remove_and_forget_unchecked(row.index()) };
 | 
				
			||||||
            let added = self.added_ticks.swap_remove(row).into_inner();
 | 
					            let added = self.added_ticks.swap_remove(row.index()).into_inner();
 | 
				
			||||||
            let changed = self.changed_ticks.swap_remove(row).into_inner();
 | 
					            let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
 | 
				
			||||||
            (data, ComponentTicks { added, changed })
 | 
					            (data, ComponentTicks { added, changed })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -136,11 +169,11 @@ impl Column {
 | 
				
			|||||||
    #[must_use = "The returned pointer should be used to dropped the removed component"]
 | 
					    #[must_use = "The returned pointer should be used to dropped the removed component"]
 | 
				
			||||||
    pub(crate) unsafe fn swap_remove_and_forget_unchecked(
 | 
					    pub(crate) unsafe fn swap_remove_and_forget_unchecked(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        row: usize,
 | 
					        row: TableRow,
 | 
				
			||||||
    ) -> (OwningPtr<'_>, ComponentTicks) {
 | 
					    ) -> (OwningPtr<'_>, ComponentTicks) {
 | 
				
			||||||
        let data = self.data.swap_remove_and_forget_unchecked(row);
 | 
					        let data = self.data.swap_remove_and_forget_unchecked(row.index());
 | 
				
			||||||
        let added = self.added_ticks.swap_remove(row).into_inner();
 | 
					        let added = self.added_ticks.swap_remove(row.index()).into_inner();
 | 
				
			||||||
        let changed = self.changed_ticks.swap_remove(row).into_inner();
 | 
					        let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
 | 
				
			||||||
        (data, ComponentTicks { added, changed })
 | 
					        (data, ComponentTicks { added, changed })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -159,14 +192,16 @@ impl Column {
 | 
				
			|||||||
    pub(crate) unsafe fn initialize_from_unchecked(
 | 
					    pub(crate) unsafe fn initialize_from_unchecked(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        other: &mut Column,
 | 
					        other: &mut Column,
 | 
				
			||||||
        src_row: usize,
 | 
					        src_row: TableRow,
 | 
				
			||||||
        dst_row: usize,
 | 
					        dst_row: TableRow,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        debug_assert!(self.data.layout() == other.data.layout());
 | 
					        debug_assert!(self.data.layout() == other.data.layout());
 | 
				
			||||||
        let ptr = self.data.get_unchecked_mut(dst_row);
 | 
					        let ptr = self.data.get_unchecked_mut(dst_row.index());
 | 
				
			||||||
        other.data.swap_remove_unchecked(src_row, ptr);
 | 
					        other.data.swap_remove_unchecked(src_row.index(), ptr);
 | 
				
			||||||
        *self.added_ticks.get_unchecked_mut(dst_row) = other.added_ticks.swap_remove(src_row);
 | 
					        *self.added_ticks.get_unchecked_mut(dst_row.index()) =
 | 
				
			||||||
        *self.changed_ticks.get_unchecked_mut(dst_row) = other.changed_ticks.swap_remove(src_row);
 | 
					            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());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // # Safety
 | 
					    // # Safety
 | 
				
			||||||
@ -206,66 +241,66 @@ impl Column {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get(&self, row: usize) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | 
					    pub fn get(&self, row: TableRow) -> Option<(Ptr<'_>, TickCells<'_>)> {
 | 
				
			||||||
        (row < self.data.len())
 | 
					        (row.index() < self.data.len())
 | 
				
			||||||
            // SAFETY: The row is length checked before fetching the pointer. This is being
 | 
					            // SAFETY: The row is length checked before fetching the pointer. This is being
 | 
				
			||||||
            // accessed through a read-only reference to the column.
 | 
					            // accessed through a read-only reference to the column.
 | 
				
			||||||
            .then(|| unsafe {
 | 
					            .then(|| unsafe {
 | 
				
			||||||
                (
 | 
					                (
 | 
				
			||||||
                    self.data.get_unchecked(row),
 | 
					                    self.data.get_unchecked(row.index()),
 | 
				
			||||||
                    TickCells {
 | 
					                    TickCells {
 | 
				
			||||||
                        added: self.added_ticks.get_unchecked(row),
 | 
					                        added: self.added_ticks.get_unchecked(row.index()),
 | 
				
			||||||
                        changed: self.changed_ticks.get_unchecked(row),
 | 
					                        changed: self.changed_ticks.get_unchecked(row.index()),
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_data(&self, row: usize) -> Option<Ptr<'_>> {
 | 
					    pub fn get_data(&self, row: TableRow) -> Option<Ptr<'_>> {
 | 
				
			||||||
        // SAFETY: The row is length checked before fetching the pointer. This is being
 | 
					        // SAFETY: The row is length checked before fetching the pointer. This is being
 | 
				
			||||||
        // accessed through a read-only reference to the column.
 | 
					        // accessed through a read-only reference to the column.
 | 
				
			||||||
        (row < self.data.len()).then(|| unsafe { self.data.get_unchecked(row) })
 | 
					        (row.index() < self.data.len()).then(|| unsafe { self.data.get_unchecked(row.index()) })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// - index must be in-bounds
 | 
					    /// - index must be in-bounds
 | 
				
			||||||
    /// - no other reference to the data of the same row can exist at the same time
 | 
					    /// - no other reference to the data of the same row can exist at the same time
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub unsafe fn get_data_unchecked(&self, row: usize) -> Ptr<'_> {
 | 
					    pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
 | 
				
			||||||
        debug_assert!(row < self.data.len());
 | 
					        debug_assert!(row.index() < self.data.len());
 | 
				
			||||||
        self.data.get_unchecked(row)
 | 
					        self.data.get_unchecked(row.index())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_data_mut(&mut self, row: usize) -> Option<PtrMut<'_>> {
 | 
					    pub fn get_data_mut(&mut self, row: TableRow) -> Option<PtrMut<'_>> {
 | 
				
			||||||
        // SAFETY: The row is length checked before fetching the pointer. This is being
 | 
					        // SAFETY: The row is length checked before fetching the pointer. This is being
 | 
				
			||||||
        // accessed through an exclusive reference to the column.
 | 
					        // accessed through an exclusive reference to the column.
 | 
				
			||||||
        (row < self.data.len()).then(|| unsafe { self.data.get_unchecked_mut(row) })
 | 
					        (row.index() < self.data.len()).then(|| unsafe { self.data.get_unchecked_mut(row.index()) })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// - index must be in-bounds
 | 
					    /// - index must be in-bounds
 | 
				
			||||||
    /// - no other reference to the data of the same row can exist at the same time
 | 
					    /// - no other reference to the data of the same row can exist at the same time
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub(crate) unsafe fn get_data_unchecked_mut(&mut self, row: usize) -> PtrMut<'_> {
 | 
					    pub(crate) unsafe fn get_data_unchecked_mut(&mut self, row: TableRow) -> PtrMut<'_> {
 | 
				
			||||||
        debug_assert!(row < self.data.len());
 | 
					        debug_assert!(row.index() < self.data.len());
 | 
				
			||||||
        self.data.get_unchecked_mut(row)
 | 
					        self.data.get_unchecked_mut(row.index())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_added_ticks(&self, row: usize) -> Option<&UnsafeCell<Tick>> {
 | 
					    pub fn get_added_ticks(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
 | 
				
			||||||
        self.added_ticks.get(row)
 | 
					        self.added_ticks.get(row.index())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_changed_ticks(&self, row: usize) -> Option<&UnsafeCell<Tick>> {
 | 
					    pub fn get_changed_ticks(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
 | 
				
			||||||
        self.changed_ticks.get(row)
 | 
					        self.changed_ticks.get(row.index())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn get_ticks(&self, row: usize) -> Option<ComponentTicks> {
 | 
					    pub fn get_ticks(&self, row: TableRow) -> Option<ComponentTicks> {
 | 
				
			||||||
        if row < self.data.len() {
 | 
					        if row.index() < self.data.len() {
 | 
				
			||||||
            // SAFETY: The size of the column has already been checked.
 | 
					            // SAFETY: The size of the column has already been checked.
 | 
				
			||||||
            Some(unsafe { self.get_ticks_unchecked(row) })
 | 
					            Some(unsafe { self.get_ticks_unchecked(row) })
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -276,28 +311,28 @@ impl Column {
 | 
				
			|||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// index must be in-bounds
 | 
					    /// index must be in-bounds
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub unsafe fn get_added_ticks_unchecked(&self, row: usize) -> &UnsafeCell<Tick> {
 | 
					    pub unsafe fn get_added_ticks_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
 | 
				
			||||||
        debug_assert!(row < self.added_ticks.len());
 | 
					        debug_assert!(row.index() < self.added_ticks.len());
 | 
				
			||||||
        self.added_ticks.get_unchecked(row)
 | 
					        self.added_ticks.get_unchecked(row.index())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// index must be in-bounds
 | 
					    /// index must be in-bounds
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub unsafe fn get_changed_ticks_unchecked(&self, row: usize) -> &UnsafeCell<Tick> {
 | 
					    pub unsafe fn get_changed_ticks_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
 | 
				
			||||||
        debug_assert!(row < self.changed_ticks.len());
 | 
					        debug_assert!(row.index() < self.changed_ticks.len());
 | 
				
			||||||
        self.changed_ticks.get_unchecked(row)
 | 
					        self.changed_ticks.get_unchecked(row.index())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// index must be in-bounds
 | 
					    /// index must be in-bounds
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub unsafe fn get_ticks_unchecked(&self, row: usize) -> ComponentTicks {
 | 
					    pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
 | 
				
			||||||
        debug_assert!(row < self.added_ticks.len());
 | 
					        debug_assert!(row.index() < self.added_ticks.len());
 | 
				
			||||||
        debug_assert!(row < self.changed_ticks.len());
 | 
					        debug_assert!(row.index() < self.changed_ticks.len());
 | 
				
			||||||
        ComponentTicks {
 | 
					        ComponentTicks {
 | 
				
			||||||
            added: self.added_ticks.get_unchecked(row).read(),
 | 
					            added: self.added_ticks.get_unchecked(row.index()).read(),
 | 
				
			||||||
            changed: self.changed_ticks.get_unchecked(row).read(),
 | 
					            changed: self.changed_ticks.get_unchecked(row.index()).read(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -385,16 +420,16 @@ impl Table {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// `row` must be in-bounds
 | 
					    /// `row` must be in-bounds
 | 
				
			||||||
    pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: usize) -> Option<Entity> {
 | 
					    pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) -> Option<Entity> {
 | 
				
			||||||
        for column in self.columns.values_mut() {
 | 
					        for column in self.columns.values_mut() {
 | 
				
			||||||
            column.swap_remove_unchecked(row);
 | 
					            column.swap_remove_unchecked(row);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let is_last = row == self.entities.len() - 1;
 | 
					        let is_last = row.index() == self.entities.len() - 1;
 | 
				
			||||||
        self.entities.swap_remove(row);
 | 
					        self.entities.swap_remove(row.index());
 | 
				
			||||||
        if is_last {
 | 
					        if is_last {
 | 
				
			||||||
            None
 | 
					            None
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Some(self.entities[row])
 | 
					            Some(self.entities[row.index()])
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -407,12 +442,12 @@ impl Table {
 | 
				
			|||||||
    /// Row must be in-bounds
 | 
					    /// Row must be in-bounds
 | 
				
			||||||
    pub(crate) unsafe fn move_to_and_forget_missing_unchecked(
 | 
					    pub(crate) unsafe fn move_to_and_forget_missing_unchecked(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        row: usize,
 | 
					        row: TableRow,
 | 
				
			||||||
        new_table: &mut Table,
 | 
					        new_table: &mut Table,
 | 
				
			||||||
    ) -> TableMoveResult {
 | 
					    ) -> TableMoveResult {
 | 
				
			||||||
        debug_assert!(row < self.entity_count());
 | 
					        debug_assert!(row.index() < self.entity_count());
 | 
				
			||||||
        let is_last = row == self.entities.len() - 1;
 | 
					        let is_last = row.index() == self.entities.len() - 1;
 | 
				
			||||||
        let new_row = new_table.allocate(self.entities.swap_remove(row));
 | 
					        let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
 | 
				
			||||||
        for (component_id, column) in self.columns.iter_mut() {
 | 
					        for (component_id, column) in self.columns.iter_mut() {
 | 
				
			||||||
            if let Some(new_column) = new_table.get_column_mut(*component_id) {
 | 
					            if let Some(new_column) = new_table.get_column_mut(*component_id) {
 | 
				
			||||||
                new_column.initialize_from_unchecked(column, row, new_row);
 | 
					                new_column.initialize_from_unchecked(column, row, new_row);
 | 
				
			||||||
@ -426,7 +461,7 @@ impl Table {
 | 
				
			|||||||
            swapped_entity: if is_last {
 | 
					            swapped_entity: if is_last {
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                Some(self.entities[row])
 | 
					                Some(self.entities[row.index()])
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -439,12 +474,12 @@ impl Table {
 | 
				
			|||||||
    /// row must be in-bounds
 | 
					    /// row must be in-bounds
 | 
				
			||||||
    pub(crate) unsafe fn move_to_and_drop_missing_unchecked(
 | 
					    pub(crate) unsafe fn move_to_and_drop_missing_unchecked(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        row: usize,
 | 
					        row: TableRow,
 | 
				
			||||||
        new_table: &mut Table,
 | 
					        new_table: &mut Table,
 | 
				
			||||||
    ) -> TableMoveResult {
 | 
					    ) -> TableMoveResult {
 | 
				
			||||||
        debug_assert!(row < self.entity_count());
 | 
					        debug_assert!(row.index() < self.entity_count());
 | 
				
			||||||
        let is_last = row == self.entities.len() - 1;
 | 
					        let is_last = row.index() == self.entities.len() - 1;
 | 
				
			||||||
        let new_row = new_table.allocate(self.entities.swap_remove(row));
 | 
					        let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
 | 
				
			||||||
        for (component_id, column) in self.columns.iter_mut() {
 | 
					        for (component_id, column) in self.columns.iter_mut() {
 | 
				
			||||||
            if let Some(new_column) = new_table.get_column_mut(*component_id) {
 | 
					            if let Some(new_column) = new_table.get_column_mut(*component_id) {
 | 
				
			||||||
                new_column.initialize_from_unchecked(column, row, new_row);
 | 
					                new_column.initialize_from_unchecked(column, row, new_row);
 | 
				
			||||||
@ -457,7 +492,7 @@ impl Table {
 | 
				
			|||||||
            swapped_entity: if is_last {
 | 
					            swapped_entity: if is_last {
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                Some(self.entities[row])
 | 
					                Some(self.entities[row.index()])
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -470,12 +505,12 @@ impl Table {
 | 
				
			|||||||
    /// `row` must be in-bounds. `new_table` must contain every component this table has
 | 
					    /// `row` must be in-bounds. `new_table` must contain every component this table has
 | 
				
			||||||
    pub(crate) unsafe fn move_to_superset_unchecked(
 | 
					    pub(crate) unsafe fn move_to_superset_unchecked(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        row: usize,
 | 
					        row: TableRow,
 | 
				
			||||||
        new_table: &mut Table,
 | 
					        new_table: &mut Table,
 | 
				
			||||||
    ) -> TableMoveResult {
 | 
					    ) -> TableMoveResult {
 | 
				
			||||||
        debug_assert!(row < self.entity_count());
 | 
					        debug_assert!(row.index() < self.entity_count());
 | 
				
			||||||
        let is_last = row == self.entities.len() - 1;
 | 
					        let is_last = row.index() == self.entities.len() - 1;
 | 
				
			||||||
        let new_row = new_table.allocate(self.entities.swap_remove(row));
 | 
					        let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
 | 
				
			||||||
        for (component_id, column) in self.columns.iter_mut() {
 | 
					        for (component_id, column) in self.columns.iter_mut() {
 | 
				
			||||||
            new_table
 | 
					            new_table
 | 
				
			||||||
                .get_column_mut(*component_id)
 | 
					                .get_column_mut(*component_id)
 | 
				
			||||||
@ -487,7 +522,7 @@ impl Table {
 | 
				
			|||||||
            swapped_entity: if is_last {
 | 
					            swapped_entity: if is_last {
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                Some(self.entities[row])
 | 
					                Some(self.entities[row.index()])
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -524,7 +559,7 @@ impl Table {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Safety
 | 
					    /// # Safety
 | 
				
			||||||
    /// the allocated row must be written to immediately with valid values in each column
 | 
					    /// the allocated row must be written to immediately with valid values in each column
 | 
				
			||||||
    pub(crate) unsafe fn allocate(&mut self, entity: Entity) -> usize {
 | 
					    pub(crate) unsafe fn allocate(&mut self, entity: Entity) -> TableRow {
 | 
				
			||||||
        self.reserve(1);
 | 
					        self.reserve(1);
 | 
				
			||||||
        let index = self.entities.len();
 | 
					        let index = self.entities.len();
 | 
				
			||||||
        self.entities.push(entity);
 | 
					        self.entities.push(entity);
 | 
				
			||||||
@ -533,7 +568,7 @@ impl Table {
 | 
				
			|||||||
            column.added_ticks.push(UnsafeCell::new(Tick::new(0)));
 | 
					            column.added_ticks.push(UnsafeCell::new(Tick::new(0)));
 | 
				
			||||||
            column.changed_ticks.push(UnsafeCell::new(Tick::new(0)));
 | 
					            column.changed_ticks.push(UnsafeCell::new(Tick::new(0)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        index
 | 
					        TableRow(index)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
@ -594,7 +629,7 @@ impl Default for Tables {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub(crate) struct TableMoveResult {
 | 
					pub(crate) struct TableMoveResult {
 | 
				
			||||||
    pub swapped_entity: Option<Entity>,
 | 
					    pub swapped_entity: Option<Entity>,
 | 
				
			||||||
    pub new_row: usize,
 | 
					    pub new_row: TableRow,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Tables {
 | 
					impl Tables {
 | 
				
			||||||
@ -690,7 +725,7 @@ mod tests {
 | 
				
			|||||||
    use crate::{
 | 
					    use crate::{
 | 
				
			||||||
        component::{Components, Tick},
 | 
					        component::{Components, Tick},
 | 
				
			||||||
        entity::Entity,
 | 
					        entity::Entity,
 | 
				
			||||||
        storage::TableBuilder,
 | 
					        storage::{TableBuilder, TableRow},
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    #[derive(Component)]
 | 
					    #[derive(Component)]
 | 
				
			||||||
    struct W<T>(T);
 | 
					    struct W<T>(T);
 | 
				
			||||||
@ -699,7 +734,7 @@ mod tests {
 | 
				
			|||||||
    fn table() {
 | 
					    fn table() {
 | 
				
			||||||
        let mut components = Components::default();
 | 
					        let mut components = Components::default();
 | 
				
			||||||
        let mut storages = Storages::default();
 | 
					        let mut storages = Storages::default();
 | 
				
			||||||
        let component_id = components.init_component::<W<usize>>(&mut storages);
 | 
					        let component_id = components.init_component::<W<TableRow>>(&mut storages);
 | 
				
			||||||
        let columns = &[component_id];
 | 
					        let columns = &[component_id];
 | 
				
			||||||
        let mut builder = TableBuilder::with_capacity(0, columns.len());
 | 
					        let mut builder = TableBuilder::with_capacity(0, columns.len());
 | 
				
			||||||
        builder.add_column(components.get_info(component_id).unwrap());
 | 
					        builder.add_column(components.get_info(component_id).unwrap());
 | 
				
			||||||
@ -709,7 +744,7 @@ mod tests {
 | 
				
			|||||||
            // SAFETY: we allocate and immediately set data afterwards
 | 
					            // SAFETY: we allocate and immediately set data afterwards
 | 
				
			||||||
            unsafe {
 | 
					            unsafe {
 | 
				
			||||||
                let row = table.allocate(*entity);
 | 
					                let row = table.allocate(*entity);
 | 
				
			||||||
                let value: W<usize> = W(row);
 | 
					                let value: W<TableRow> = W(row);
 | 
				
			||||||
                OwningPtr::make(value, |value_ptr| {
 | 
					                OwningPtr::make(value, |value_ptr| {
 | 
				
			||||||
                    table.get_column_mut(component_id).unwrap().initialize(
 | 
					                    table.get_column_mut(component_id).unwrap().initialize(
 | 
				
			||||||
                        row,
 | 
					                        row,
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ use crate::{
 | 
				
			|||||||
        TickCells,
 | 
					        TickCells,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    entity::{Entities, Entity, EntityLocation},
 | 
					    entity::{Entities, Entity, EntityLocation},
 | 
				
			||||||
    storage::{Column, ComponentSparseSet, SparseSet, Storages},
 | 
					    storage::{Column, ComponentSparseSet, SparseSet, Storages, TableRow},
 | 
				
			||||||
    world::{Mut, World},
 | 
					    world::{Mut, World},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_ptr::{OwningPtr, Ptr};
 | 
					use bevy_ptr::{OwningPtr, Ptr};
 | 
				
			||||||
@ -371,7 +371,8 @@ impl<'w> EntityMut<'w> {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
        // SAFETY: location matches current entity. `T` matches `bundle_info`
 | 
					        // SAFETY: location matches current entity. `T` matches `bundle_info`
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            self.location = bundle_inserter.insert(self.entity, self.location.index, bundle);
 | 
					            self.location =
 | 
				
			||||||
 | 
					                bundle_inserter.insert(self.entity, self.location.archetype_row, bundle);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
@ -465,7 +466,7 @@ impl<'w> EntityMut<'w> {
 | 
				
			|||||||
        new_archetype_id: ArchetypeId,
 | 
					        new_archetype_id: ArchetypeId,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let old_archetype = &mut archetypes[old_archetype_id];
 | 
					        let old_archetype = &mut archetypes[old_archetype_id];
 | 
				
			||||||
        let remove_result = old_archetype.swap_remove(old_location.index);
 | 
					        let remove_result = old_archetype.swap_remove(old_location.archetype_row);
 | 
				
			||||||
        if let Some(swapped_entity) = remove_result.swapped_entity {
 | 
					        if let Some(swapped_entity) = remove_result.swapped_entity {
 | 
				
			||||||
            entities.set(swapped_entity.index(), old_location);
 | 
					            entities.set(swapped_entity.index(), old_location);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -494,7 +495,7 @@ impl<'w> EntityMut<'w> {
 | 
				
			|||||||
            if let Some(swapped_entity) = move_result.swapped_entity {
 | 
					            if let Some(swapped_entity) = move_result.swapped_entity {
 | 
				
			||||||
                let swapped_location = entities.get(swapped_entity).unwrap();
 | 
					                let swapped_location = entities.get(swapped_entity).unwrap();
 | 
				
			||||||
                archetypes[swapped_location.archetype_id]
 | 
					                archetypes[swapped_location.archetype_id]
 | 
				
			||||||
                    .set_entity_table_row(swapped_location.index, old_table_row);
 | 
					                    .set_entity_table_row(swapped_location.archetype_row, old_table_row);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            new_location
 | 
					            new_location
 | 
				
			||||||
@ -588,7 +589,7 @@ impl<'w> EntityMut<'w> {
 | 
				
			|||||||
                    .get_or_insert_with(component_id, Vec::new);
 | 
					                    .get_or_insert_with(component_id, Vec::new);
 | 
				
			||||||
                removed_components.push(self.entity);
 | 
					                removed_components.push(self.entity);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            let remove_result = archetype.swap_remove(location.index);
 | 
					            let remove_result = archetype.swap_remove(location.archetype_row);
 | 
				
			||||||
            if let Some(swapped_entity) = remove_result.swapped_entity {
 | 
					            if let Some(swapped_entity) = remove_result.swapped_entity {
 | 
				
			||||||
                // SAFETY: swapped_entity is valid and the swapped entity's components are
 | 
					                // SAFETY: swapped_entity is valid and the swapped entity's components are
 | 
				
			||||||
                // moved to the new location immediately after.
 | 
					                // moved to the new location immediately after.
 | 
				
			||||||
@ -611,7 +612,7 @@ impl<'w> EntityMut<'w> {
 | 
				
			|||||||
        if let Some(moved_entity) = moved_entity {
 | 
					        if let Some(moved_entity) = moved_entity {
 | 
				
			||||||
            let moved_location = world.entities.get(moved_entity).unwrap();
 | 
					            let moved_location = world.entities.get(moved_entity).unwrap();
 | 
				
			||||||
            world.archetypes[moved_location.archetype_id]
 | 
					            world.archetypes[moved_location.archetype_id]
 | 
				
			||||||
                .set_entity_table_row(moved_location.index, table_row);
 | 
					                .set_entity_table_row(moved_location.archetype_row, table_row);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -701,11 +702,11 @@ fn fetch_table(
 | 
				
			|||||||
    world: &World,
 | 
					    world: &World,
 | 
				
			||||||
    location: EntityLocation,
 | 
					    location: EntityLocation,
 | 
				
			||||||
    component_id: ComponentId,
 | 
					    component_id: ComponentId,
 | 
				
			||||||
) -> Option<(&Column, usize)> {
 | 
					) -> Option<(&Column, TableRow)> {
 | 
				
			||||||
    let archetype = &world.archetypes[location.archetype_id];
 | 
					    let archetype = &world.archetypes[location.archetype_id];
 | 
				
			||||||
    let table = &world.storages.tables[archetype.table_id()];
 | 
					    let table = &world.storages.tables[archetype.table_id()];
 | 
				
			||||||
    let components = table.get_column(component_id)?;
 | 
					    let components = table.get_column(component_id)?;
 | 
				
			||||||
    let table_row = archetype.entity_table_row(location.index);
 | 
					    let table_row = archetype.entity_table_row(location.archetype_row);
 | 
				
			||||||
    Some((components, table_row))
 | 
					    Some((components, table_row))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -823,7 +824,7 @@ unsafe fn take_component<'a>(
 | 
				
			|||||||
            let table = &mut storages.tables[archetype.table_id()];
 | 
					            let table = &mut storages.tables[archetype.table_id()];
 | 
				
			||||||
            // SAFETY: archetypes will always point to valid columns
 | 
					            // SAFETY: archetypes will always point to valid columns
 | 
				
			||||||
            let components = table.get_column_mut(component_id).unwrap();
 | 
					            let components = table.get_column_mut(component_id).unwrap();
 | 
				
			||||||
            let table_row = archetype.entity_table_row(location.index);
 | 
					            let table_row = archetype.entity_table_row(location.archetype_row);
 | 
				
			||||||
            // SAFETY: archetypes only store valid table_rows and the stored component type is T
 | 
					            // SAFETY: archetypes only store valid table_rows and the stored component type is T
 | 
				
			||||||
            components.get_data_unchecked_mut(table_row).promote()
 | 
					            components.get_data_unchecked_mut(table_row).promote()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ pub use spawn_batch::*;
 | 
				
			|||||||
pub use world_cell::*;
 | 
					pub use world_cell::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    archetype::{ArchetypeComponentId, ArchetypeId, Archetypes},
 | 
					    archetype::{ArchetypeComponentId, ArchetypeId, ArchetypeRow, Archetypes},
 | 
				
			||||||
    bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
 | 
					    bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
 | 
				
			||||||
    change_detection::{MutUntyped, Ticks},
 | 
					    change_detection::{MutUntyped, Ticks},
 | 
				
			||||||
    component::{
 | 
					    component::{
 | 
				
			||||||
@ -329,10 +329,10 @@ impl World {
 | 
				
			|||||||
                .entities()
 | 
					                .entities()
 | 
				
			||||||
                .iter()
 | 
					                .iter()
 | 
				
			||||||
                .enumerate()
 | 
					                .enumerate()
 | 
				
			||||||
                .map(|(index, archetype_entity)| {
 | 
					                .map(|(archetype_row, archetype_entity)| {
 | 
				
			||||||
                    let location = EntityLocation {
 | 
					                    let location = EntityLocation {
 | 
				
			||||||
                        archetype_id: archetype.id(),
 | 
					                        archetype_id: archetype.id(),
 | 
				
			||||||
                        index,
 | 
					                        archetype_row: ArchetypeRow::new(archetype_row),
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    EntityRef::new(self, archetype_entity.entity(), location)
 | 
					                    EntityRef::new(self, archetype_entity.entity(), location)
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
@ -1096,7 +1096,7 @@ impl World {
 | 
				
			|||||||
                            if location.archetype_id == archetype =>
 | 
					                            if location.archetype_id == archetype =>
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            // SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
 | 
					                            // SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
 | 
				
			||||||
                            unsafe { inserter.insert(entity, location.index, bundle) };
 | 
					                            unsafe { inserter.insert(entity, location.archetype_row, bundle) };
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        _ => {
 | 
					                        _ => {
 | 
				
			||||||
                            let mut inserter = bundle_info.get_bundle_inserter(
 | 
					                            let mut inserter = bundle_info.get_bundle_inserter(
 | 
				
			||||||
@ -1108,7 +1108,7 @@ impl World {
 | 
				
			|||||||
                                change_tick,
 | 
					                                change_tick,
 | 
				
			||||||
                            );
 | 
					                            );
 | 
				
			||||||
                            // SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
 | 
					                            // SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
 | 
				
			||||||
                            unsafe { inserter.insert(entity, location.index, bundle) };
 | 
					                            unsafe { inserter.insert(entity, location.archetype_row, bundle) };
 | 
				
			||||||
                            spawn_or_insert =
 | 
					                            spawn_or_insert =
 | 
				
			||||||
                                SpawnOrInsert::Insert(inserter, location.archetype_id);
 | 
					                                SpawnOrInsert::Insert(inserter, location.archetype_id);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user