Skip to content

Commit 603ba07

Browse files
move take_component to Storages and add some safety comments
1 parent ae2172e commit 603ba07

File tree

2 files changed

+52
-49
lines changed

2 files changed

+52
-49
lines changed

crates/bevy_ecs/src/storage/mod.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
component::{ComponentId, ComponentTicks, Components, StorageType, TickCells},
1515
entity::{Entity, EntityLocation},
1616
};
17-
use bevy_ptr::Ptr;
17+
use bevy_ptr::{OwningPtr, Ptr};
1818
use std::any::TypeId;
1919

2020
/// The raw data stores of a [World](crate::world::World)
@@ -186,6 +186,50 @@ impl Storages {
186186
}
187187
}
188188

189+
impl Storages {
190+
/// Moves component data out of storage.
191+
///
192+
/// This function leaves the underlying memory unchanged, but the component behind
193+
/// returned pointer is semantically owned by the caller and will not be dropped in its original location.
194+
/// Caller is responsible to drop component data behind returned pointer.
195+
///
196+
/// # Safety
197+
/// - `location` must be within bounds of the given archetype and `entity` must exist inside the `archetype`
198+
/// - `component_id` must be valid
199+
/// - `components` must come from the same world as `self`
200+
/// - The relevant table row **must be removed** by the caller once all components are taken
201+
#[inline]
202+
pub(crate) unsafe fn take_component<'a>(
203+
&'a mut self,
204+
components: &Components,
205+
removed_components: &mut SparseSet<ComponentId, Vec<Entity>>,
206+
component_id: ComponentId,
207+
entity: Entity,
208+
location: EntityLocation,
209+
) -> OwningPtr<'a> {
210+
let component_info = components.get_info_unchecked(component_id);
211+
let removed_components = removed_components.get_or_insert_with(component_id, Vec::new);
212+
removed_components.push(entity);
213+
match component_info.storage_type() {
214+
StorageType::Table => {
215+
let table = &mut self.tables[location.table_id];
216+
// SAFETY: archetypes will always point to valid columns
217+
let components = table.get_column_mut(component_id).unwrap();
218+
// SAFETY: archetypes only store valid table_rows and the stored component type is T
219+
components
220+
.get_data_unchecked_mut(location.table_row)
221+
.promote()
222+
}
223+
StorageType::SparseSet => self
224+
.sparse_sets
225+
.get_mut(component_id)
226+
.unwrap()
227+
.remove_and_forget(entity)
228+
.unwrap(),
229+
}
230+
}
231+
}
232+
189233
#[inline]
190234
unsafe fn fetch_table<'s>(
191235
archetypes: &Archetypes,

crates/bevy_ecs/src/world/entity_ref.rs

Lines changed: 7 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use crate::{
66
Component, ComponentId, ComponentStorage, ComponentTicks, Components, StorageType,
77
},
88
entity::{Entities, Entity, EntityLocation},
9-
storage::{SparseSet, Storages},
9+
storage::Storages,
1010
world::{Mut, World},
1111
};
12-
use bevy_ptr::{OwningPtr, Ptr};
12+
use bevy_ptr::Ptr;
1313
use bevy_utils::tracing::debug;
1414
use std::any::TypeId;
1515

@@ -437,10 +437,12 @@ impl<'w> EntityMut<'w> {
437437
let result = unsafe {
438438
T::from_components(storages, &mut |storages| {
439439
let component_id = bundle_components.next().unwrap();
440-
// SAFETY: entity location is valid and table row is removed below
441-
take_component(
440+
// SAFETY:
441+
// - entity location is valid
442+
// - table row is removed below
443+
// - `components` comes from the same world as `storages`
444+
storages.take_component(
442445
components,
443-
storages,
444446
removed_components,
445447
component_id,
446448
entity,
@@ -718,49 +720,6 @@ impl<'w> EntityMut<'w> {
718720
}
719721
}
720722

721-
// TODO: move to Storages?
722-
/// Moves component data out of storage.
723-
///
724-
/// This function leaves the underlying memory unchanged, but the component behind
725-
/// returned pointer is semantically owned by the caller and will not be dropped in its original location.
726-
/// Caller is responsible to drop component data behind returned pointer.
727-
///
728-
/// # Safety
729-
/// - `location` must be within bounds of the given archetype and table and `entity` must exist inside the archetype
730-
/// and table.
731-
/// - `component_id` must be valid
732-
/// - The relevant table row **must be removed** by the caller once all components are taken
733-
#[inline]
734-
unsafe fn take_component<'a>(
735-
components: &Components,
736-
storages: &'a mut Storages,
737-
removed_components: &mut SparseSet<ComponentId, Vec<Entity>>,
738-
component_id: ComponentId,
739-
entity: Entity,
740-
location: EntityLocation,
741-
) -> OwningPtr<'a> {
742-
let component_info = components.get_info_unchecked(component_id);
743-
let removed_components = removed_components.get_or_insert_with(component_id, Vec::new);
744-
removed_components.push(entity);
745-
match component_info.storage_type() {
746-
StorageType::Table => {
747-
let table = &mut storages.tables[location.table_id];
748-
// SAFETY: archetypes will always point to valid columns
749-
let components = table.get_column_mut(component_id).unwrap();
750-
// SAFETY: archetypes only store valid table_rows and the stored component type is T
751-
components
752-
.get_data_unchecked_mut(location.table_row)
753-
.promote()
754-
}
755-
StorageType::SparseSet => storages
756-
.sparse_sets
757-
.get_mut(component_id)
758-
.unwrap()
759-
.remove_and_forget(entity)
760-
.unwrap(),
761-
}
762-
}
763-
764723
fn contains_component_with_type(world: &World, type_id: TypeId, location: EntityLocation) -> bool {
765724
if let Some(component_id) = world.components.get_id(type_id) {
766725
contains_component_with_id(world, component_id, location)

0 commit comments

Comments
 (0)