mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Add EntityMut::get_mut_by_id_unchecked (#16210)
# Objective - Fixes: #15603 ## Solution - Add an unsafe `get_mut_by_id_unchecked` to `EntityMut` that borrows &self instead of &mut self, thereby allowing access to multiple components simultaneously. ## Testing - a unit test function `get_mut_by_id_unchecked` was added. --------- Co-authored-by: Mike <mike.hsu@gmail.com>
This commit is contained in:
parent
57931ce42f
commit
b83c0e106e
1 changed files with 51 additions and 0 deletions
|
@ -730,6 +730,34 @@ impl<'w> EntityMut<'w> {
|
||||||
unsafe { component_ids.fetch_mut(self.0) }
|
unsafe { component_ids.fetch_mut(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns [untyped mutable reference](MutUntyped) to component for
|
||||||
|
/// the current entity, based on the given [`ComponentId`].
|
||||||
|
///
|
||||||
|
/// Unlike [`EntityMut::get_mut_by_id`], this method borrows &self instead of
|
||||||
|
/// &mut self, allowing the caller to access multiple components simultaneously.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - Returns [`EntityComponentError::MissingComponent`] if the entity does
|
||||||
|
/// not have a component.
|
||||||
|
/// - Returns [`EntityComponentError::AliasedMutability`] if a component
|
||||||
|
/// is requested multiple times.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// It is the callers responsibility to ensure that
|
||||||
|
/// - the [`UnsafeEntityCell`] has permission to access the component mutably
|
||||||
|
/// - no other references to the component exist at the same time
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get_mut_by_id_unchecked<F: DynamicComponentFetch>(
|
||||||
|
&self,
|
||||||
|
component_ids: F,
|
||||||
|
) -> Result<F::Mut<'_>, EntityComponentError> {
|
||||||
|
// SAFETY:
|
||||||
|
// - The caller must ensure simultaneous access is limited
|
||||||
|
// - to components that are mutually independent.
|
||||||
|
unsafe { component_ids.fetch_mut(self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes `self` and returns [untyped mutable reference(s)](MutUntyped)
|
/// Consumes `self` and returns [untyped mutable reference(s)](MutUntyped)
|
||||||
/// to component(s) with lifetime `'w` for the current entity, based on the
|
/// to component(s) with lifetime `'w` for the current entity, based on the
|
||||||
/// given [`ComponentId`]s.
|
/// given [`ComponentId`]s.
|
||||||
|
@ -4425,4 +4453,27 @@ mod tests {
|
||||||
.map(|_| { unreachable!() })
|
.map(|_| { unreachable!() })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_mut_by_id_unchecked() {
|
||||||
|
let mut world = World::default();
|
||||||
|
let e1 = world.spawn((X(7), Y(10))).id();
|
||||||
|
let x_id = world.register_component::<X>();
|
||||||
|
let y_id = world.register_component::<Y>();
|
||||||
|
|
||||||
|
let e1_mut = &world.get_entity_mut([e1]).unwrap()[0];
|
||||||
|
// SAFETY: The entity e1 contains component X.
|
||||||
|
let x_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(x_id) }.unwrap();
|
||||||
|
// SAFETY: The entity e1 contains component Y, with components X and Y being mutually independent.
|
||||||
|
let y_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(y_id) }.unwrap();
|
||||||
|
|
||||||
|
// SAFETY: components match the id they were fetched with
|
||||||
|
let x_component = unsafe { x_ptr.into_inner().deref_mut::<X>() };
|
||||||
|
x_component.0 += 1;
|
||||||
|
// SAFETY: components match the id they were fetched with
|
||||||
|
let y_component = unsafe { y_ptr.into_inner().deref_mut::<Y>() };
|
||||||
|
y_component.0 -= 1;
|
||||||
|
|
||||||
|
assert_eq!((&mut X(8), &mut Y(9)), (x_component, y_component));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue