Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1041
vendor/bevy_ecs/src/archetype.rs vendored Normal file

File diff suppressed because it is too large Load Diff

107
vendor/bevy_ecs/src/batching.rs vendored Normal file
View File

@@ -0,0 +1,107 @@
//! Types for controlling batching behavior during parallel processing.
use core::ops::Range;
/// Dictates how a parallel operation chunks up large quantities
/// during iteration.
///
/// A parallel query will chunk up large tables and archetypes into
/// chunks of at most a certain batch size. Similarly, a parallel event
/// reader will chunk up the remaining events.
///
/// By default, this batch size is automatically determined by dividing
/// the size of the largest matched archetype by the number
/// of threads (rounded up). This attempts to minimize the overhead of scheduling
/// tasks onto multiple threads, but assumes each entity has roughly the
/// same amount of work to be done, which may not hold true in every
/// workload.
///
/// See [`Query::par_iter`], [`EventReader::par_read`] for more information.
///
/// [`Query::par_iter`]: crate::system::Query::par_iter
/// [`EventReader::par_read`]: crate::event::EventReader::par_read
#[derive(Clone, Debug)]
pub struct BatchingStrategy {
/// The upper and lower limits for a batch of entities.
///
/// Setting the bounds to the same value will result in a fixed
/// batch size.
///
/// Defaults to `[1, usize::MAX]`.
pub batch_size_limits: Range<usize>,
/// The number of batches per thread in the [`ComputeTaskPool`].
/// Increasing this value will decrease the batch size, which may
/// increase the scheduling overhead for the iteration.
///
/// Defaults to 1.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
pub batches_per_thread: usize,
}
impl Default for BatchingStrategy {
fn default() -> Self {
Self::new()
}
}
impl BatchingStrategy {
/// Creates a new unconstrained default batching strategy.
pub const fn new() -> Self {
Self {
batch_size_limits: 1..usize::MAX,
batches_per_thread: 1,
}
}
/// Declares a batching strategy with a fixed batch size.
pub const fn fixed(batch_size: usize) -> Self {
Self {
batch_size_limits: batch_size..batch_size,
batches_per_thread: 1,
}
}
/// Configures the minimum allowed batch size of this instance.
pub const fn min_batch_size(mut self, batch_size: usize) -> Self {
self.batch_size_limits.start = batch_size;
self
}
/// Configures the maximum allowed batch size of this instance.
pub const fn max_batch_size(mut self, batch_size: usize) -> Self {
self.batch_size_limits.end = batch_size;
self
}
/// Configures the number of batches to assign to each thread for this instance.
pub fn batches_per_thread(mut self, batches_per_thread: usize) -> Self {
assert!(
batches_per_thread > 0,
"The number of batches per thread must be non-zero."
);
self.batches_per_thread = batches_per_thread;
self
}
/// Calculate the batch size according to the given thread count and max item count.
/// The count is provided as a closure so that it can be calculated only if needed.
///
/// # Panics
///
/// Panics if `thread_count` is 0.
#[inline]
pub fn calc_batch_size(&self, max_items: impl FnOnce() -> usize, thread_count: usize) -> usize {
if self.batch_size_limits.is_empty() {
return self.batch_size_limits.start;
}
assert!(
thread_count > 0,
"Attempted to run parallel iteration with an empty TaskPool"
);
let batches = thread_count * self.batches_per_thread;
// Round up to the nearest batch size.
let batch_size = max_items().div_ceil(batches);
batch_size.clamp(self.batch_size_limits.start, self.batch_size_limits.end)
}
}

1989
vendor/bevy_ecs/src/bundle.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1888
vendor/bevy_ecs/src/change_detection.rs vendored Normal file

File diff suppressed because it is too large Load Diff

3178
vendor/bevy_ecs/src/component.rs vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

547
vendor/bevy_ecs/src/entity/entity_set.rs vendored Normal file
View File

@@ -0,0 +1,547 @@
use alloc::{
boxed::Box,
collections::{btree_map, btree_set},
rc::Rc,
};
use bevy_platform::collections::HashSet;
use core::{
array,
fmt::{Debug, Formatter},
hash::{BuildHasher, Hash},
iter::{self, FusedIterator},
option, result,
};
use super::{Entity, UniqueEntityEquivalentSlice};
use bevy_platform::sync::Arc;
/// A trait for types that contain an [`Entity`].
///
/// This trait behaves similarly to `Borrow<Entity>`, but yielding `Entity` directly.
///
/// It should only be implemented when:
/// - Retrieving the [`Entity`] is a simple operation.
/// - The [`Entity`] contained by the type is unambiguous.
pub trait ContainsEntity {
/// Returns the contained entity.
fn entity(&self) -> Entity;
}
/// A trait for types that represent an [`Entity`].
///
/// Comparison trait behavior between an [`EntityEquivalent`] type and its underlying entity will match.
/// This property includes [`PartialEq`], [`Eq`], [`PartialOrd`], [`Ord`] and [`Hash`],
/// and remains even after [`Clone`] and/or [`Borrow`] calls.
///
/// # Safety
/// Any [`PartialEq`], [`Eq`], [`PartialOrd`], and [`Ord`] impls must evaluate the same for `Self` and
/// its underlying entity.
/// `x.entity() == y.entity()` must be equivalent to `x == y`.
///
/// The above equivalence must also hold through and between calls to any [`Clone`] and
/// [`Borrow`]/[`BorrowMut`] impls in place of [`entity()`].
///
/// The result of [`entity()`] must be unaffected by any interior mutability.
///
/// The aforementioned properties imply determinism in both [`entity()`] calls
/// and comparison trait behavior.
///
/// All [`Hash`] impls except that for [`Entity`] must delegate to the [`Hash`] impl of
/// another [`EntityEquivalent`] type. All conversions to the delegatee within the [`Hash`] impl must
/// follow [`entity()`] equivalence.
///
/// It should be noted that [`Hash`] is *not* a comparison trait, and with [`Hash::hash`] being forcibly
/// generic over all [`Hasher`]s, **cannot** guarantee determinism or uniqueness of any final hash values
/// on its own.
/// To obtain hash values forming the same total order as [`Entity`], any [`Hasher`] used must be
/// deterministic and concerning [`Entity`], collisionless.
/// Standard library hash collections handle collisions with an [`Eq`] fallback, but do not account for
/// determinism when [`BuildHasher`] is unspecified,.
///
/// [`Hash`]: core::hash::Hash
/// [`Hasher`]: core::hash::Hasher
/// [`Borrow`]: core::borrow::Borrow
/// [`BorrowMut`]: core::borrow::BorrowMut
/// [`entity()`]: ContainsEntity::entity
pub unsafe trait EntityEquivalent: ContainsEntity + Eq {}
impl ContainsEntity for Entity {
fn entity(&self) -> Entity {
*self
}
}
// SAFETY:
// The trait implementations of Entity are correct and deterministic.
unsafe impl EntityEquivalent for Entity {}
impl<T: ContainsEntity> ContainsEntity for &T {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `&T` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone` and `Borrow` maintain equality.
// `&T` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for &T {}
impl<T: ContainsEntity> ContainsEntity for &mut T {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `&mut T` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Borrow` and `BorrowMut` maintain equality.
// `&mut T` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for &mut T {}
impl<T: ContainsEntity> ContainsEntity for Box<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `Box<T>` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone`, `Borrow` and `BorrowMut` maintain equality.
// `Box<T>` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for Box<T> {}
impl<T: ContainsEntity> ContainsEntity for Rc<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `Rc<T>` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone`, `Borrow` and `BorrowMut` maintain equality.
// `Rc<T>` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for Rc<T> {}
impl<T: ContainsEntity> ContainsEntity for Arc<T> {
fn entity(&self) -> Entity {
(**self).entity()
}
}
// SAFETY:
// `Arc<T>` delegates `PartialEq`, `Eq`, `PartialOrd`, `Ord`, and `Hash` to T.
// `Clone`, `Borrow` and `BorrowMut` maintain equality.
// `Arc<T>` is `Freeze`.
unsafe impl<T: EntityEquivalent> EntityEquivalent for Arc<T> {}
/// A set of unique entities.
///
/// Any element returned by [`Self::IntoIter`] will compare non-equal to every other element in the iterator.
/// As a consequence, [`into_iter()`] on `EntitySet` will always produce another `EntitySet`.
///
/// Implementing this trait allows for unique query iteration over a list of entities.
/// See [`iter_many_unique`] and [`iter_many_unique_mut`]
///
/// Note that there is no guarantee of the [`IntoIterator`] impl being deterministic,
/// it might return different iterators when called multiple times.
/// Neither is there a guarantee that the comparison trait impls of `EntitySet` match that
/// of the respective [`EntitySetIterator`] (or of a [`Vec`] collected from its elements)
///
/// [`Self::IntoIter`]: IntoIterator::IntoIter
/// [`into_iter()`]: IntoIterator::into_iter
/// [`iter_many_unique`]: crate::system::Query::iter_many_unique
/// [`iter_many_unique_mut`]: crate::system::Query::iter_many_unique_mut
/// [`Vec`]: alloc::vec::Vec
pub trait EntitySet: IntoIterator<IntoIter: EntitySetIterator> {}
impl<T: IntoIterator<IntoIter: EntitySetIterator>> EntitySet for T {}
/// An iterator over a set of unique entities.
///
/// Every `EntitySetIterator` is also [`EntitySet`].
///
/// # Safety
///
/// `x != y` must hold for any 2 elements returned by the iterator.
/// This is always true for iterators that cannot return more than one element.
pub unsafe trait EntitySetIterator: Iterator<Item: EntityEquivalent> {
/// Transforms an `EntitySetIterator` into a collection.
///
/// This is a specialized form of [`collect`], for collections which benefit from the uniqueness guarantee.
/// When present, this should always be preferred over [`collect`].
///
/// [`collect`]: Iterator::collect
// FIXME: When subtrait item shadowing stabilizes, this should be renamed and shadow `Iterator::collect`
fn collect_set<B: FromEntitySetIterator<Self::Item>>(self) -> B
where
Self: Sized,
{
FromEntitySetIterator::from_entity_set_iter(self)
}
}
// SAFETY:
// A correct `BTreeMap` contains only unique keys.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeMap`.
unsafe impl<K: EntityEquivalent, V> EntitySetIterator for btree_map::Keys<'_, K, V> {}
// SAFETY:
// A correct `BTreeMap` contains only unique keys.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeMap`.
unsafe impl<K: EntityEquivalent, V> EntitySetIterator for btree_map::IntoKeys<K, V> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The sub-range maintains uniqueness.
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::Range<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "intersection" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Intersection<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "union" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Union<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "difference" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::Difference<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
// The "symmetric difference" operation maintains uniqueness.
unsafe impl<T: EntityEquivalent + Ord> EntitySetIterator for btree_set::SymmetricDifference<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::Iter<'_, T> {}
// SAFETY:
// A correct `BTreeSet` contains only unique elements.
// EntityEquivalent guarantees a trustworthy Ord impl for T, and thus a correct `BTreeSet`.
unsafe impl<T: EntityEquivalent> EntitySetIterator for btree_set::IntoIter<T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for option::Iter<'_, T> {}
// SAFETY: This iterator only returns one element.
// unsafe impl<T: EntityEquivalent> EntitySetIterator for option::IterMut<'_, T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for option::IntoIter<T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for result::Iter<'_, T> {}
// SAFETY: This iterator only returns one element.
// unsafe impl<T: EntityEquivalent> EntitySetIterator for result::IterMut<'_, T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for result::IntoIter<T> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for array::IntoIter<T, 1> {}
// SAFETY: This iterator does not return any elements.
unsafe impl<T: EntityEquivalent> EntitySetIterator for array::IntoIter<T, 0> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent, F: FnOnce() -> T> EntitySetIterator for iter::OnceWith<F> {}
// SAFETY: This iterator only returns one element.
unsafe impl<T: EntityEquivalent> EntitySetIterator for iter::Once<T> {}
// SAFETY: This iterator does not return any elements.
unsafe impl<T: EntityEquivalent> EntitySetIterator for iter::Empty<T> {}
// SAFETY: Taking a mutable reference of an iterator has no effect on its elements.
unsafe impl<I: EntitySetIterator + ?Sized> EntitySetIterator for &mut I {}
// SAFETY: Boxing an iterator has no effect on its elements.
unsafe impl<I: EntitySetIterator + ?Sized> EntitySetIterator for Box<I> {}
// SAFETY: EntityEquivalent ensures that Copy does not affect equality, via its restrictions on Clone.
unsafe impl<'a, T: 'a + EntityEquivalent + Copy, I: EntitySetIterator<Item = &'a T>>
EntitySetIterator for iter::Copied<I>
{
}
// SAFETY: EntityEquivalent ensures that Clone does not affect equality.
unsafe impl<'a, T: 'a + EntityEquivalent + Clone, I: EntitySetIterator<Item = &'a T>>
EntitySetIterator for iter::Cloned<I>
{
}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::Filter<I, P>
{
}
// SAFETY: Yielding only `None` after yielding it once can only remove elements, which maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Fuse<I> {}
// SAFETY:
// Obtaining immutable references the elements of an iterator does not affect uniqueness.
// EntityEquivalent ensures the lack of interior mutability.
unsafe impl<I: EntitySetIterator, F: FnMut(&<I as Iterator>::Item)> EntitySetIterator
for iter::Inspect<I, F>
{
}
// SAFETY: Reversing an iterator does not affect uniqueness.
unsafe impl<I: DoubleEndedIterator + EntitySetIterator> EntitySetIterator for iter::Rev<I> {}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Skip<I> {}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::SkipWhile<I, P>
{
}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::Take<I> {}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator, P: FnMut(&<I as Iterator>::Item) -> bool> EntitySetIterator
for iter::TakeWhile<I, P>
{
}
// SAFETY: Discarding elements maintains uniqueness.
unsafe impl<I: EntitySetIterator> EntitySetIterator for iter::StepBy<I> {}
/// Conversion from an `EntitySetIterator`.
///
/// Some collections, while they can be constructed from plain iterators,
/// benefit strongly from the additional uniqueness guarantee [`EntitySetIterator`] offers.
/// Mirroring [`Iterator::collect`]/[`FromIterator::from_iter`], [`EntitySetIterator::collect_set`] and
/// `FromEntitySetIterator::from_entity_set_iter` can be used for construction.
///
/// See also: [`EntitySet`].
// FIXME: When subtrait item shadowing stabilizes, this should be renamed and shadow `FromIterator::from_iter`
pub trait FromEntitySetIterator<A: EntityEquivalent>: FromIterator<A> {
/// Creates a value from an [`EntitySetIterator`].
fn from_entity_set_iter<T: EntitySet<Item = A>>(set_iter: T) -> Self;
}
impl<T: EntityEquivalent + Hash, S: BuildHasher + Default> FromEntitySetIterator<T>
for HashSet<T, S>
{
fn from_entity_set_iter<I: EntitySet<Item = T>>(set_iter: I) -> Self {
let iter = set_iter.into_iter();
let set = HashSet::<T, S>::with_capacity_and_hasher(iter.size_hint().0, S::default());
iter.fold(set, |mut set, e| {
// SAFETY: Every element in self is unique.
unsafe {
set.insert_unique_unchecked(e);
}
set
})
}
}
/// An iterator that yields unique entities.
///
/// This wrapper can provide an [`EntitySetIterator`] implementation when an instance of `I` is known to uphold uniqueness.
pub struct UniqueEntityIter<I: Iterator<Item: EntityEquivalent>> {
iter: I,
}
impl<I: EntitySetIterator> UniqueEntityIter<I> {
/// Constructs a `UniqueEntityIter` from an [`EntitySetIterator`].
pub fn from_entity_set_iterator<S>(iter: I) -> Self {
Self { iter }
}
}
impl<I: Iterator<Item: EntityEquivalent>> UniqueEntityIter<I> {
/// Constructs a [`UniqueEntityIter`] from an iterator unsafely.
///
/// # Safety
/// `iter` must only yield unique elements.
/// As in, the resulting iterator must adhere to the safety contract of [`EntitySetIterator`].
pub unsafe fn from_iterator_unchecked(iter: I) -> Self {
Self { iter }
}
/// Returns the inner `I`.
pub fn into_inner(self) -> I {
self.iter
}
/// Returns a reference to the inner `I`.
pub fn as_inner(&self) -> &I {
&self.iter
}
/// Returns a mutable reference to the inner `I`.
///
/// # Safety
///
/// `self` must always contain an iterator that yields unique elements,
/// even while this reference is live.
pub unsafe fn as_mut_inner(&mut self) -> &mut I {
&mut self.iter
}
}
impl<I: Iterator<Item: EntityEquivalent>> Iterator for UniqueEntityIter<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I: ExactSizeIterator<Item: EntityEquivalent>> ExactSizeIterator for UniqueEntityIter<I> {}
impl<I: DoubleEndedIterator<Item: EntityEquivalent>> DoubleEndedIterator for UniqueEntityIter<I> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<I: FusedIterator<Item: EntityEquivalent>> FusedIterator for UniqueEntityIter<I> {}
// SAFETY: The underlying iterator is ensured to only return unique elements by its construction.
unsafe impl<I: Iterator<Item: EntityEquivalent>> EntitySetIterator for UniqueEntityIter<I> {}
impl<T, I: Iterator<Item: EntityEquivalent> + AsRef<[T]>> AsRef<[T]> for UniqueEntityIter<I> {
fn as_ref(&self) -> &[T] {
self.iter.as_ref()
}
}
impl<T: EntityEquivalent, I: Iterator<Item: EntityEquivalent> + AsRef<[T]>>
AsRef<UniqueEntityEquivalentSlice<T>> for UniqueEntityIter<I>
{
fn as_ref(&self) -> &UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.iter.as_ref()) }
}
}
impl<T: EntityEquivalent, I: Iterator<Item: EntityEquivalent> + AsMut<[T]>>
AsMut<UniqueEntityEquivalentSlice<T>> for UniqueEntityIter<I>
{
fn as_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.iter.as_mut()) }
}
}
// Default does not guarantee uniqueness, meaning `I` needs to be EntitySetIterator.
impl<I: EntitySetIterator + Default> Default for UniqueEntityIter<I> {
fn default() -> Self {
Self {
iter: Default::default(),
}
}
}
// Clone does not guarantee to maintain uniqueness, meaning `I` needs to be EntitySetIterator.
impl<I: EntitySetIterator + Clone> Clone for UniqueEntityIter<I> {
fn clone(&self) -> Self {
Self {
iter: self.iter.clone(),
}
}
}
impl<I: Iterator<Item: EntityEquivalent> + Debug> Debug for UniqueEntityIter<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("UniqueEntityIter")
.field("iter", &self.iter)
.finish()
}
}
#[cfg(test)]
mod tests {
use alloc::{vec, vec::Vec};
use crate::prelude::{Schedule, World};
use crate::component::Component;
use crate::entity::Entity;
use crate::query::{QueryState, With};
use crate::system::Query;
use crate::world::Mut;
use super::UniqueEntityIter;
#[derive(Component, Clone)]
pub struct Thing;
#[expect(
clippy::iter_skip_zero,
reason = "The `skip(0)` is used to ensure that the `Skip` iterator implements `EntitySet`, which is needed to pass the iterator as the `entities` parameter."
)]
#[test]
fn preserving_uniqueness() {
let mut world = World::new();
let mut query = QueryState::<&mut Thing>::new(&mut world);
let spawn_batch: Vec<Entity> = world.spawn_batch(vec![Thing; 1000]).collect();
// SAFETY: SpawnBatchIter is `EntitySetIterator`,
let mut unique_entity_iter =
unsafe { UniqueEntityIter::from_iterator_unchecked(spawn_batch.iter()) };
let entity_set = unique_entity_iter
.by_ref()
.filter(|_| true)
.fuse()
.inspect(|_| ())
.rev()
.skip(0)
.skip_while(|_| false)
.take(1000)
.take_while(|_| true)
.step_by(2)
.cloned();
// With `iter_many_mut` collecting is not possible, because you need to drop each `Mut`/`&mut` before the next is retrieved.
let _results: Vec<Mut<Thing>> =
query.iter_many_unique_mut(&mut world, entity_set).collect();
}
#[test]
fn nesting_queries() {
let mut world = World::new();
world.spawn_batch(vec![Thing; 1000]);
pub fn system(
mut thing_entities: Query<Entity, With<Thing>>,
mut things: Query<&mut Thing>,
) {
things.iter_many_unique(thing_entities.iter());
things.iter_many_unique_mut(thing_entities.iter_mut());
}
let mut schedule = Schedule::default();
schedule.add_systems(system);
schedule.run(&mut world);
}
}

77
vendor/bevy_ecs/src/entity/hash.rs vendored Normal file
View File

@@ -0,0 +1,77 @@
use core::hash::{BuildHasher, Hasher};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
/// A [`BuildHasher`] that results in a [`EntityHasher`].
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default, Clone))]
pub struct EntityHash;
impl BuildHasher for EntityHash {
type Hasher = EntityHasher;
fn build_hasher(&self) -> Self::Hasher {
Self::Hasher::default()
}
}
/// A very fast hash that is only designed to work on generational indices
/// like [`Entity`](super::Entity). It will panic if attempting to hash a type containing
/// non-u64 fields.
///
/// This is heavily optimized for typical cases, where you have mostly live
/// entities, and works particularly well for contiguous indices.
///
/// If you have an unusual case -- say all your indices are multiples of 256
/// or most of the entities are dead generations -- then you might want also to
/// try [`DefaultHasher`](bevy_platform::hash::DefaultHasher) for a slower hash
/// computation but fewer lookup conflicts.
#[derive(Debug, Default)]
pub struct EntityHasher {
hash: u64,
}
impl Hasher for EntityHasher {
#[inline]
fn finish(&self) -> u64 {
self.hash
}
fn write(&mut self, _bytes: &[u8]) {
panic!("EntityHasher can only hash u64 fields.");
}
#[inline]
fn write_u64(&mut self, bits: u64) {
// SwissTable (and thus `hashbrown`) cares about two things from the hash:
// - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item
// - H2: high 7 bits are used to SIMD optimize hash collision probing
// For more see <https://abseil.io/about/design/swisstables#metadata-layout>
// This hash function assumes that the entity ids are still well-distributed,
// so for H1 leaves the entity id alone in the low bits so that id locality
// will also give memory locality for things spawned together.
// For H2, take advantage of the fact that while multiplication doesn't
// spread entropy to the low bits, it's incredibly good at spreading it
// upward, which is exactly where we need it the most.
// While this does include the generation in the output, it doesn't do so
// *usefully*. H1 won't care until you have over 3 billion entities in
// the table, and H2 won't care until something hits generation 33 million.
// Thus the comment suggesting that this is best for live entities,
// where there won't be generation conflicts where it would matter.
// The high 32 bits of this are ⅟φ for Fibonacci hashing. That works
// particularly well for hashing for the same reason as described in
// <https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/>
// It loses no information because it has a modular inverse.
// (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.)
//
// The low 32 bits make that part of the just product a pass-through.
const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001;
// This is `(MAGIC * index + generation) << 32 + index`, in a single instruction.
self.hash = bits.wrapping_mul(UPPER_PHI);
}
}

272
vendor/bevy_ecs/src/entity/hash_map.rs vendored Normal file
View File

@@ -0,0 +1,272 @@
//! Contains the [`EntityHashMap`] type, a [`HashMap`] pre-configured to use [`EntityHash`] hashing.
//!
//! This module is a lightweight wrapper around Bevy's [`HashMap`] that is more performant for [`Entity`] keys.
use core::{
fmt::{self, Debug, Formatter},
iter::FusedIterator,
marker::PhantomData,
ops::{Deref, DerefMut, Index},
};
use bevy_platform::collections::hash_map::{self, HashMap};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use super::{Entity, EntityEquivalent, EntityHash, EntitySetIterator};
/// A [`HashMap`] pre-configured to use [`EntityHash`] hashing.
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EntityHashMap<V>(pub(crate) HashMap<Entity, V, EntityHash>);
impl<V> EntityHashMap<V> {
/// Creates an empty `EntityHashMap`.
///
/// Equivalent to [`HashMap::with_hasher(EntityHash)`].
///
/// [`HashMap::with_hasher(EntityHash)`]: HashMap::with_hasher
pub const fn new() -> Self {
Self(HashMap::with_hasher(EntityHash))
}
/// Creates an empty `EntityHashMap` with the specified capacity.
///
/// Equivalent to [`HashMap::with_capacity_and_hasher(n, EntityHash)`].
///
/// [`HashMap:with_capacity_and_hasher(n, EntityHash)`]: HashMap::with_capacity_and_hasher
pub fn with_capacity(n: usize) -> Self {
Self(HashMap::with_capacity_and_hasher(n, EntityHash))
}
/// Returns the inner [`HashMap`].
pub fn into_inner(self) -> HashMap<Entity, V, EntityHash> {
self.0
}
/// An iterator visiting all keys in arbitrary order.
/// The iterator element type is `&'a Entity`.
///
/// Equivalent to [`HashMap::keys`].
pub fn keys(&self) -> Keys<'_, V> {
Keys(self.0.keys(), PhantomData)
}
/// Creates a consuming iterator visiting all the keys in arbitrary order.
/// The map cannot be used after calling this.
/// The iterator element type is [`Entity`].
///
/// Equivalent to [`HashMap::into_keys`].
pub fn into_keys(self) -> IntoKeys<V> {
IntoKeys(self.0.into_keys(), PhantomData)
}
}
impl<V> Default for EntityHashMap<V> {
fn default() -> Self {
Self(Default::default())
}
}
impl<V> Deref for EntityHashMap<V> {
type Target = HashMap<Entity, V, EntityHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<V> DerefMut for EntityHashMap<V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a, V: Copy> Extend<&'a (Entity, V)> for EntityHashMap<V> {
fn extend<T: IntoIterator<Item = &'a (Entity, V)>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<'a, V: Copy> Extend<(&'a Entity, &'a V)> for EntityHashMap<V> {
fn extend<T: IntoIterator<Item = (&'a Entity, &'a V)>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<V> Extend<(Entity, V)> for EntityHashMap<V> {
fn extend<T: IntoIterator<Item = (Entity, V)>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<V, const N: usize> From<[(Entity, V); N]> for EntityHashMap<V> {
fn from(value: [(Entity, V); N]) -> Self {
Self(HashMap::from_iter(value))
}
}
impl<V> FromIterator<(Entity, V)> for EntityHashMap<V> {
fn from_iter<I: IntoIterator<Item = (Entity, V)>>(iterable: I) -> Self {
Self(HashMap::from_iter(iterable))
}
}
impl<V, Q: EntityEquivalent + ?Sized> Index<&Q> for EntityHashMap<V> {
type Output = V;
fn index(&self, key: &Q) -> &V {
self.0.index(&key.entity())
}
}
impl<'a, V> IntoIterator for &'a EntityHashMap<V> {
type Item = (&'a Entity, &'a V);
type IntoIter = hash_map::Iter<'a, Entity, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, V> IntoIterator for &'a mut EntityHashMap<V> {
type Item = (&'a Entity, &'a mut V);
type IntoIter = hash_map::IterMut<'a, Entity, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<V> IntoIterator for EntityHashMap<V> {
type Item = (Entity, V);
type IntoIter = hash_map::IntoIter<Entity, V>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
/// An iterator over the keys of a [`EntityHashMap`] in arbitrary order.
/// The iterator element type is `&'a Entity`.
///
/// This struct is created by the [`keys`] method on [`EntityHashMap`]. See its documentation for more.
///
/// [`keys`]: EntityHashMap::keys
pub struct Keys<'a, V, S = EntityHash>(hash_map::Keys<'a, Entity, V>, PhantomData<S>);
impl<'a, V> Keys<'a, V> {
/// Returns the inner [`Keys`](hash_map::Keys).
pub fn into_inner(self) -> hash_map::Keys<'a, Entity, V> {
self.0
}
}
impl<'a, V> Deref for Keys<'a, V> {
type Target = hash_map::Keys<'a, Entity, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, V> Iterator for Keys<'a, V> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<V> ExactSizeIterator for Keys<'_, V> {}
impl<V> FusedIterator for Keys<'_, V> {}
impl<V> Clone for Keys<'_, V> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl<V: Debug> Debug for Keys<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Keys").field(&self.0).field(&self.1).finish()
}
}
impl<V> Default for Keys<'_, V> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: Keys stems from a correctly behaving `HashMap<Entity, V, EntityHash>`.
unsafe impl<V> EntitySetIterator for Keys<'_, V> {}
/// An owning iterator over the keys of a [`EntityHashMap`] in arbitrary order.
/// The iterator element type is [`Entity`].
///
/// This struct is created by the [`into_keys`] method on [`EntityHashMap`].
/// See its documentation for more.
/// The map cannot be used after calling that method.
///
/// [`into_keys`]: EntityHashMap::into_keys
pub struct IntoKeys<V, S = EntityHash>(hash_map::IntoKeys<Entity, V>, PhantomData<S>);
impl<V> IntoKeys<V> {
/// Returns the inner [`IntoKeys`](hash_map::IntoKeys).
pub fn into_inner(self) -> hash_map::IntoKeys<Entity, V> {
self.0
}
}
impl<V> Deref for IntoKeys<V> {
type Target = hash_map::IntoKeys<Entity, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<V> Iterator for IntoKeys<V> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<V> ExactSizeIterator for IntoKeys<V> {}
impl<V> FusedIterator for IntoKeys<V> {}
impl<V: Debug> Debug for IntoKeys<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoKeys")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl<V> Default for IntoKeys<V> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: IntoKeys stems from a correctly behaving `HashMap<Entity, V, EntityHash>`.
unsafe impl<V> EntitySetIterator for IntoKeys<V> {}
#[cfg(test)]
mod tests {
use super::*;
use bevy_reflect::Reflect;
use static_assertions::assert_impl_all;
// Check that the HashMaps are Clone if the key/values are Clone
assert_impl_all!(EntityHashMap::<usize>: Clone);
// EntityHashMap should implement Reflect
#[cfg(feature = "bevy_reflect")]
assert_impl_all!(EntityHashMap::<i32>: Reflect);
}

420
vendor/bevy_ecs/src/entity/hash_set.rs vendored Normal file
View File

@@ -0,0 +1,420 @@
//! Contains the [`EntityHashSet`] type, a [`HashSet`] pre-configured to use [`EntityHash`] hashing.
//!
//! This module is a lightweight wrapper around Bevy's [`HashSet`] that is more performant for [`Entity`] keys.
use core::{
fmt::{self, Debug, Formatter},
iter::FusedIterator,
marker::PhantomData,
ops::{
BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Deref, DerefMut, Sub,
SubAssign,
},
};
use bevy_platform::collections::hash_set::{self, HashSet};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use super::{Entity, EntityHash, EntitySet, EntitySetIterator, FromEntitySetIterator};
/// A [`HashSet`] pre-configured to use [`EntityHash`] hashing.
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct EntityHashSet(pub(crate) HashSet<Entity, EntityHash>);
impl EntityHashSet {
/// Creates an empty `EntityHashSet`.
///
/// Equivalent to [`HashSet::with_hasher(EntityHash)`].
///
/// [`HashSet::with_hasher(EntityHash)`]: HashSet::with_hasher
pub const fn new() -> Self {
Self(HashSet::with_hasher(EntityHash))
}
/// Creates an empty `EntityHashSet` with the specified capacity.
///
/// Equivalent to [`HashSet::with_capacity_and_hasher(n, EntityHash)`].
///
/// [`HashSet::with_capacity_and_hasher(n, EntityHash)`]: HashSet::with_capacity_and_hasher
pub fn with_capacity(n: usize) -> Self {
Self(HashSet::with_capacity_and_hasher(n, EntityHash))
}
/// Returns the number of elements in the set.
pub fn len(&self) -> usize {
self.0.len()
}
/// Returns `true` if the set contains no elements.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Returns the inner [`HashSet`].
pub fn into_inner(self) -> HashSet<Entity, EntityHash> {
self.0
}
/// Clears the set, returning all elements in an iterator.
///
/// Equivalent to [`HashSet::drain`].
pub fn drain(&mut self) -> Drain<'_> {
Drain(self.0.drain(), PhantomData)
}
/// An iterator visiting all elements in arbitrary order.
/// The iterator element type is `&'a Entity`.
///
/// Equivalent to [`HashSet::iter`].
pub fn iter(&self) -> Iter<'_> {
Iter(self.0.iter(), PhantomData)
}
/// Drains elements which are true under the given predicate,
/// and returns an iterator over the removed items.
///
/// Equivalent to [`HashSet::extract_if`].
pub fn extract_if<F: FnMut(&Entity) -> bool>(&mut self, f: F) -> ExtractIf<'_, F> {
ExtractIf(self.0.extract_if(f), PhantomData)
}
}
impl Deref for EntityHashSet {
type Target = HashSet<Entity, EntityHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for EntityHashSet {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a> IntoIterator for &'a EntityHashSet {
type Item = &'a Entity;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter((&self.0).into_iter(), PhantomData)
}
}
impl IntoIterator for EntityHashSet {
type Item = Entity;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter(), PhantomData)
}
}
impl BitAnd for &EntityHashSet {
type Output = EntityHashSet;
fn bitand(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.bitand(&rhs.0))
}
}
impl BitAndAssign<&EntityHashSet> for EntityHashSet {
fn bitand_assign(&mut self, rhs: &Self) {
self.0.bitand_assign(&rhs.0);
}
}
impl BitOr for &EntityHashSet {
type Output = EntityHashSet;
fn bitor(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.bitor(&rhs.0))
}
}
impl BitOrAssign<&EntityHashSet> for EntityHashSet {
fn bitor_assign(&mut self, rhs: &Self) {
self.0.bitor_assign(&rhs.0);
}
}
impl BitXor for &EntityHashSet {
type Output = EntityHashSet;
fn bitxor(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.bitxor(&rhs.0))
}
}
impl BitXorAssign<&EntityHashSet> for EntityHashSet {
fn bitxor_assign(&mut self, rhs: &Self) {
self.0.bitxor_assign(&rhs.0);
}
}
impl Sub for &EntityHashSet {
type Output = EntityHashSet;
fn sub(self, rhs: Self) -> Self::Output {
EntityHashSet(self.0.sub(&rhs.0))
}
}
impl SubAssign<&EntityHashSet> for EntityHashSet {
fn sub_assign(&mut self, rhs: &Self) {
self.0.sub_assign(&rhs.0);
}
}
impl<'a> Extend<&'a Entity> for EntityHashSet {
fn extend<T: IntoIterator<Item = &'a Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl Extend<Entity> for EntityHashSet {
fn extend<T: IntoIterator<Item = Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<const N: usize> From<[Entity; N]> for EntityHashSet {
fn from(value: [Entity; N]) -> Self {
Self(HashSet::from_iter(value))
}
}
impl FromIterator<Entity> for EntityHashSet {
fn from_iter<I: IntoIterator<Item = Entity>>(iterable: I) -> Self {
Self(HashSet::from_iter(iterable))
}
}
impl FromEntitySetIterator<Entity> for EntityHashSet {
fn from_entity_set_iter<I: EntitySet<Item = Entity>>(set_iter: I) -> Self {
let iter = set_iter.into_iter();
let set = EntityHashSet::with_capacity(iter.size_hint().0);
iter.fold(set, |mut set, e| {
// SAFETY: Every element in self is unique.
unsafe {
set.insert_unique_unchecked(e);
}
set
})
}
}
/// An iterator over the items of an [`EntityHashSet`].
///
/// This struct is created by the [`iter`] method on [`EntityHashSet`]. See its documentation for more.
///
/// [`iter`]: EntityHashSet::iter
pub struct Iter<'a, S = EntityHash>(hash_set::Iter<'a, Entity>, PhantomData<S>);
impl<'a> Iter<'a> {
/// Returns the inner [`Iter`](hash_set::Iter).
pub fn into_inner(self) -> hash_set::Iter<'a, Entity> {
self.0
}
}
impl<'a> Deref for Iter<'a> {
type Target = hash_set::Iter<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl ExactSizeIterator for Iter<'_> {}
impl FusedIterator for Iter<'_> {}
impl Clone for Iter<'_> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl Debug for Iter<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Iter").field(&self.0).field(&self.1).finish()
}
}
impl Default for Iter<'_> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: Iter stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Iter<'_> {}
/// Owning iterator over the items of an [`EntityHashSet`].
///
/// This struct is created by the [`into_iter`] method on [`EntityHashSet`] (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: EntityHashSet::into_iter
pub struct IntoIter<S = EntityHash>(hash_set::IntoIter<Entity>, PhantomData<S>);
impl IntoIter {
/// Returns the inner [`IntoIter`](hash_set::IntoIter).
pub fn into_inner(self) -> hash_set::IntoIter<Entity> {
self.0
}
}
impl Deref for IntoIter {
type Target = hash_set::IntoIter<Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Iterator for IntoIter {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl ExactSizeIterator for IntoIter {}
impl FusedIterator for IntoIter {}
impl Debug for IntoIter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl Default for IntoIter {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: IntoIter stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for IntoIter {}
/// A draining iterator over the items of an [`EntityHashSet`].
///
/// This struct is created by the [`drain`] method on [`EntityHashSet`]. See its documentation for more.
///
/// [`drain`]: EntityHashSet::drain
pub struct Drain<'a, S = EntityHash>(hash_set::Drain<'a, Entity>, PhantomData<S>);
impl<'a> Drain<'a> {
/// Returns the inner [`Drain`](hash_set::Drain).
pub fn into_inner(self) -> hash_set::Drain<'a, Entity> {
self.0
}
}
impl<'a> Deref for Drain<'a> {
type Target = hash_set::Drain<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Drain<'a> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl ExactSizeIterator for Drain<'_> {}
impl FusedIterator for Drain<'_> {}
impl Debug for Drain<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain")
.field(&self.0)
.field(&self.1)
.finish()
}
}
// SAFETY: Drain stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Drain<'_> {}
/// A draining iterator over entries of a [`EntityHashSet`] which don't satisfy the predicate `f`.
///
/// This struct is created by the [`extract_if`] method on [`EntityHashSet`]. See its documentation for more.
///
/// [`extract_if`]: EntityHashSet::extract_if
pub struct ExtractIf<'a, F: FnMut(&Entity) -> bool, S = EntityHash>(
hash_set::ExtractIf<'a, Entity, F>,
PhantomData<S>,
);
impl<'a, F: FnMut(&Entity) -> bool> ExtractIf<'a, F> {
/// Returns the inner [`ExtractIf`](hash_set::ExtractIf).
pub fn into_inner(self) -> hash_set::ExtractIf<'a, Entity, F> {
self.0
}
}
impl<'a, F: FnMut(&Entity) -> bool> Deref for ExtractIf<'a, F> {
type Target = hash_set::ExtractIf<'a, Entity, F>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, F: FnMut(&Entity) -> bool> Iterator for ExtractIf<'a, F> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<F: FnMut(&Entity) -> bool> FusedIterator for ExtractIf<'_, F> {}
impl<F: FnMut(&Entity) -> bool> Debug for ExtractIf<'_, F> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("ExtractIf").finish()
}
}
// SAFETY: ExtractIf stems from a correctly behaving `HashSet<Entity, EntityHash>`.
unsafe impl<F: FnMut(&Entity) -> bool> EntitySetIterator for ExtractIf<'_, F> {}
// SAFETY: Difference stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::Difference<'_, Entity, EntityHash> {}
// SAFETY: Intersection stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::Intersection<'_, Entity, EntityHash> {}
// SAFETY: SymmetricDifference stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::SymmetricDifference<'_, Entity, EntityHash> {}
// SAFETY: Union stems from two correctly behaving `HashSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for hash_set::Union<'_, Entity, EntityHash> {}

1218
vendor/bevy_ecs/src/entity/index_map.rs vendored Normal file

File diff suppressed because it is too large Load Diff

766
vendor/bevy_ecs/src/entity/index_set.rs vendored Normal file
View File

@@ -0,0 +1,766 @@
//! Contains the [`EntityIndexSet`] type, a [`IndexSet`] pre-configured to use [`EntityHash`] hashing.
//!
//! This module is a lightweight wrapper around `indexmap`'ss [`IndexSet`] that is more performant for [`Entity`] keys.
use core::{
cmp::Ordering,
fmt::{self, Debug, Formatter},
hash::BuildHasher,
hash::{Hash, Hasher},
iter::FusedIterator,
marker::PhantomData,
ops::{
BitAnd, BitOr, BitXor, Bound, Deref, DerefMut, Index, Range, RangeBounds, RangeFrom,
RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Sub,
},
ptr,
};
use indexmap::set::{self, IndexSet};
use super::{Entity, EntityHash, EntitySetIterator};
use bevy_platform::prelude::Box;
/// An [`IndexSet`] pre-configured to use [`EntityHash`] hashing.
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Clone, Default)]
pub struct EntityIndexSet(pub(crate) IndexSet<Entity, EntityHash>);
impl EntityIndexSet {
/// Creates an empty `EntityIndexSet`.
///
/// Equivalent to [`IndexSet::with_hasher(EntityHash)`].
///
/// [`IndexSet::with_hasher(EntityHash)`]: IndexSet::with_hasher
pub const fn new() -> Self {
Self(IndexSet::with_hasher(EntityHash))
}
/// Creates an empty `EntityIndexSet` with the specified capacity.
///
/// Equivalent to [`IndexSet::with_capacity_and_hasher(n, EntityHash)`].
///
/// [`IndexSet::with_capacity_and_hasher(n, EntityHash)`]: IndexSet::with_capacity_and_hasher
pub fn with_capacity(n: usize) -> Self {
Self(IndexSet::with_capacity_and_hasher(n, EntityHash))
}
/// Returns the inner [`IndexSet`].
pub fn into_inner(self) -> IndexSet<Entity, EntityHash> {
self.0
}
/// Returns a slice of all the values in the set.
///
/// Equivalent to [`IndexSet::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
/// Clears the `IndexSet` in the given index range, returning those values
/// as a drain iterator.
///
/// Equivalent to [`IndexSet::drain`].
pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> Drain<'_> {
Drain(self.0.drain(range), PhantomData)
}
/// Returns a slice of values in the given range of indices.
///
/// Equivalent to [`IndexSet::get_range`].
pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Slice> {
self.0.get_range(range).map(|slice|
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(slice) })
}
/// Return an iterator over the values of the set, in their order.
///
/// Equivalent to [`IndexSet::iter`].
pub fn iter(&self) -> Iter<'_> {
Iter(self.0.iter(), PhantomData)
}
/// Converts into a boxed slice of all the values in the set.
///
/// Equivalent to [`IndexSet::into_boxed_slice`].
pub fn into_boxed_slice(self) -> Box<Slice> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Slice::from_boxed_slice_unchecked(self.0.into_boxed_slice()) }
}
}
impl Deref for EntityIndexSet {
type Target = IndexSet<Entity, EntityHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for EntityIndexSet {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a> IntoIterator for &'a EntityIndexSet {
type Item = &'a Entity;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter((&self.0).into_iter(), PhantomData)
}
}
impl IntoIterator for EntityIndexSet {
type Item = Entity;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter(), PhantomData)
}
}
impl BitAnd for &EntityIndexSet {
type Output = EntityIndexSet;
fn bitand(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.bitand(&rhs.0))
}
}
impl BitOr for &EntityIndexSet {
type Output = EntityIndexSet;
fn bitor(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.bitor(&rhs.0))
}
}
impl BitXor for &EntityIndexSet {
type Output = EntityIndexSet;
fn bitxor(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.bitxor(&rhs.0))
}
}
impl Sub for &EntityIndexSet {
type Output = EntityIndexSet;
fn sub(self, rhs: Self) -> Self::Output {
EntityIndexSet(self.0.sub(&rhs.0))
}
}
impl<'a> Extend<&'a Entity> for EntityIndexSet {
fn extend<T: IntoIterator<Item = &'a Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl Extend<Entity> for EntityIndexSet {
fn extend<T: IntoIterator<Item = Entity>>(&mut self, iter: T) {
self.0.extend(iter);
}
}
impl<const N: usize> From<[Entity; N]> for EntityIndexSet {
fn from(value: [Entity; N]) -> Self {
Self(IndexSet::from_iter(value))
}
}
impl FromIterator<Entity> for EntityIndexSet {
fn from_iter<I: IntoIterator<Item = Entity>>(iterable: I) -> Self {
Self(IndexSet::from_iter(iterable))
}
}
impl<S2> PartialEq<IndexSet<Entity, S2>> for EntityIndexSet
where
S2: BuildHasher,
{
fn eq(&self, other: &IndexSet<Entity, S2>) -> bool {
self.0.eq(other)
}
}
impl PartialEq for EntityIndexSet {
fn eq(&self, other: &EntityIndexSet) -> bool {
self.0.eq(other)
}
}
impl Eq for EntityIndexSet {}
impl Index<(Bound<usize>, Bound<usize>)> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<Range<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: Range<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeFrom<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeFrom<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeFull> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeFull) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeInclusive<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeInclusive<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeTo<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeTo<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<RangeToInclusive<usize>> for EntityIndexSet {
type Output = Slice;
fn index(&self, key: RangeToInclusive<usize>) -> &Self::Output {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.index(key)) }
}
}
impl Index<usize> for EntityIndexSet {
type Output = Entity;
fn index(&self, key: usize) -> &Entity {
self.0.index(key)
}
}
/// A dynamically-sized slice of values in an [`EntityIndexSet`].
///
/// Equivalent to an [`indexmap::set::Slice<V>`] whose source [`IndexSet`]
/// uses [`EntityHash`].
#[repr(transparent)]
pub struct Slice<S = EntityHash>(PhantomData<S>, set::Slice<Entity>);
impl Slice {
/// Returns an empty slice.
///
/// Equivalent to [`set::Slice::new`].
pub const fn new<'a>() -> &'a Self {
// SAFETY: The source slice is empty.
unsafe { Self::from_slice_unchecked(set::Slice::new()) }
}
/// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely.
///
/// # Safety
///
/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].
///
/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`
pub const unsafe fn from_slice_unchecked(slice: &set::Slice<Entity>) -> &Self {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { &*(ptr::from_ref(slice) as *const Self) }
}
/// Constructs a [`entity::index_set::Slice`] from a [`indexmap::set::Slice`] unsafely.
///
/// # Safety
///
/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].
///
/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`
pub const unsafe fn from_slice_unchecked_mut(slice: &mut set::Slice<Entity>) -> &mut Self {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { &mut *(ptr::from_mut(slice) as *mut Self) }
}
/// Casts `self` to the inner slice.
pub const fn as_inner(&self) -> &set::Slice<Entity> {
&self.1
}
/// Constructs a boxed [`entity::index_set::Slice`] from a boxed [`indexmap::set::Slice`] unsafely.
///
/// # Safety
///
/// `slice` must stem from an [`IndexSet`] using [`EntityHash`].
///
/// [`entity::index_set::Slice`]: `crate::entity::index_set::Slice`
pub unsafe fn from_boxed_slice_unchecked(slice: Box<set::Slice<Entity>>) -> Box<Self> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Box::from_raw(Box::into_raw(slice) as *mut Self) }
}
/// Casts a reference to `self` to the inner slice.
#[expect(
clippy::borrowed_box,
reason = "We wish to access the Box API of the inner type, without consuming it."
)]
pub fn as_boxed_inner(self: &Box<Self>) -> &Box<set::Slice<Entity>> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { &*(ptr::from_ref(self).cast::<Box<set::Slice<Entity>>>()) }
}
/// Casts `self` to the inner slice.
pub fn into_boxed_inner(self: Box<Self>) -> Box<set::Slice<Entity>> {
// SAFETY: Slice is a transparent wrapper around indexmap::set::Slice.
unsafe { Box::from_raw(Box::into_raw(self) as *mut set::Slice<Entity>) }
}
/// Returns a slice of values in the given range of indices.
///
/// Equivalent to [`set::Slice::get_range`].
pub fn get_range<R: RangeBounds<usize>>(&self, range: R) -> Option<&Self> {
self.1.get_range(range).map(|slice|
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(slice) })
}
/// Divides one slice into two at an index.
///
/// Equivalent to [`set::Slice::split_at`].
pub fn split_at(&self, index: usize) -> (&Self, &Self) {
let (slice_1, slice_2) = self.1.split_at(index);
// SAFETY: These are subslices of a valid slice.
unsafe {
(
Self::from_slice_unchecked(slice_1),
Self::from_slice_unchecked(slice_2),
)
}
}
/// Returns the first value and the rest of the slice,
/// or `None` if it is empty.
///
/// Equivalent to [`set::Slice::split_first`].
pub fn split_first(&self) -> Option<(&Entity, &Self)> {
self.1.split_first().map(|(first, rest)| {
(
first,
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(rest) },
)
})
}
/// Returns the last value and the rest of the slice,
/// or `None` if it is empty.
///
/// Equivalent to [`set::Slice::split_last`].
pub fn split_last(&self) -> Option<(&Entity, &Self)> {
self.1.split_last().map(|(last, rest)| {
(
last,
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(rest) },
)
})
}
/// Return an iterator over the values of the set slice.
///
/// Equivalent to [`set::Slice::iter`].
pub fn iter(&self) -> Iter<'_> {
Iter(self.1.iter(), PhantomData)
}
}
impl Deref for Slice {
type Target = set::Slice<Entity>;
fn deref(&self) -> &Self::Target {
&self.1
}
}
impl<'a> IntoIterator for &'a Slice {
type IntoIter = Iter<'a>;
type Item = &'a Entity;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl IntoIterator for Box<Slice> {
type IntoIter = IntoIter;
type Item = Entity;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.into_boxed_inner().into_iter(), PhantomData)
}
}
impl Clone for Box<Slice> {
fn clone(&self) -> Self {
// SAFETY: This is a clone of a valid slice.
unsafe { Slice::from_boxed_slice_unchecked(self.as_boxed_inner().clone()) }
}
}
impl Default for &Slice {
fn default() -> Self {
// SAFETY: The source slice is empty.
unsafe { Slice::from_slice_unchecked(<&set::Slice<Entity>>::default()) }
}
}
impl Default for Box<Slice> {
fn default() -> Self {
// SAFETY: The source slice is empty.
unsafe { Slice::from_boxed_slice_unchecked(<Box<set::Slice<Entity>>>::default()) }
}
}
impl<V: Debug> Debug for Slice<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Slice")
.field(&self.0)
.field(&&self.1)
.finish()
}
}
impl From<&Slice> for Box<Slice> {
fn from(value: &Slice) -> Self {
// SAFETY: This slice is a copy of a valid slice.
unsafe { Slice::from_boxed_slice_unchecked(value.1.into()) }
}
}
impl Hash for Slice {
fn hash<H: Hasher>(&self, state: &mut H) {
self.1.hash(state);
}
}
impl PartialOrd for Slice {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Slice {
fn cmp(&self, other: &Self) -> Ordering {
self.1.cmp(other)
}
}
impl PartialEq for Slice {
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl Eq for Slice {}
impl Index<(Bound<usize>, Bound<usize>)> for Slice {
type Output = Self;
fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<Range<usize>> for Slice {
type Output = Self;
fn index(&self, key: Range<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeFrom<usize>> for Slice {
type Output = Slice;
fn index(&self, key: RangeFrom<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeFull> for Slice {
type Output = Self;
fn index(&self, key: RangeFull) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeInclusive<usize>> for Slice {
type Output = Self;
fn index(&self, key: RangeInclusive<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeTo<usize>> for Slice {
type Output = Self;
fn index(&self, key: RangeTo<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<RangeToInclusive<usize>> for Slice {
type Output = Self;
fn index(&self, key: RangeToInclusive<usize>) -> &Self {
// SAFETY: This a subslice of a valid slice.
unsafe { Self::from_slice_unchecked(self.1.index(key)) }
}
}
impl Index<usize> for Slice {
type Output = Entity;
fn index(&self, key: usize) -> &Entity {
self.1.index(key)
}
}
/// An iterator over the items of an [`EntityIndexSet`].
///
/// This struct is created by the [`iter`] method on [`EntityIndexSet`]. See its documentation for more.
///
/// [`iter`]: EntityIndexSet::iter
pub struct Iter<'a, S = EntityHash>(set::Iter<'a, Entity>, PhantomData<S>);
impl<'a> Iter<'a> {
/// Returns the inner [`Iter`](set::Iter).
pub fn into_inner(self) -> set::Iter<'a, Entity> {
self.0
}
/// Returns a slice of the remaining entries in the iterator.
///
/// Equivalent to [`set::Iter::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
}
impl<'a> Deref for Iter<'a> {
type Target = set::Iter<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for Iter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for Iter<'_> {}
impl FusedIterator for Iter<'_> {}
impl Clone for Iter<'_> {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl Debug for Iter<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Iter").field(&self.0).field(&self.1).finish()
}
}
impl Default for Iter<'_> {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: Iter stems from a correctly behaving `IndexSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Iter<'_> {}
/// Owning iterator over the items of an [`EntityIndexSet`].
///
/// This struct is created by the [`into_iter`] method on [`EntityIndexSet`] (provided by the [`IntoIterator`] trait). See its documentation for more.
///
/// [`into_iter`]: EntityIndexSet::into_iter
pub struct IntoIter<S = EntityHash>(set::IntoIter<Entity>, PhantomData<S>);
impl IntoIter {
/// Returns the inner [`IntoIter`](set::IntoIter).
pub fn into_inner(self) -> set::IntoIter<Entity> {
self.0
}
/// Returns a slice of the remaining entries in the iterator.
///
/// Equivalent to [`set::IntoIter::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
}
impl Deref for IntoIter {
type Target = set::IntoIter<Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Iterator for IntoIter {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for IntoIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for IntoIter {}
impl FusedIterator for IntoIter {}
impl Clone for IntoIter {
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
impl Debug for IntoIter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl Default for IntoIter {
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
// SAFETY: IntoIter stems from a correctly behaving `IndexSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for IntoIter {}
/// A draining iterator over the items of an [`EntityIndexSet`].
///
/// This struct is created by the [`drain`] method on [`EntityIndexSet`]. See its documentation for more.
///
/// [`drain`]: EntityIndexSet::drain
pub struct Drain<'a, S = EntityHash>(set::Drain<'a, Entity>, PhantomData<S>);
impl<'a> Drain<'a> {
/// Returns the inner [`Drain`](set::Drain).
pub fn into_inner(self) -> set::Drain<'a, Entity> {
self.0
}
/// Returns a slice of the remaining entries in the iterator.$
///
/// Equivalent to [`set::Drain::as_slice`].
pub fn as_slice(&self) -> &Slice {
// SAFETY: The source IndexSet uses EntityHash.
unsafe { Slice::from_slice_unchecked(self.0.as_slice()) }
}
}
impl<'a> Deref for Drain<'a> {
type Target = set::Drain<'a, Entity>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Iterator for Drain<'a> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for Drain<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for Drain<'_> {}
impl FusedIterator for Drain<'_> {}
impl Debug for Drain<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain")
.field(&self.0)
.field(&self.1)
.finish()
}
}
// SAFETY: Drain stems from a correctly behaving `IndexSet<Entity, EntityHash>`.
unsafe impl EntitySetIterator for Drain<'_> {}
// SAFETY: Difference stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::Difference<'_, Entity, EntityHash> {}
// SAFETY: Intersection stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::Intersection<'_, Entity, EntityHash> {}
// SAFETY: SymmetricDifference stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::SymmetricDifference<'_, Entity, EntityHash, EntityHash> {}
// SAFETY: Union stems from two correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl EntitySetIterator for set::Union<'_, Entity, EntityHash> {}
// SAFETY: Splice stems from a correctly behaving `IndexSet<Entity, EntityHash>`s.
unsafe impl<I: Iterator<Item = Entity>> EntitySetIterator
for set::Splice<'_, I, Entity, EntityHash>
{
}

View File

@@ -0,0 +1,349 @@
pub use bevy_ecs_macros::MapEntities;
use crate::{
entity::{hash_map::EntityHashMap, Entity},
identifier::masks::{IdentifierMask, HIGH_MASK},
world::World,
};
use alloc::{collections::VecDeque, vec::Vec};
use bevy_platform::collections::HashSet;
use core::hash::BuildHasher;
use smallvec::SmallVec;
/// Operation to map all contained [`Entity`] fields in a type to new values.
///
/// As entity IDs are valid only for the [`World`] they're sourced from, using [`Entity`]
/// as references in components copied from another world will be invalid. This trait
/// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which
/// inject the entity mapping strategy between your `MapEntities` type and the current world
/// (usually by using an [`EntityHashMap<Entity>`] between source entities and entities in the
/// current world).
///
/// Components use [`Component::map_entities`](crate::component::Component::map_entities) to map
/// entities in the context of scenes and entity cloning, which generally uses [`MapEntities`] internally
/// to map each field (see those docs for usage).
///
/// [`HashSet<Entity>`]: bevy_platform::collections::HashSet
///
/// ## Example
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::entity::MapEntities;
///
/// #[derive(Component)]
/// struct Spring {
/// a: Entity,
/// b: Entity,
/// }
///
/// impl MapEntities for Spring {
/// fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
/// self.a = entity_mapper.get_mapped(self.a);
/// self.b = entity_mapper.get_mapped(self.b);
/// }
/// }
/// ```
pub trait MapEntities {
/// Updates all [`Entity`] references stored inside using `entity_mapper`.
///
/// Implementors should look up any and all [`Entity`] values stored within `self` and
/// update them to the mapped values via `entity_mapper`.
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E);
}
impl MapEntities for Entity {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = entity_mapper.get_mapped(*self);
}
}
impl MapEntities for Option<Entity> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
if let Some(entity) = self {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
impl<S: BuildHasher + Default> MapEntities for HashSet<Entity, S> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
*self = self.drain().map(|e| entity_mapper.get_mapped(e)).collect();
}
}
impl MapEntities for Vec<Entity> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entity in self.iter_mut() {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
impl MapEntities for VecDeque<Entity> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entity in self.iter_mut() {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
impl<A: smallvec::Array<Item = Entity>> MapEntities for SmallVec<A> {
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E) {
for entity in self.iter_mut() {
*entity = entity_mapper.get_mapped(*entity);
}
}
}
/// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`].
///
/// Usually this is done by using an [`EntityHashMap<Entity>`] to map source entities
/// (mapper inputs) to the current world's entities (mapper outputs).
///
/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
///
/// This is used by [`MapEntities`] implementors.
///
/// ## Example
///
/// ```
/// # use bevy_ecs::entity::{Entity, EntityMapper};
/// # use bevy_ecs::entity::EntityHashMap;
/// #
/// pub struct SimpleEntityMapper {
/// map: EntityHashMap<Entity>,
/// }
///
/// // Example implementation of EntityMapper where we map an entity to another entity if it exists
/// // in the underlying `EntityHashMap`, otherwise we just return the original entity.
/// impl EntityMapper for SimpleEntityMapper {
/// fn get_mapped(&mut self, entity: Entity) -> Entity {
/// self.map.get(&entity).copied().unwrap_or(entity)
/// }
///
/// fn set_mapped(&mut self, source: Entity, target: Entity) {
/// self.map.insert(source, target);
/// }
/// }
/// ```
pub trait EntityMapper {
/// Returns the "target" entity that maps to the given `source`.
fn get_mapped(&mut self, source: Entity) -> Entity;
/// Maps the `target` entity to the given `source`. For some implementations this might not actually determine the result
/// of [`EntityMapper::get_mapped`].
fn set_mapped(&mut self, source: Entity, target: Entity);
}
impl EntityMapper for () {
#[inline]
fn get_mapped(&mut self, source: Entity) -> Entity {
source
}
#[inline]
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
}
impl EntityMapper for (Entity, Entity) {
#[inline]
fn get_mapped(&mut self, source: Entity) -> Entity {
if source == self.0 {
self.1
} else {
source
}
}
fn set_mapped(&mut self, _source: Entity, _target: Entity) {}
}
impl EntityMapper for &mut dyn EntityMapper {
fn get_mapped(&mut self, source: Entity) -> Entity {
(*self).get_mapped(source)
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
(*self).set_mapped(source, target);
}
}
impl EntityMapper for SceneEntityMapper<'_> {
/// Returns the corresponding mapped entity or reserves a new dead entity ID in the current world if it is absent.
fn get_mapped(&mut self, source: Entity) -> Entity {
if let Some(&mapped) = self.map.get(&source) {
return mapped;
}
// this new entity reference is specifically designed to never represent any living entity
let new = Entity::from_raw_and_generation(
self.dead_start.index(),
IdentifierMask::inc_masked_high_by(self.dead_start.generation, self.generations),
);
// Prevent generations counter from being a greater value than HIGH_MASK.
self.generations = (self.generations + 1) & HIGH_MASK;
self.map.insert(source, new);
new
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
self.map.insert(source, target);
}
}
impl EntityMapper for EntityHashMap<Entity> {
/// Returns the corresponding mapped entity or returns `entity` if there is no mapped entity
fn get_mapped(&mut self, source: Entity) -> Entity {
self.get(&source).cloned().unwrap_or(source)
}
fn set_mapped(&mut self, source: Entity, target: Entity) {
self.insert(source, target);
}
}
/// A wrapper for [`EntityHashMap<Entity>`], augmenting it with the ability to allocate new [`Entity`] references in a destination
/// world. These newly allocated references are guaranteed to never point to any living entity in that world.
///
/// References are allocated by returning increasing generations starting from an internally initialized base
/// [`Entity`]. After it is finished being used, this entity is despawned and the requisite number of generations reserved.
pub struct SceneEntityMapper<'m> {
/// A mapping from one set of entities to another.
///
/// This is typically used to coordinate data transfer between sets of entities, such as between a scene and the world
/// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse
/// identifiers directly.
///
/// On its own, a [`EntityHashMap<Entity>`] is not capable of allocating new entity identifiers, which is needed to map references
/// to entities that lie outside the source entity set. This functionality can be accessed through [`SceneEntityMapper::world_scope()`].
map: &'m mut EntityHashMap<Entity>,
/// A base [`Entity`] used to allocate new references.
dead_start: Entity,
/// The number of generations this mapper has allocated thus far.
generations: u32,
}
impl<'m> SceneEntityMapper<'m> {
/// Gets a reference to the underlying [`EntityHashMap<Entity>`].
pub fn get_map(&'m self) -> &'m EntityHashMap<Entity> {
self.map
}
/// Gets a mutable reference to the underlying [`EntityHashMap<Entity>`].
pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap<Entity> {
self.map
}
/// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
pub fn new(map: &'m mut EntityHashMap<Entity>, world: &mut World) -> Self {
// We're going to be calling methods on `Entities` that require advance
// flushing, such as `alloc` and `free`.
world.flush_entities();
Self {
map,
// SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
dead_start: unsafe { world.entities_mut().alloc() },
generations: 0,
}
}
/// Reserves the allocated references to dead entities within the world. This frees the temporary base
/// [`Entity`] while reserving extra generations. Because this makes the [`SceneEntityMapper`] unable to
/// safely allocate any more references, this method takes ownership of `self` in order to render it unusable.
pub fn finish(self, world: &mut World) {
// SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope`
let entities = unsafe { world.entities_mut() };
assert!(entities.free(self.dead_start).is_some());
assert!(entities.reserve_generations(self.dead_start.index(), self.generations));
}
/// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
/// provided function with it. This allows one to allocate new entity references in this [`World`] that are
/// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely
/// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called
/// within the scope of this world. Its return value is then returned from `world_scope` as the generic type
/// parameter `R`.
pub fn world_scope<R>(
entity_map: &'m mut EntityHashMap<Entity>,
world: &mut World,
f: impl FnOnce(&mut World, &mut Self) -> R,
) -> R {
let mut mapper = Self::new(entity_map, world);
let result = f(world, &mut mapper);
mapper.finish(world);
result
}
}
#[cfg(test)]
mod tests {
use crate::{
entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper},
world::World,
};
#[test]
fn entity_mapper() {
const FIRST_IDX: u32 = 1;
const SECOND_IDX: u32 = 2;
let mut map = EntityHashMap::default();
let mut world = World::new();
let mut mapper = SceneEntityMapper::new(&mut map, &mut world);
let mapped_ent = Entity::from_raw(FIRST_IDX);
let dead_ref = mapper.get_mapped(mapped_ent);
assert_eq!(
dead_ref,
mapper.get_mapped(mapped_ent),
"should persist the allocated mapping from the previous line"
);
assert_eq!(
mapper.get_mapped(Entity::from_raw(SECOND_IDX)).index(),
dead_ref.index(),
"should re-use the same index for further dead refs"
);
mapper.finish(&mut world);
// Next allocated entity should be a further generation on the same index
let entity = world.spawn_empty().id();
assert_eq!(entity.index(), dead_ref.index());
assert!(entity.generation() > dead_ref.generation());
}
#[test]
fn world_scope_reserves_generations() {
let mut map = EntityHashMap::default();
let mut world = World::new();
let dead_ref = SceneEntityMapper::world_scope(&mut map, &mut world, |_, mapper| {
mapper.get_mapped(Entity::from_raw(0))
});
// Next allocated entity should be a further generation on the same index
let entity = world.spawn_empty().id();
assert_eq!(entity.index(), dead_ref.index());
assert!(entity.generation() > dead_ref.generation());
}
#[test]
fn entity_mapper_no_panic() {
let mut world = World::new();
// "Dirty" the `Entities`, requiring a flush afterward.
world.entities.reserve_entity();
assert!(world.entities.needs_flush());
// Create and exercise a SceneEntityMapper - should not panic because it flushes
// `Entities` first.
SceneEntityMapper::world_scope(&mut Default::default(), &mut world, |_, m| {
m.get_mapped(Entity::PLACEHOLDER);
});
// The SceneEntityMapper should leave `Entities` in a flushed state.
assert!(!world.entities.needs_flush());
}
}

1377
vendor/bevy_ecs/src/entity/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,587 @@
//! A wrapper around entity arrays with a uniqueness invariant.
use core::{
array,
borrow::{Borrow, BorrowMut},
fmt::Debug,
ops::{
Bound, Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
RangeTo, RangeToInclusive,
},
ptr,
};
use alloc::{
boxed::Box,
collections::{BTreeSet, BinaryHeap, LinkedList, VecDeque},
rc::Rc,
vec::Vec,
};
use bevy_platform::sync::Arc;
use super::{
unique_slice::{self, UniqueEntityEquivalentSlice},
Entity, EntityEquivalent, UniqueEntityIter,
};
/// An array that contains only unique entities.
///
/// It can be obtained through certain methods on [`UniqueEntityEquivalentSlice`],
/// and some [`TryFrom`] implementations.
///
/// When `T` is [`Entity`], use [`UniqueEntityArray`].
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct UniqueEntityEquivalentArray<T: EntityEquivalent, const N: usize>([T; N]);
/// An array that contains only unique [`Entity`].
///
/// This is the default case of a [`UniqueEntityEquivalentArray`].
pub type UniqueEntityArray<const N: usize> = UniqueEntityEquivalentArray<Entity, N>;
impl<T: EntityEquivalent, const N: usize> UniqueEntityEquivalentArray<T, N> {
/// Constructs a `UniqueEntityEquivalentArray` from a [`[T; N]`] unsafely.
///
/// # Safety
///
/// `array` must contain only unique elements.
pub const unsafe fn from_array_unchecked(array: [T; N]) -> Self {
Self(array)
}
/// Constructs a `&UniqueEntityEquivalentArray` from a [`&[T; N]`] unsafely.
///
/// # Safety
///
/// `array` must contain only unique elements.
pub const unsafe fn from_array_ref_unchecked(array: &[T; N]) -> &Self {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { &*(ptr::from_ref(array).cast()) }
}
/// Constructs a `Box<UniqueEntityEquivalentArray>` from a [`Box<[T; N]>`] unsafely.
///
/// # Safety
///
/// `array` must contain only unique elements.
pub unsafe fn from_boxed_array_unchecked(array: Box<[T; N]>) -> Box<Self> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Box::from_raw(Box::into_raw(array).cast()) }
}
/// Casts `self` into the inner array.
pub fn into_boxed_inner(self: Box<Self>) -> Box<[T; N]> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Box::from_raw(Box::into_raw(self).cast()) }
}
/// Constructs a `Arc<UniqueEntityEquivalentArray>` from a [`Arc<[T; N]>`] unsafely.
///
/// # Safety
///
/// `slice` must contain only unique elements.
pub unsafe fn from_arc_array_unchecked(slice: Arc<[T; N]>) -> Arc<Self> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Arc::from_raw(Arc::into_raw(slice).cast()) }
}
/// Casts `self` to the inner array.
pub fn into_arc_inner(this: Arc<Self>) -> Arc<[T; N]> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Arc::from_raw(Arc::into_raw(this).cast()) }
}
// Constructs a `Rc<UniqueEntityEquivalentArray>` from a [`Rc<[T; N]>`] unsafely.
///
/// # Safety
///
/// `slice` must contain only unique elements.
pub unsafe fn from_rc_array_unchecked(slice: Rc<[T; N]>) -> Rc<Self> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Rc::from_raw(Rc::into_raw(slice).cast()) }
}
/// Casts `self` to the inner array.
pub fn into_rc_inner(self: Rc<Self>) -> Rc<[T; N]> {
// SAFETY: UniqueEntityEquivalentArray is a transparent wrapper around [T; N].
unsafe { Rc::from_raw(Rc::into_raw(self).cast()) }
}
/// Return the inner array.
pub fn into_inner(self) -> [T; N] {
self.0
}
/// Returns a reference to the inner array.
pub fn as_inner(&self) -> &[T; N] {
&self.0
}
/// Returns a slice containing the entire array. Equivalent to `&s[..]`.
pub const fn as_slice(&self) -> &UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.as_slice()) }
}
/// Returns a mutable slice containing the entire array. Equivalent to
/// `&mut s[..]`.
pub fn as_mut_slice(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.as_mut_slice()) }
}
/// Borrows each element and returns an array of references with the same
/// size as `self`.
///
/// Equivalent to [`[T; N]::as_ref`](array::each_ref).
pub fn each_ref(&self) -> UniqueEntityEquivalentArray<&T, N> {
UniqueEntityEquivalentArray(self.0.each_ref())
}
}
impl<T: EntityEquivalent, const N: usize> Deref for UniqueEntityEquivalentArray<T, N> {
type Target = UniqueEntityEquivalentSlice<T>;
fn deref(&self) -> &Self::Target {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(&self.0) }
}
}
impl<T: EntityEquivalent, const N: usize> DerefMut for UniqueEntityEquivalentArray<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(&mut self.0) }
}
}
impl<T: EntityEquivalent> Default for UniqueEntityEquivalentArray<T, 0> {
fn default() -> Self {
Self(Default::default())
}
}
impl<'a, T: EntityEquivalent, const N: usize> IntoIterator
for &'a UniqueEntityEquivalentArray<T, N>
{
type Item = &'a T;
type IntoIter = unique_slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityIter::from_iterator_unchecked(self.0.iter()) }
}
}
impl<T: EntityEquivalent, const N: usize> IntoIterator for UniqueEntityEquivalentArray<T, N> {
type Item = T;
type IntoIter = IntoIter<N, T>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: All elements in the original array are unique.
unsafe { UniqueEntityIter::from_iterator_unchecked(self.0.into_iter()) }
}
}
impl<T: EntityEquivalent, const N: usize> AsRef<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn as_ref(&self) -> &UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> AsMut<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn as_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> Borrow<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn borrow(&self) -> &UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> BorrowMut<UniqueEntityEquivalentSlice<T>>
for UniqueEntityEquivalentArray<T, N>
{
fn borrow_mut(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
self
}
}
impl<T: EntityEquivalent, const N: usize> Index<(Bound<usize>, Bound<usize>)>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: (Bound<usize>, Bound<usize>)) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<Range<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: Range<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeFrom<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeFrom<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeFull> for UniqueEntityEquivalentArray<T, N> {
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeFull) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeInclusive<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeTo<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeTo<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<RangeToInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
type Output = UniqueEntityEquivalentSlice<T>;
fn index(&self, key: RangeToInclusive<usize>) -> &Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.0.index(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> Index<usize> for UniqueEntityEquivalentArray<T, N> {
type Output = T;
fn index(&self, key: usize) -> &T {
self.0.index(key)
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<(Bound<usize>, Bound<usize>)>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: (Bound<usize>, Bound<usize>)) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<Range<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: Range<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeFrom<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeFrom<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeFull>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeFull) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeInclusive<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeTo<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeTo<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent, const N: usize> IndexMut<RangeToInclusive<usize>>
for UniqueEntityEquivalentArray<T, N>
{
fn index_mut(&mut self, key: RangeToInclusive<usize>) -> &mut Self::Output {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked_mut(self.0.index_mut(key)) }
}
}
impl<T: EntityEquivalent + Clone> From<&[T; 1]> for UniqueEntityEquivalentArray<T, 1> {
fn from(value: &[T; 1]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent + Clone> From<&[T; 0]> for UniqueEntityEquivalentArray<T, 0> {
fn from(value: &[T; 0]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent + Clone> From<&mut [T; 1]> for UniqueEntityEquivalentArray<T, 1> {
fn from(value: &mut [T; 1]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent + Clone> From<&mut [T; 0]> for UniqueEntityEquivalentArray<T, 0> {
fn from(value: &mut [T; 0]) -> Self {
Self(value.clone())
}
}
impl<T: EntityEquivalent> From<[T; 1]> for UniqueEntityEquivalentArray<T, 1> {
fn from(value: [T; 1]) -> Self {
Self(value)
}
}
impl<T: EntityEquivalent> From<[T; 0]> for UniqueEntityEquivalentArray<T, 0> {
fn from(value: [T; 0]) -> Self {
Self(value)
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 1>> for (T,) {
fn from(array: UniqueEntityEquivalentArray<T, 1>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 2>> for (T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 2>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 3>> for (T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 3>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 4>> for (T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 4>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 5>> for (T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 5>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 6>> for (T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 6>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 7>> for (T, T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 7>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 8>> for (T, T, T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 8>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 9>> for (T, T, T, T, T, T, T, T, T) {
fn from(array: UniqueEntityEquivalentArray<T, 9>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 10>>
for (T, T, T, T, T, T, T, T, T, T)
{
fn from(array: UniqueEntityEquivalentArray<T, 10>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 11>>
for (T, T, T, T, T, T, T, T, T, T, T)
{
fn from(array: UniqueEntityEquivalentArray<T, 11>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent> From<UniqueEntityEquivalentArray<T, 12>>
for (T, T, T, T, T, T, T, T, T, T, T, T)
{
fn from(array: UniqueEntityEquivalentArray<T, 12>) -> Self {
Self::from(array.into_inner())
}
}
impl<T: EntityEquivalent + Ord, const N: usize> From<UniqueEntityEquivalentArray<T, N>>
for BTreeSet<T>
{
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
BTreeSet::from(value.0)
}
}
impl<T: EntityEquivalent + Ord, const N: usize> From<UniqueEntityEquivalentArray<T, N>>
for BinaryHeap<T>
{
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
BinaryHeap::from(value.0)
}
}
impl<T: EntityEquivalent, const N: usize> From<UniqueEntityEquivalentArray<T, N>>
for LinkedList<T>
{
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
LinkedList::from(value.0)
}
}
impl<T: EntityEquivalent, const N: usize> From<UniqueEntityEquivalentArray<T, N>> for Vec<T> {
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
Vec::from(value.0)
}
}
impl<T: EntityEquivalent, const N: usize> From<UniqueEntityEquivalentArray<T, N>> for VecDeque<T> {
fn from(value: UniqueEntityEquivalentArray<T, N>) -> Self {
VecDeque::from(value.0)
}
}
impl<T: EntityEquivalent + PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&UniqueEntityEquivalentSlice<U>> for UniqueEntityEquivalentArray<T, N>
{
fn eq(&self, other: &&UniqueEntityEquivalentSlice<U>) -> bool {
self.0.eq(&other.as_inner())
}
}
impl<T: EntityEquivalent + PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<UniqueEntityEquivalentSlice<U>> for UniqueEntityEquivalentArray<T, N>
{
fn eq(&self, other: &UniqueEntityEquivalentSlice<U>) -> bool {
self.0.eq(other.as_inner())
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&UniqueEntityEquivalentArray<U, N>> for Vec<T>
{
fn eq(&self, other: &&UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&UniqueEntityEquivalentArray<U, N>> for VecDeque<T>
{
fn eq(&self, other: &&UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<&mut UniqueEntityEquivalentArray<U, N>> for VecDeque<T>
{
fn eq(&self, other: &&mut UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<UniqueEntityEquivalentArray<U, N>> for Vec<T>
{
fn eq(&self, other: &UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
impl<T: PartialEq<U>, U: EntityEquivalent, const N: usize>
PartialEq<UniqueEntityEquivalentArray<U, N>> for VecDeque<T>
{
fn eq(&self, other: &UniqueEntityEquivalentArray<U, N>) -> bool {
self.eq(&other.0)
}
}
/// A by-value array iterator.
///
/// Equivalent to [`array::IntoIter`].
pub type IntoIter<const N: usize, T = Entity> = UniqueEntityIter<array::IntoIter<T, N>>;
impl<T: EntityEquivalent, const N: usize> UniqueEntityIter<array::IntoIter<T, N>> {
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
///
/// Equivalent to [`array::IntoIter::as_slice`].
pub fn as_slice(&self) -> &UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe { UniqueEntityEquivalentSlice::from_slice_unchecked(self.as_inner().as_slice()) }
}
/// Returns a mutable slice of all elements that have not been yielded yet.
///
/// Equivalent to [`array::IntoIter::as_mut_slice`].
pub fn as_mut_slice(&mut self) -> &mut UniqueEntityEquivalentSlice<T> {
// SAFETY: All elements in the original slice are unique.
unsafe {
UniqueEntityEquivalentSlice::from_slice_unchecked_mut(
self.as_mut_inner().as_mut_slice(),
)
}
}
}

1895
vendor/bevy_ecs/src/entity/unique_slice.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1114
vendor/bevy_ecs/src/entity/unique_vec.rs vendored Normal file

File diff suppressed because it is too large Load Diff

307
vendor/bevy_ecs/src/entity_disabling.rs vendored Normal file
View File

@@ -0,0 +1,307 @@
//! Disabled entities do not show up in queries unless the query explicitly mentions them.
//!
//! Entities which are disabled in this way are not removed from the [`World`],
//! and their relationships remain intact.
//! In many cases, you may want to disable entire trees of entities at once,
//! using [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive).
//!
//! While Bevy ships with a built-in [`Disabled`] component, you can also create your own
//! disabling components, which will operate in the same way but can have distinct semantics.
//!
//! ```
//! use bevy_ecs::prelude::*;
//!
//! // Our custom disabling component!
//! #[derive(Component, Clone)]
//! struct Prefab;
//!
//! #[derive(Component)]
//! struct A;
//!
//! let mut world = World::new();
//! world.register_disabling_component::<Prefab>();
//! world.spawn((A, Prefab));
//! world.spawn((A,));
//! world.spawn((A,));
//!
//! let mut normal_query = world.query::<&A>();
//! assert_eq!(2, normal_query.iter(&world).count());
//!
//! let mut prefab_query = world.query_filtered::<&A, With<Prefab>>();
//! assert_eq!(1, prefab_query.iter(&world).count());
//!
//! let mut maybe_prefab_query = world.query::<(&A, Has<Prefab>)>();
//! assert_eq!(3, maybe_prefab_query.iter(&world).count());
//! ```
//!
//! ## Default query filters
//!
//! In Bevy, entity disabling is implemented through the construction of a global "default query filter".
//! Queries which do not explicitly mention the disabled component will not include entities with that component.
//! If an entity has multiple disabling components, it will only be included in queries that mention all of them.
//!
//! For example, `Query<&Position>` will not include entities with the [`Disabled`] component,
//! even if they have a `Position` component,
//! but `Query<&Position, With<Disabled>>` or `Query<(&Position, Has<Disabled>)>` will see them.
//!
//! Entities with disabling components are still present in the [`World`] and can be accessed directly,
//! using methods on [`World`] or [`Commands`](crate::prelude::Commands).
//!
//! ### Warnings
//!
//! Currently, only queries for which the cache is built after enabling a default query filter will have entities
//! with those components filtered. As a result, they should generally only be modified before the
//! app starts.
//!
//! Because filters are applied to all queries they can have performance implication for
//! the enire [`World`], especially when they cause queries to mix sparse and table components.
//! See [`Query` performance] for more info.
//!
//! Custom disabling components can cause significant interoperability issues within the ecosystem,
//! as users must be aware of each disabling component in use.
//! Libraries should think carefully about whether they need to use a new disabling component,
//! and clearly communicate their presence to their users to avoid the new for library compatibility flags.
//!
//! [`With`]: crate::prelude::With
//! [`Has`]: crate::prelude::Has
//! [`World`]: crate::prelude::World
//! [`Query` performance]: crate::prelude::Query#performance
use crate::{
component::{ComponentId, Components, StorageType},
query::FilteredAccess,
world::{FromWorld, World},
};
use bevy_ecs_macros::{Component, Resource};
use smallvec::SmallVec;
#[cfg(feature = "bevy_reflect")]
use {
crate::reflect::ReflectComponent, bevy_reflect::std_traits::ReflectDefault,
bevy_reflect::Reflect,
};
/// A marker component for disabled entities.
///
/// Semantically, this component is used to mark entities that are temporarily disabled (typically for gameplay reasons),
/// but will likely be re-enabled at some point.
///
/// Like all disabling components, this only disables the entity itself,
/// not its children or other entities that reference it.
/// To disable an entire tree of entities, use [`EntityCommands::insert_recursive`](crate::prelude::EntityCommands::insert_recursive).
///
/// Every [`World`] has a default query filter that excludes entities with this component,
/// registered in the [`DefaultQueryFilters`] resource.
/// See [the module docs] for more info.
///
/// [the module docs]: crate::entity_disabling
#[derive(Component, Clone, Debug, Default)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Component),
reflect(Debug, Clone, Default)
)]
// This component is registered as a disabling component during World::bootstrap
pub struct Disabled;
/// Default query filters work by excluding entities with certain components from most queries.
///
/// If a query does not explicitly mention a given disabling component, it will not include entities with that component.
/// To be more precise, this checks if the query's [`FilteredAccess`] contains the component,
/// and if it does not, adds a [`Without`](crate::prelude::Without) filter for that component to the query.
///
/// This resource is initialized in the [`World`] whenever a new world is created,
/// with the [`Disabled`] component as a disabling component.
///
/// Note that you can remove default query filters by overwriting the [`DefaultQueryFilters`] resource.
/// This can be useful as a last resort escape hatch, but is liable to break compatibility with other libraries.
///
/// See the [module docs](crate::entity_disabling) for more info.
///
///
/// # Warning
///
/// Default query filters are a global setting that affects all queries in the [`World`],
/// and incur a small performance cost for each query.
///
/// They can cause significant interoperability issues within the ecosystem,
/// as users must be aware of each disabling component in use.
///
/// Think carefully about whether you need to use a new disabling component,
/// and clearly communicate their presence in any libraries you publish.
#[derive(Resource, Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct DefaultQueryFilters {
// We only expect a few components per application to act as disabling components, so we use a SmallVec here
// to avoid heap allocation in most cases.
disabling: SmallVec<[ComponentId; 4]>,
}
impl FromWorld for DefaultQueryFilters {
fn from_world(world: &mut World) -> Self {
let mut filters = DefaultQueryFilters::empty();
let disabled_component_id = world.register_component::<Disabled>();
filters.register_disabling_component(disabled_component_id);
filters
}
}
impl DefaultQueryFilters {
/// Creates a new, completely empty [`DefaultQueryFilters`].
///
/// This is provided as an escape hatch; in most cases you should initialize this using [`FromWorld`],
/// which is automatically called when creating a new [`World`].
#[must_use]
pub fn empty() -> Self {
DefaultQueryFilters {
disabling: SmallVec::new(),
}
}
/// Adds this [`ComponentId`] to the set of [`DefaultQueryFilters`],
/// causing entities with this component to be excluded from queries.
///
/// This method is idempotent, and will not add the same component multiple times.
///
/// # Warning
///
/// This method should only be called before the app starts, as it will not affect queries
/// initialized before it is called.
///
/// As discussed in the [module docs](crate::entity_disabling), this can have performance implications,
/// as well as create interoperability issues, and should be used with caution.
pub fn register_disabling_component(&mut self, component_id: ComponentId) {
if !self.disabling.contains(&component_id) {
self.disabling.push(component_id);
}
}
/// Get an iterator over all of the components which disable entities when present.
pub fn disabling_ids(&self) -> impl Iterator<Item = ComponentId> + use<'_> {
self.disabling.iter().copied()
}
/// Modifies the provided [`FilteredAccess`] to include the filters from this [`DefaultQueryFilters`].
pub(super) fn modify_access(&self, component_access: &mut FilteredAccess<ComponentId>) {
for component_id in self.disabling_ids() {
if !component_access.contains(component_id) {
component_access.and_without(component_id);
}
}
}
pub(super) fn is_dense(&self, components: &Components) -> bool {
self.disabling_ids().all(|component_id| {
components
.get_info(component_id)
.is_some_and(|info| info.storage_type() == StorageType::Table)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
prelude::World,
query::{Has, With},
};
use alloc::{vec, vec::Vec};
#[test]
fn filters_modify_access() {
let mut filters = DefaultQueryFilters::empty();
filters.register_disabling_component(ComponentId::new(1));
// A component access with an unrelated component
let mut component_access = FilteredAccess::<ComponentId>::default();
component_access
.access_mut()
.add_component_read(ComponentId::new(2));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(0, applied_access.with_filters().count());
assert_eq!(
vec![ComponentId::new(1)],
applied_access.without_filters().collect::<Vec<_>>()
);
// We add a with filter, now we expect to see both filters
component_access.and_with(ComponentId::new(4));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(
vec![ComponentId::new(4)],
applied_access.with_filters().collect::<Vec<_>>()
);
assert_eq!(
vec![ComponentId::new(1)],
applied_access.without_filters().collect::<Vec<_>>()
);
let copy = component_access.clone();
// We add a rule targeting a default component, that filter should no longer be added
component_access.and_with(ComponentId::new(1));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(
vec![ComponentId::new(1), ComponentId::new(4)],
applied_access.with_filters().collect::<Vec<_>>()
);
assert_eq!(0, applied_access.without_filters().count());
// Archetypal access should also filter rules
component_access = copy.clone();
component_access
.access_mut()
.add_archetypal(ComponentId::new(1));
let mut applied_access = component_access.clone();
filters.modify_access(&mut applied_access);
assert_eq!(
vec![ComponentId::new(4)],
applied_access.with_filters().collect::<Vec<_>>()
);
assert_eq!(0, applied_access.without_filters().count());
}
#[derive(Component)]
struct CustomDisabled;
#[test]
fn multiple_disabling_components() {
let mut world = World::new();
world.register_disabling_component::<CustomDisabled>();
world.spawn_empty();
world.spawn(Disabled);
world.spawn(CustomDisabled);
world.spawn((Disabled, CustomDisabled));
let mut query = world.query::<()>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query_filtered::<(), With<Disabled>>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query::<Has<Disabled>>();
assert_eq!(2, query.iter(&world).count());
let mut query = world.query_filtered::<(), With<CustomDisabled>>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query::<Has<CustomDisabled>>();
assert_eq!(2, query.iter(&world).count());
let mut query = world.query_filtered::<(), (With<Disabled>, With<CustomDisabled>)>();
assert_eq!(1, query.iter(&world).count());
let mut query = world.query::<(Has<Disabled>, Has<CustomDisabled>)>();
assert_eq!(4, query.iter(&world).count());
}
}

249
vendor/bevy_ecs/src/error/bevy_error.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
use alloc::boxed::Box;
use core::{
error::Error,
fmt::{Debug, Display},
};
/// The built in "universal" Bevy error type. This has a blanket [`From`] impl for any type that implements Rust's [`Error`],
/// meaning it can be used as a "catch all" error.
///
/// # Backtraces
///
/// When used with the `backtrace` Cargo feature, it will capture a backtrace when the error is constructed (generally in the [`From`] impl]).
/// When printed, the backtrace will be displayed. By default, the backtrace will be trimmed down to filter out noise. To see the full backtrace,
/// set the `BEVY_BACKTRACE=full` environment variable.
///
/// # Usage
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// fn fallible_system() -> Result<(), BevyError> {
/// // This will result in Rust's built-in ParseIntError, which will automatically
/// // be converted into a BevyError.
/// let parsed: usize = "I am not a number".parse()?;
/// Ok(())
/// }
/// ```
pub struct BevyError {
inner: Box<InnerBevyError>,
}
impl BevyError {
/// Attempts to downcast the internal error to the given type.
pub fn downcast_ref<E: Error + 'static>(&self) -> Option<&E> {
self.inner.error.downcast_ref::<E>()
}
fn format_backtrace(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[cfg(feature = "backtrace")]
{
let f = _f;
let backtrace = &self.inner.backtrace;
if let std::backtrace::BacktraceStatus::Captured = backtrace.status() {
let full_backtrace = std::env::var("BEVY_BACKTRACE").is_ok_and(|val| val == "full");
let backtrace_str = alloc::string::ToString::to_string(backtrace);
let mut skip_next_location_line = false;
for line in backtrace_str.split('\n') {
if !full_backtrace {
if skip_next_location_line {
if line.starts_with(" at") {
continue;
}
skip_next_location_line = false;
}
if line.contains("std::backtrace_rs::backtrace::") {
skip_next_location_line = true;
continue;
}
if line.contains("std::backtrace::Backtrace::") {
skip_next_location_line = true;
continue;
}
if line.contains("<bevy_ecs::error::bevy_error::BevyError as core::convert::From<E>>::from") {
skip_next_location_line = true;
continue;
}
if line.contains("<core::result::Result<T,F> as core::ops::try_trait::FromResidual<core::result::Result<core::convert::Infallible,E>>>::from_residual") {
skip_next_location_line = true;
continue;
}
if line.contains("__rust_begin_short_backtrace") {
break;
}
if line.contains("bevy_ecs::observer::Observers::invoke::{{closure}}") {
break;
}
}
writeln!(f, "{}", line)?;
}
if !full_backtrace {
if std::thread::panicking() {
SKIP_NORMAL_BACKTRACE.set(true);
}
writeln!(f, "{FILTER_MESSAGE}")?;
}
}
}
Ok(())
}
}
/// This type exists (rather than having a `BevyError(Box<dyn InnerBevyError)`) to make [`BevyError`] use a "thin pointer" instead of
/// a "fat pointer", which reduces the size of our Result by a usize. This does introduce an extra indirection, but error handling is a "cold path".
/// We don't need to optimize it to that degree.
/// PERF: We could probably have the best of both worlds with a "custom vtable" impl, but thats not a huge priority right now and the code simplicity
/// of the current impl is nice.
struct InnerBevyError {
error: Box<dyn Error + Send + Sync + 'static>,
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace,
}
// NOTE: writing the impl this way gives us From<&str> ... nice!
impl<E> From<E> for BevyError
where
Box<dyn Error + Send + Sync + 'static>: From<E>,
{
#[cold]
fn from(error: E) -> Self {
BevyError {
inner: Box::new(InnerBevyError {
error: error.into(),
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace::capture(),
}),
}
}
}
impl Display for BevyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{}", self.inner.error)?;
self.format_backtrace(f)?;
Ok(())
}
}
impl Debug for BevyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{:?}", self.inner.error)?;
self.format_backtrace(f)?;
Ok(())
}
}
#[cfg(feature = "backtrace")]
const FILTER_MESSAGE: &str = "note: Some \"noisy\" backtrace lines have been filtered out. Run with `BEVY_BACKTRACE=full` for a verbose backtrace.";
#[cfg(feature = "backtrace")]
std::thread_local! {
static SKIP_NORMAL_BACKTRACE: core::cell::Cell<bool> =
const { core::cell::Cell::new(false) };
}
/// When called, this will skip the currently configured panic hook when a [`BevyError`] backtrace has already been printed.
#[cfg(feature = "backtrace")]
#[expect(clippy::print_stdout, reason = "Allowed behind `std` feature gate.")]
pub fn bevy_error_panic_hook(
current_hook: impl Fn(&std::panic::PanicHookInfo),
) -> impl Fn(&std::panic::PanicHookInfo) {
move |info| {
if SKIP_NORMAL_BACKTRACE.replace(false) {
if let Some(payload) = info.payload().downcast_ref::<&str>() {
std::println!("{payload}");
} else if let Some(payload) = info.payload().downcast_ref::<alloc::string::String>() {
std::println!("{payload}");
}
return;
}
current_hook(info);
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(not(miri))] // miri backtraces are weird
#[cfg(not(windows))] // the windows backtrace in this context is ... unhelpful and not worth testing
fn filtered_backtrace_test() {
fn i_fail() -> crate::error::Result {
let _: usize = "I am not a number".parse()?;
Ok(())
}
// SAFETY: this is not safe ... this test could run in parallel with another test
// that writes the environment variable. We either accept that so we can write this test,
// or we don't.
unsafe { std::env::set_var("RUST_BACKTRACE", "1") };
let error = i_fail().err().unwrap();
let debug_message = alloc::format!("{error:?}");
let mut lines = debug_message.lines().peekable();
assert_eq!(
"ParseIntError { kind: InvalidDigit }",
lines.next().unwrap()
);
// On mac backtraces can start with Backtrace::create
let mut skip = false;
if let Some(line) = lines.peek() {
if &line[6..] == "std::backtrace::Backtrace::create" {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
let expected_lines = alloc::vec![
"bevy_ecs::error::bevy_error::tests::filtered_backtrace_test::i_fail",
"bevy_ecs::error::bevy_error::tests::filtered_backtrace_test",
"bevy_ecs::error::bevy_error::tests::filtered_backtrace_test::{{closure}}",
"core::ops::function::FnOnce::call_once",
];
for expected in expected_lines {
let line = lines.next().unwrap();
assert_eq!(&line[6..], expected);
let mut skip = false;
if let Some(line) = lines.peek() {
if line.starts_with(" at") {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
}
// on linux there is a second call_once
let mut skip = false;
if let Some(line) = lines.peek() {
if &line[6..] == "core::ops::function::FnOnce::call_once" {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
let mut skip = false;
if let Some(line) = lines.peek() {
if line.starts_with(" at") {
skip = true;
}
}
if skip {
lines.next().unwrap();
}
assert_eq!(super::FILTER_MESSAGE, lines.next().unwrap());
assert!(lines.next().is_none());
}
}

View File

@@ -0,0 +1,120 @@
use core::{any::type_name, fmt};
use crate::{
entity::Entity,
never::Never,
system::{entity_command::EntityCommandError, Command, EntityCommand},
world::{error::EntityMutableFetchError, World},
};
use super::{default_error_handler, BevyError, ErrorContext};
/// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
/// a [`Command`] that internally handles an error if it occurs and returns `()`.
pub trait HandleError<Out = ()> {
/// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
/// a [`Command`] that internally handles an error if it occurs and returns `()`.
fn handle_error_with(self, error_handler: fn(BevyError, ErrorContext)) -> impl Command;
/// Takes a [`Command`] that returns a Result and uses the default error handler function to convert it into
/// a [`Command`] that internally handles an error if it occurs and returns `()`.
fn handle_error(self) -> impl Command
where
Self: Sized,
{
self.handle_error_with(default_error_handler())
}
}
impl<C, T, E> HandleError<Result<T, E>> for C
where
C: Command<Result<T, E>>,
E: Into<BevyError>,
{
fn handle_error_with(self, error_handler: fn(BevyError, ErrorContext)) -> impl Command {
move |world: &mut World| match self.apply(world) {
Ok(_) => {}
Err(err) => (error_handler)(
err.into(),
ErrorContext::Command {
name: type_name::<C>().into(),
},
),
}
}
}
impl<C> HandleError<Never> for C
where
C: Command<Never>,
{
fn handle_error_with(self, _error_handler: fn(BevyError, ErrorContext)) -> impl Command {
move |world: &mut World| {
self.apply(world);
}
}
}
impl<C> HandleError for C
where
C: Command,
{
#[inline]
fn handle_error_with(self, _error_handler: fn(BevyError, ErrorContext)) -> impl Command {
self
}
#[inline]
fn handle_error(self) -> impl Command
where
Self: Sized,
{
self
}
}
/// Passes in a specific entity to an [`EntityCommand`], resulting in a [`Command`] that
/// internally runs the [`EntityCommand`] on that entity.
///
// NOTE: This is a separate trait from `EntityCommand` because "result-returning entity commands" and
// "non-result returning entity commands" require different implementations, so they cannot be automatically
// implemented. And this isn't the type of implementation that we want to thrust on people implementing
// EntityCommand.
pub trait CommandWithEntity<Out> {
/// Passes in a specific entity to an [`EntityCommand`], resulting in a [`Command`] that
/// internally runs the [`EntityCommand`] on that entity.
fn with_entity(self, entity: Entity) -> impl Command<Out> + HandleError<Out>;
}
impl<C> CommandWithEntity<Result<(), EntityMutableFetchError>> for C
where
C: EntityCommand,
{
fn with_entity(
self,
entity: Entity,
) -> impl Command<Result<(), EntityMutableFetchError>>
+ HandleError<Result<(), EntityMutableFetchError>> {
move |world: &mut World| -> Result<(), EntityMutableFetchError> {
let entity = world.get_entity_mut(entity)?;
self.apply(entity);
Ok(())
}
}
}
impl<C, T, Err> CommandWithEntity<Result<T, EntityCommandError<Err>>> for C
where
C: EntityCommand<Result<T, Err>>,
Err: fmt::Debug + fmt::Display + Send + Sync + 'static,
{
fn with_entity(
self,
entity: Entity,
) -> impl Command<Result<T, EntityCommandError<Err>>> + HandleError<Result<T, EntityCommandError<Err>>>
{
move |world: &mut World| {
let entity = world.get_entity_mut(entity)?;
self.apply(entity)
.map_err(EntityCommandError::CommandFailed)
}
}
}

183
vendor/bevy_ecs/src/error/handler.rs vendored Normal file
View File

@@ -0,0 +1,183 @@
#[cfg(feature = "configurable_error_handler")]
use bevy_platform::sync::OnceLock;
use core::fmt::Display;
use crate::{component::Tick, error::BevyError};
use alloc::borrow::Cow;
/// Context for a [`BevyError`] to aid in debugging.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ErrorContext {
/// The error occurred in a system.
System {
/// The name of the system that failed.
name: Cow<'static, str>,
/// The last tick that the system was run.
last_run: Tick,
},
/// The error occurred in a run condition.
RunCondition {
/// The name of the run condition that failed.
name: Cow<'static, str>,
/// The last tick that the run condition was evaluated.
last_run: Tick,
},
/// The error occurred in a command.
Command {
/// The name of the command that failed.
name: Cow<'static, str>,
},
/// The error occurred in an observer.
Observer {
/// The name of the observer that failed.
name: Cow<'static, str>,
/// The last tick that the observer was run.
last_run: Tick,
},
}
impl Display for ErrorContext {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::System { name, .. } => {
write!(f, "System `{}` failed", name)
}
Self::Command { name } => write!(f, "Command `{}` failed", name),
Self::Observer { name, .. } => {
write!(f, "Observer `{}` failed", name)
}
Self::RunCondition { name, .. } => {
write!(f, "Run condition `{}` failed", name)
}
}
}
}
impl ErrorContext {
/// The name of the ECS construct that failed.
pub fn name(&self) -> &str {
match self {
Self::System { name, .. }
| Self::Command { name, .. }
| Self::Observer { name, .. }
| Self::RunCondition { name, .. } => name,
}
}
/// A string representation of the kind of ECS construct that failed.
///
/// This is a simpler helper used for logging.
pub fn kind(&self) -> &str {
match self {
Self::System { .. } => "system",
Self::Command { .. } => "command",
Self::Observer { .. } => "observer",
Self::RunCondition { .. } => "run condition",
}
}
}
/// A global error handler. This can be set at startup, as long as it is set before
/// any uses. This should generally be configured _before_ initializing the app.
///
/// This should be set inside of your `main` function, before initializing the Bevy app.
/// The value of this error handler can be accessed using the [`default_error_handler`] function,
/// which calls [`OnceLock::get_or_init`] to get the value.
///
/// **Note:** this is only available when the `configurable_error_handler` feature of `bevy_ecs` (or `bevy`) is enabled!
///
/// # Example
///
/// ```
/// # use bevy_ecs::error::{GLOBAL_ERROR_HANDLER, warn};
/// GLOBAL_ERROR_HANDLER.set(warn).expect("The error handler can only be set once, globally.");
/// // initialize Bevy App here
/// ```
///
/// To use this error handler in your app for custom error handling logic:
///
/// ```rust
/// use bevy_ecs::error::{default_error_handler, GLOBAL_ERROR_HANDLER, BevyError, ErrorContext, panic};
///
/// fn handle_errors(error: BevyError, ctx: ErrorContext) {
/// let error_handler = default_error_handler();
/// error_handler(error, ctx);
/// }
/// ```
///
/// # Warning
///
/// As this can *never* be overwritten, library code should never set this value.
#[cfg(feature = "configurable_error_handler")]
pub static GLOBAL_ERROR_HANDLER: OnceLock<fn(BevyError, ErrorContext)> = OnceLock::new();
/// The default error handler. This defaults to [`panic()`],
/// but if set, the [`GLOBAL_ERROR_HANDLER`] will be used instead, enabling error handler customization.
/// The `configurable_error_handler` feature must be enabled to change this from the panicking default behavior,
/// as there may be runtime overhead.
#[inline]
pub fn default_error_handler() -> fn(BevyError, ErrorContext) {
#[cfg(not(feature = "configurable_error_handler"))]
return panic;
#[cfg(feature = "configurable_error_handler")]
return *GLOBAL_ERROR_HANDLER.get_or_init(|| panic);
}
macro_rules! inner {
($call:path, $e:ident, $c:ident) => {
$call!(
"Encountered an error in {} `{}`: {}",
$c.kind(),
$c.name(),
$e
);
};
}
/// Error handler that panics with the system error.
#[track_caller]
#[inline]
pub fn panic(error: BevyError, ctx: ErrorContext) {
inner!(panic, error, ctx);
}
/// Error handler that logs the system error at the `error` level.
#[track_caller]
#[inline]
pub fn error(error: BevyError, ctx: ErrorContext) {
inner!(log::error, error, ctx);
}
/// Error handler that logs the system error at the `warn` level.
#[track_caller]
#[inline]
pub fn warn(error: BevyError, ctx: ErrorContext) {
inner!(log::warn, error, ctx);
}
/// Error handler that logs the system error at the `info` level.
#[track_caller]
#[inline]
pub fn info(error: BevyError, ctx: ErrorContext) {
inner!(log::info, error, ctx);
}
/// Error handler that logs the system error at the `debug` level.
#[track_caller]
#[inline]
pub fn debug(error: BevyError, ctx: ErrorContext) {
inner!(log::debug, error, ctx);
}
/// Error handler that logs the system error at the `trace` level.
#[track_caller]
#[inline]
pub fn trace(error: BevyError, ctx: ErrorContext) {
inner!(log::trace, error, ctx);
}
/// Error handler that ignores the system error.
#[track_caller]
#[inline]
pub fn ignore(_: BevyError, _: ErrorContext) {}

81
vendor/bevy_ecs/src/error/mod.rs vendored Normal file
View File

@@ -0,0 +1,81 @@
//! Error handling for Bevy systems, commands, and observers.
//!
//! When a system is added to a [`Schedule`], and its return type is that of [`Result`], then Bevy
//! considers those systems to be "fallible", and the ECS scheduler will special-case the [`Err`]
//! variant of the returned `Result`.
//!
//! All [`BevyError`]s returned by a system, observer or command are handled by an "error handler". By default, the
//! [`panic`] error handler function is used, resulting in a panic with the error message attached.
//!
//! You can change the default behavior by registering a custom error handler.
//! Modify the [`GLOBAL_ERROR_HANDLER`] value to set a custom error handler function for your entire app.
//! In practice, this is generally feature-flagged: panicking or loudly logging errors in development,
//! and quietly logging or ignoring them in production to avoid crashing the app.
//!
//! Bevy provides a number of pre-built error-handlers for you to use:
//!
//! - [`panic`] panics with the system error
//! - [`error`] logs the system error at the `error` level
//! - [`warn`] logs the system error at the `warn` level
//! - [`info`] logs the system error at the `info` level
//! - [`debug`] logs the system error at the `debug` level
//! - [`trace`] logs the system error at the `trace` level
//! - [`ignore`] ignores the system error
//!
//! However, you can use any custom error handler logic by providing your own function (or
//! non-capturing closure that coerces to the function signature) as long as it matches the
//! signature:
//!
//! ```rust,ignore
//! fn(BevyError, ErrorContext)
//! ```
//!
//! The [`ErrorContext`] allows you to access additional details relevant to providing
//! context surrounding the error such as the system's [`name`] in your error messages.
//!
//! Remember to turn on the `configurable_error_handler` feature to set a global error handler!
//!
//! ```rust, ignore
//! use bevy_ecs::error::{GLOBAL_ERROR_HANDLER, BevyError, ErrorContext};
//! use log::trace;
//!
//! fn my_error_handler(error: BevyError, ctx: ErrorContext) {
//! if ctx.name().ends_with("plz_ignore") {
//! trace!("Nothing to see here, move along.");
//! return;
//! }
//! bevy_ecs::error::error(error, ctx);
//! }
//!
//! fn main() {
//! // This requires the "configurable_error_handler" feature to be enabled to be in scope.
//! GLOBAL_ERROR_HANDLER.set(my_error_handler).expect("The error handler can only be set once.");
//!
//! // Initialize your Bevy App here
//! }
//! ```
//!
//! If you need special handling of individual fallible systems, you can use Bevy's [`system piping
//! feature`] to capture the [`Result`] output of the system and handle it accordingly.
//!
//! When working with commands, you can handle the result of each command separately using the [`HandleError::handle_error_with`] method.
//!
//! [`Schedule`]: crate::schedule::Schedule
//! [`panic`]: panic()
//! [`World`]: crate::world::World
//! [`System`]: crate::system::System
//! [`name`]: crate::system::System::name
//! [`system piping feature`]: crate::system::In
mod bevy_error;
mod command_handling;
mod handler;
pub use bevy_error::*;
pub use command_handling::*;
pub use handler::*;
/// A result type for use in fallible systems, commands and observers.
///
/// The [`BevyError`] type is a type-erased error type with optional Bevy-specific diagnostics.
pub type Result<T = (), E = BevyError> = core::result::Result<T, E>;

184
vendor/bevy_ecs/src/event/base.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
use crate::change_detection::MaybeLocation;
use crate::component::ComponentId;
use crate::world::World;
use crate::{component::Component, traversal::Traversal};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::{
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
};
/// Something that "happens" and might be read / observed by app logic.
///
/// Events can be stored in an [`Events<E>`] resource
/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter.
///
/// Events can also be "triggered" on a [`World`], which will then cause any [`Observer`] of that trigger to run.
///
/// Events must be thread-safe.
///
/// ## Derive
/// This trait can be derived.
/// Adding `auto_propagate` sets [`Self::AUTO_PROPAGATE`] to true.
/// Adding `traversal = "X"` sets [`Self::Traversal`] to be of type "X".
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Event)]
/// #[event(auto_propagate)]
/// struct MyEvent;
/// ```
///
///
/// [`World`]: crate::world::World
/// [`ComponentId`]: crate::component::ComponentId
/// [`Observer`]: crate::observer::Observer
/// [`Events<E>`]: super::Events
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[diagnostic::on_unimplemented(
message = "`{Self}` is not an `Event`",
label = "invalid `Event`",
note = "consider annotating `{Self}` with `#[derive(Event)]`"
)]
pub trait Event: Send + Sync + 'static {
/// The component that describes which Entity to propagate this event to next, when [propagation] is enabled.
///
/// [propagation]: crate::observer::Trigger::propagate
type Traversal: Traversal<Self>;
/// When true, this event will always attempt to propagate when [triggered], without requiring a call
/// to [`Trigger::propagate`].
///
/// [triggered]: crate::system::Commands::trigger_targets
/// [`Trigger::propagate`]: crate::observer::Trigger::propagate
const AUTO_PROPAGATE: bool = false;
/// Generates the [`ComponentId`] for this event type.
///
/// If this type has already been registered,
/// this will return the existing [`ComponentId`].
///
/// This is used by various dynamically typed observer APIs,
/// such as [`World::trigger_targets_dynamic`].
///
/// # Warning
///
/// This method should not be overridden by implementors,
/// and should always correspond to the implementation of [`component_id`](Event::component_id).
fn register_component_id(world: &mut World) -> ComponentId {
world.register_component::<EventWrapperComponent<Self>>()
}
/// Fetches the [`ComponentId`] for this event type,
/// if it has already been generated.
///
/// This is used by various dynamically typed observer APIs,
/// such as [`World::trigger_targets_dynamic`].
///
/// # Warning
///
/// This method should not be overridden by implementors,
/// and should always correspond to the implementation of [`register_component_id`](Event::register_component_id).
fn component_id(world: &World) -> Option<ComponentId> {
world.component_id::<EventWrapperComponent<Self>>()
}
}
/// An internal type that implements [`Component`] for a given [`Event`] type.
///
/// This exists so we can easily get access to a unique [`ComponentId`] for each [`Event`] type,
/// without requiring that [`Event`] types implement [`Component`] directly.
/// [`ComponentId`] is used internally as a unique identitifier for events because they are:
///
/// - Unique to each event type.
/// - Can be quickly generated and looked up.
/// - Are compatible with dynamic event types, which aren't backed by a Rust type.
///
/// This type is an implementation detail and should never be made public.
// TODO: refactor events to store their metadata on distinct entities, rather than using `ComponentId`
#[derive(Component)]
struct EventWrapperComponent<E: Event + ?Sized>(PhantomData<E>);
/// An `EventId` uniquely identifies an event stored in a specific [`World`].
///
/// An `EventId` can among other things be used to trace the flow of an event from the point it was
/// sent to the point it was processed. `EventId`s increase monotonically by send order.
///
/// [`World`]: crate::world::World
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Clone, Debug, PartialEq, Hash)
)]
pub struct EventId<E: Event> {
/// Uniquely identifies the event associated with this ID.
// This value corresponds to the order in which each event was added to the world.
pub id: usize,
/// The source code location that triggered this event.
pub caller: MaybeLocation,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
pub(super) _marker: PhantomData<E>,
}
impl<E: Event> Copy for EventId<E> {}
impl<E: Event> Clone for EventId<E> {
fn clone(&self) -> Self {
*self
}
}
impl<E: Event> fmt::Display for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}
impl<E: Event> fmt::Debug for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"event<{}>#{}",
core::any::type_name::<E>().split("::").last().unwrap(),
self.id,
)
}
}
impl<E: Event> PartialEq for EventId<E> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<E: Event> Eq for EventId<E> {}
impl<E: Event> PartialOrd for EventId<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<E: Event> Ord for EventId<E> {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl<E: Event> Hash for EventId<E> {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.id, state);
}
}
#[derive(Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
pub(crate) struct EventInstance<E: Event> {
pub event_id: EventId<E>,
pub event: E,
}

422
vendor/bevy_ecs/src/event/collections.rs vendored Normal file
View File

@@ -0,0 +1,422 @@
use alloc::vec::Vec;
use bevy_ecs::{
change_detection::MaybeLocation,
event::{Event, EventCursor, EventId, EventInstance},
resource::Resource,
};
use core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
#[cfg(feature = "bevy_reflect")]
use {
bevy_ecs::reflect::ReflectResource,
bevy_reflect::{std_traits::ReflectDefault, Reflect},
};
/// An event collection that represents the events that occurred within the last two
/// [`Events::update`] calls.
/// Events can be written to using an [`EventWriter`]
/// and are typically cheaply read using an [`EventReader`].
///
/// Each event can be consumed by multiple systems, in parallel,
/// with consumption tracked by the [`EventReader`] on a per-system basis.
///
/// If no [ordering](https://github.com/bevyengine/bevy/blob/main/examples/ecs/ecs_guide.rs)
/// is applied between writing and reading systems, there is a risk of a race condition.
/// This means that whether the events arrive before or after the next [`Events::update`] is unpredictable.
///
/// This collection is meant to be paired with a system that calls
/// [`Events::update`] exactly once per update/frame.
///
/// [`event_update_system`] is a system that does this, typically initialized automatically using
/// [`add_event`](https://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event).
/// [`EventReader`]s are expected to read events from this collection at least once per loop/frame.
/// Events will persist across a single frame boundary and so ordering of event producers and
/// consumers is not critical (although poorly-planned ordering may cause accumulating lag).
/// If events are not handled by the end of the frame after they are updated, they will be
/// dropped silently.
///
/// # Example
/// ```
/// use bevy_ecs::event::{Event, Events};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize
/// }
///
/// // setup
/// let mut events = Events::<MyEvent>::default();
/// let mut cursor = events.get_cursor();
///
/// // run this once per update/frame
/// events.update();
///
/// // somewhere else: send an event
/// events.send(MyEvent { value: 1 });
///
/// // somewhere else: read the events
/// for event in cursor.read(&events) {
/// assert_eq!(event.value, 1)
/// }
///
/// // events are only processed once per reader
/// assert_eq!(cursor.read(&events).count(), 0);
/// ```
///
/// # Details
///
/// [`Events`] is implemented using a variation of a double buffer strategy.
/// Each call to [`update`](Events::update) swaps buffers and clears out the oldest one.
/// - [`EventReader`]s will read events from both buffers.
/// - [`EventReader`]s that read at least once per update will never drop events.
/// - [`EventReader`]s that read once within two updates might still receive some events
/// - [`EventReader`]s that read after two updates are guaranteed to drop all events that occurred
/// before those updates.
///
/// The buffers in [`Events`] will grow indefinitely if [`update`](Events::update) is never called.
///
/// An alternative call pattern would be to call [`update`](Events::update)
/// manually across frames to control when events are cleared.
/// This complicates consumption and risks ever-expanding memory usage if not cleaned up,
/// but can be done by adding your event as a resource instead of using
/// [`add_event`](https://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event).
///
/// [Example usage.](https://github.com/bevyengine/bevy/blob/latest/examples/ecs/event.rs)
/// [Example usage standalone.](https://github.com/bevyengine/bevy/blob/latest/crates/bevy_ecs/examples/events.rs)
///
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
/// [`event_update_system`]: super::event_update_system
#[derive(Debug, Resource)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Resource, Default))]
pub struct Events<E: Event> {
/// Holds the oldest still active events.
/// Note that `a.start_event_count + a.len()` should always be equal to `events_b.start_event_count`.
pub(crate) events_a: EventSequence<E>,
/// Holds the newer events.
pub(crate) events_b: EventSequence<E>,
pub(crate) event_count: usize,
}
// Derived Default impl would incorrectly require E: Default
impl<E: Event> Default for Events<E> {
fn default() -> Self {
Self {
events_a: Default::default(),
events_b: Default::default(),
event_count: Default::default(),
}
}
}
impl<E: Event> Events<E> {
/// Returns the index of the oldest event stored in the event buffer.
pub fn oldest_event_count(&self) -> usize {
self.events_a.start_event_count
}
/// "Sends" an `event` by writing it to the current event buffer.
/// [`EventReader`](super::EventReader)s can then read the event.
/// This method returns the [ID](`EventId`) of the sent `event`.
#[track_caller]
pub fn send(&mut self, event: E) -> EventId<E> {
self.send_with_caller(event, MaybeLocation::caller())
}
pub(crate) fn send_with_caller(&mut self, event: E, caller: MaybeLocation) -> EventId<E> {
let event_id = EventId {
id: self.event_count,
caller,
_marker: PhantomData,
};
#[cfg(feature = "detailed_trace")]
tracing::trace!("Events::send() -> id: {}", event_id);
let event_instance = EventInstance { event_id, event };
self.events_b.push(event_instance);
self.event_count += 1;
event_id
}
/// Sends a list of `events` all at once, which can later be read by [`EventReader`](super::EventReader)s.
/// This is more efficient than sending each event individually.
/// This method returns the [IDs](`EventId`) of the sent `events`.
#[track_caller]
pub fn send_batch(&mut self, events: impl IntoIterator<Item = E>) -> SendBatchIds<E> {
let last_count = self.event_count;
self.extend(events);
SendBatchIds {
last_count,
event_count: self.event_count,
_marker: PhantomData,
}
}
/// Sends the default value of the event. Useful when the event is an empty struct.
/// This method returns the [ID](`EventId`) of the sent `event`.
#[track_caller]
pub fn send_default(&mut self) -> EventId<E>
where
E: Default,
{
self.send(Default::default())
}
/// Gets a new [`EventCursor`]. This will include all events already in the event buffers.
pub fn get_cursor(&self) -> EventCursor<E> {
EventCursor::default()
}
/// Gets a new [`EventCursor`]. This will ignore all events already in the event buffers.
/// It will read all future events.
pub fn get_cursor_current(&self) -> EventCursor<E> {
EventCursor {
last_event_count: self.event_count,
..Default::default()
}
}
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be
/// called once per frame/update.
///
/// If you need access to the events that were removed, consider using [`Events::update_drain`].
pub fn update(&mut self) {
core::mem::swap(&mut self.events_a, &mut self.events_b);
self.events_b.clear();
self.events_b.start_event_count = self.event_count;
debug_assert_eq!(
self.events_a.start_event_count + self.events_a.len(),
self.events_b.start_event_count
);
}
/// Swaps the event buffers and drains the oldest event buffer, returning an iterator
/// of all events that were removed. In general, this should be called once per frame/update.
///
/// If you do not need to take ownership of the removed events, use [`Events::update`] instead.
#[must_use = "If you do not need the returned events, call .update() instead."]
pub fn update_drain(&mut self) -> impl Iterator<Item = E> + '_ {
core::mem::swap(&mut self.events_a, &mut self.events_b);
let iter = self.events_b.events.drain(..);
self.events_b.start_event_count = self.event_count;
debug_assert_eq!(
self.events_a.start_event_count + self.events_a.len(),
self.events_b.start_event_count
);
iter.map(|e| e.event)
}
#[inline]
fn reset_start_event_count(&mut self) {
self.events_a.start_event_count = self.event_count;
self.events_b.start_event_count = self.event_count;
}
/// Removes all events.
#[inline]
pub fn clear(&mut self) {
self.reset_start_event_count();
self.events_a.clear();
self.events_b.clear();
}
/// Returns the number of events currently stored in the event buffer.
#[inline]
pub fn len(&self) -> usize {
self.events_a.len() + self.events_b.len()
}
/// Returns true if there are no events currently stored in the event buffer.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Creates a draining iterator that removes all events.
pub fn drain(&mut self) -> impl Iterator<Item = E> + '_ {
self.reset_start_event_count();
// Drain the oldest events first, then the newest
self.events_a
.drain(..)
.chain(self.events_b.drain(..))
.map(|i| i.event)
}
/// Iterates over events that happened since the last "update" call.
/// WARNING: You probably don't want to use this call. In most cases you should use an
/// [`EventReader`]. You should only use this if you know you only need to consume events
/// between the last `update()` call and your call to `iter_current_update_events`.
/// If events happen outside that window, they will not be handled. For example, any events that
/// happen after this call and before the next `update()` call will be dropped.
///
/// [`EventReader`]: super::EventReader
pub fn iter_current_update_events(&self) -> impl ExactSizeIterator<Item = &E> {
self.events_b.iter().map(|i| &i.event)
}
/// Get a specific event by id if it still exists in the events buffer.
pub fn get_event(&self, id: usize) -> Option<(&E, EventId<E>)> {
if id < self.oldest_event_count() {
return None;
}
let sequence = self.sequence(id);
let index = id.saturating_sub(sequence.start_event_count);
sequence
.get(index)
.map(|instance| (&instance.event, instance.event_id))
}
/// Which event buffer is this event id a part of.
fn sequence(&self, id: usize) -> &EventSequence<E> {
if id < self.events_b.start_event_count {
&self.events_a
} else {
&self.events_b
}
}
}
impl<E: Event> Extend<E> for Events<E> {
#[track_caller]
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = E>,
{
let old_count = self.event_count;
let mut event_count = self.event_count;
let events = iter.into_iter().map(|event| {
let event_id = EventId {
id: event_count,
caller: MaybeLocation::caller(),
_marker: PhantomData,
};
event_count += 1;
EventInstance { event_id, event }
});
self.events_b.extend(events);
if old_count != event_count {
#[cfg(feature = "detailed_trace")]
tracing::trace!(
"Events::extend() -> ids: ({}..{})",
self.event_count,
event_count
);
}
self.event_count = event_count;
}
}
#[derive(Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default))]
pub(crate) struct EventSequence<E: Event> {
pub(crate) events: Vec<EventInstance<E>>,
pub(crate) start_event_count: usize,
}
// Derived Default impl would incorrectly require E: Default
impl<E: Event> Default for EventSequence<E> {
fn default() -> Self {
Self {
events: Default::default(),
start_event_count: Default::default(),
}
}
}
impl<E: Event> Deref for EventSequence<E> {
type Target = Vec<EventInstance<E>>;
fn deref(&self) -> &Self::Target {
&self.events
}
}
impl<E: Event> DerefMut for EventSequence<E> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.events
}
}
/// [`Iterator`] over sent [`EventIds`](`EventId`) from a batch.
pub struct SendBatchIds<E> {
last_count: usize,
event_count: usize,
_marker: PhantomData<E>,
}
impl<E: Event> Iterator for SendBatchIds<E> {
type Item = EventId<E>;
fn next(&mut self) -> Option<Self::Item> {
if self.last_count >= self.event_count {
return None;
}
let result = Some(EventId {
id: self.last_count,
caller: MaybeLocation::caller(),
_marker: PhantomData,
});
self.last_count += 1;
result
}
}
impl<E: Event> ExactSizeIterator for SendBatchIds<E> {
fn len(&self) -> usize {
self.event_count.saturating_sub(self.last_count)
}
}
#[cfg(test)]
mod tests {
use crate::event::Events;
use bevy_ecs_macros::Event;
#[test]
fn iter_current_update_events_iterates_over_current_events() {
#[derive(Event, Clone)]
struct TestEvent;
let mut test_events = Events::<TestEvent>::default();
// Starting empty
assert_eq!(test_events.len(), 0);
assert_eq!(test_events.iter_current_update_events().count(), 0);
test_events.update();
// Sending one event
test_events.send(TestEvent);
assert_eq!(test_events.len(), 1);
assert_eq!(test_events.iter_current_update_events().count(), 1);
test_events.update();
// Sending two events on the next frame
test_events.send(TestEvent);
test_events.send(TestEvent);
assert_eq!(test_events.len(), 3); // Events are double-buffered, so we see 1 + 2 = 3
assert_eq!(test_events.iter_current_update_events().count(), 2);
test_events.update();
// Sending zero events
assert_eq!(test_events.len(), 2); // Events are double-buffered, so we see 2 + 0 = 2
assert_eq!(test_events.iter_current_update_events().count(), 0);
}
}

View File

@@ -0,0 +1,140 @@
use bevy_ecs::event::{
Event, EventIterator, EventIteratorWithId, EventMutIterator, EventMutIteratorWithId, Events,
};
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::{EventMutParIter, EventParIter};
use core::marker::PhantomData;
/// Stores the state for an [`EventReader`] or [`EventMutator`].
///
/// Access to the [`Events<E>`] resource is required to read any incoming events.
///
/// In almost all cases, you should just use an [`EventReader`] or [`EventMutator`],
/// which will automatically manage the state for you.
///
/// However, this type can be useful if you need to manually track events,
/// such as when you're attempting to send and receive events of the same type in the same system.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::event::{Event, Events, EventCursor};
///
/// #[derive(Event, Clone, Debug)]
/// struct MyEvent;
///
/// /// A system that both sends and receives events using a [`Local`] [`EventCursor`].
/// fn send_and_receive_events(
/// // The `Local` `SystemParam` stores state inside the system itself, rather than in the world.
/// // `EventCursor<T>` is the internal state of `EventMutator<T>`, which tracks which events have been seen.
/// mut local_event_reader: Local<EventCursor<MyEvent>>,
/// // We can access the `Events` resource mutably, allowing us to both read and write its contents.
/// mut events: ResMut<Events<MyEvent>>,
/// ) {
/// // We must collect the events to resend, because we can't mutate events while we're iterating over the events.
/// let mut events_to_resend = Vec::new();
///
/// for event in local_event_reader.read(&mut events) {
/// events_to_resend.push(event.clone());
/// }
///
/// for event in events_to_resend {
/// events.send(MyEvent);
/// }
/// }
///
/// # bevy_ecs::system::assert_is_system(send_and_receive_events);
/// ```
///
/// [`EventReader`]: super::EventReader
/// [`EventMutator`]: super::EventMutator
#[derive(Debug)]
pub struct EventCursor<E: Event> {
pub(super) last_event_count: usize,
pub(super) _marker: PhantomData<E>,
}
impl<E: Event> Default for EventCursor<E> {
fn default() -> Self {
EventCursor {
last_event_count: 0,
_marker: Default::default(),
}
}
}
impl<E: Event> Clone for EventCursor<E> {
fn clone(&self) -> Self {
EventCursor {
last_event_count: self.last_event_count,
_marker: PhantomData,
}
}
}
impl<E: Event> EventCursor<E> {
/// See [`EventReader::read`](super::EventReader::read)
pub fn read<'a>(&'a mut self, events: &'a Events<E>) -> EventIterator<'a, E> {
self.read_with_id(events).without_id()
}
/// See [`EventMutator::read`](super::EventMutator::read)
pub fn read_mut<'a>(&'a mut self, events: &'a mut Events<E>) -> EventMutIterator<'a, E> {
self.read_mut_with_id(events).without_id()
}
/// See [`EventReader::read_with_id`](super::EventReader::read_with_id)
pub fn read_with_id<'a>(&'a mut self, events: &'a Events<E>) -> EventIteratorWithId<'a, E> {
EventIteratorWithId::new(self, events)
}
/// See [`EventMutator::read_with_id`](super::EventMutator::read_with_id)
pub fn read_mut_with_id<'a>(
&'a mut self,
events: &'a mut Events<E>,
) -> EventMutIteratorWithId<'a, E> {
EventMutIteratorWithId::new(self, events)
}
/// See [`EventReader::par_read`](super::EventReader::par_read)
#[cfg(feature = "multi_threaded")]
pub fn par_read<'a>(&'a mut self, events: &'a Events<E>) -> EventParIter<'a, E> {
EventParIter::new(self, events)
}
/// See [`EventMutator::par_read`](super::EventMutator::par_read)
#[cfg(feature = "multi_threaded")]
pub fn par_read_mut<'a>(&'a mut self, events: &'a mut Events<E>) -> EventMutParIter<'a, E> {
EventMutParIter::new(self, events)
}
/// See [`EventReader::len`](super::EventReader::len)
pub fn len(&self, events: &Events<E>) -> usize {
// The number of events in this reader is the difference between the most recent event
// and the last event seen by it. This will be at most the number of events contained
// with the events (any others have already been dropped)
// TODO: Warn when there are dropped events, or return e.g. a `Result<usize, (usize, usize)>`
events
.event_count
.saturating_sub(self.last_event_count)
.min(events.len())
}
/// Amount of events we missed.
pub fn missed_events(&self, events: &Events<E>) -> usize {
events
.oldest_event_count()
.saturating_sub(self.last_event_count)
}
/// See [`EventReader::is_empty()`](super::EventReader::is_empty)
pub fn is_empty(&self, events: &Events<E>) -> bool {
self.len(events) == 0
}
/// See [`EventReader::clear()`](super::EventReader::clear)
pub fn clear(&mut self, events: &Events<E>) {
self.last_event_count = events.event_count;
}
}

281
vendor/bevy_ecs/src/event/iterators.rs vendored Normal file
View File

@@ -0,0 +1,281 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::batching::BatchingStrategy;
use bevy_ecs::event::{Event, EventCursor, EventId, EventInstance, Events};
use core::{iter::Chain, slice::Iter};
/// An iterator that yields any unread events from an [`EventReader`](super::EventReader) or [`EventCursor`].
#[derive(Debug)]
pub struct EventIterator<'a, E: Event> {
iter: EventIteratorWithId<'a, E>,
}
impl<'a, E: Event> Iterator for EventIterator<'a, E> {
type Item = &'a E;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(event, _)| event)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
self.iter.last().map(|(event, _)| event)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n).map(|(event, _)| event)
}
}
impl<'a, E: Event> ExactSizeIterator for EventIterator<'a, E> {
fn len(&self) -> usize {
self.iter.len()
}
}
/// An iterator that yields any unread events (and their IDs) from an [`EventReader`](super::EventReader) or [`EventCursor`].
#[derive(Debug)]
pub struct EventIteratorWithId<'a, E: Event> {
reader: &'a mut EventCursor<E>,
chain: Chain<Iter<'a, EventInstance<E>>, Iter<'a, EventInstance<E>>>,
unread: usize,
}
impl<'a, E: Event> EventIteratorWithId<'a, E> {
/// Creates a new iterator that yields any `events` that have not yet been seen by `reader`.
pub fn new(reader: &'a mut EventCursor<E>, events: &'a Events<E>) -> Self {
let a_index = reader
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = reader
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get(a_index..).unwrap_or_default();
let b = events.events_b.get(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
// Ensure `len` is implemented correctly
debug_assert_eq!(unread_count, reader.len(events));
reader.last_event_count = events.event_count - unread_count;
// Iterate the oldest first, then the newer events
let chain = a.iter().chain(b.iter());
Self {
reader,
chain,
unread: unread_count,
}
}
/// Iterate over only the events.
pub fn without_id(self) -> EventIterator<'a, E> {
EventIterator { iter: self }
}
}
impl<'a, E: Event> Iterator for EventIteratorWithId<'a, E> {
type Item = (&'a E, EventId<E>);
fn next(&mut self) -> Option<Self::Item> {
match self
.chain
.next()
.map(|instance| (&instance.event, instance.event_id))
{
Some(item) => {
#[cfg(feature = "detailed_trace")]
tracing::trace!("EventReader::iter() -> {}", item.1);
self.reader.last_event_count += 1;
self.unread -= 1;
Some(item)
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.chain.size_hint()
}
fn count(self) -> usize {
self.reader.last_event_count += self.unread;
self.unread
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
let EventInstance { event_id, event } = self.chain.last()?;
self.reader.last_event_count += self.unread;
Some((event, *event_id))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if let Some(EventInstance { event_id, event }) = self.chain.nth(n) {
self.reader.last_event_count += n + 1;
self.unread -= n + 1;
Some((event, *event_id))
} else {
self.reader.last_event_count += self.unread;
self.unread = 0;
None
}
}
}
impl<'a, E: Event> ExactSizeIterator for EventIteratorWithId<'a, E> {
fn len(&self) -> usize {
self.unread
}
}
/// A parallel iterator over `Event`s.
#[cfg(feature = "multi_threaded")]
#[derive(Debug)]
pub struct EventParIter<'a, E: Event> {
reader: &'a mut EventCursor<E>,
slices: [&'a [EventInstance<E>]; 2],
batching_strategy: BatchingStrategy,
#[cfg(not(target_arch = "wasm32"))]
unread: usize,
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> EventParIter<'a, E> {
/// Creates a new parallel iterator over `events` that have not yet been seen by `reader`.
pub fn new(reader: &'a mut EventCursor<E>, events: &'a Events<E>) -> Self {
let a_index = reader
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = reader
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get(a_index..).unwrap_or_default();
let b = events.events_b.get(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
// Ensure `len` is implemented correctly
debug_assert_eq!(unread_count, reader.len(events));
reader.last_event_count = events.event_count - unread_count;
Self {
reader,
slices: [a, b],
batching_strategy: BatchingStrategy::default(),
#[cfg(not(target_arch = "wasm32"))]
unread: unread_count,
}
}
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs the provided closure for each unread event in parallel.
///
/// Unlike normal iteration, the event order is not guaranteed in any form.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
pub fn for_each<FN: Fn(&'a E) + Send + Sync + Clone>(self, func: FN) {
self.for_each_with_id(move |e, _| func(e));
}
/// Runs the provided closure for each unread event in parallel, like [`for_each`](Self::for_each),
/// but additionally provides the `EventId` to the closure.
///
/// Note that the order of iteration is not guaranteed, but `EventId`s are ordered by send order.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[cfg_attr(
target_arch = "wasm32",
expect(unused_mut, reason = "not mutated on this target")
)]
pub fn for_each_with_id<FN: Fn(&'a E, EventId<E>) + Send + Sync + Clone>(mut self, func: FN) {
#[cfg(target_arch = "wasm32")]
{
self.into_iter().for_each(|(e, i)| func(e, i));
}
#[cfg(not(target_arch = "wasm32"))]
{
let pool = bevy_tasks::ComputeTaskPool::get();
let thread_count = pool.thread_num();
if thread_count <= 1 {
return self.into_iter().for_each(|(e, i)| func(e, i));
}
let batch_size = self
.batching_strategy
.calc_batch_size(|| self.len(), thread_count);
let chunks = self.slices.map(|s| s.chunks_exact(batch_size));
let remainders = chunks.each_ref().map(core::slice::ChunksExact::remainder);
pool.scope(|scope| {
for batch in chunks.into_iter().flatten().chain(remainders) {
let func = func.clone();
scope.spawn(async move {
for event in batch {
func(&event.event, event.event_id);
}
});
}
});
// Events are guaranteed to be read at this point.
self.reader.last_event_count += self.unread;
self.unread = 0;
}
}
/// Returns the number of [`Event`]s to be iterated.
pub fn len(&self) -> usize {
self.slices.iter().map(|s| s.len()).sum()
}
/// Returns [`true`] if there are no events remaining in this iterator.
pub fn is_empty(&self) -> bool {
self.slices.iter().all(|x| x.is_empty())
}
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> IntoIterator for EventParIter<'a, E> {
type IntoIter = EventIteratorWithId<'a, E>;
type Item = <Self::IntoIter as Iterator>::Item;
fn into_iter(self) -> Self::IntoIter {
let EventParIter {
reader,
slices: [a, b],
..
} = self;
let unread = a.len() + b.len();
let chain = a.iter().chain(b);
EventIteratorWithId {
reader,
chain,
unread,
}
}
}

621
vendor/bevy_ecs/src/event/mod.rs vendored Normal file
View File

@@ -0,0 +1,621 @@
//! Event handling types.
mod base;
mod collections;
mod event_cursor;
mod iterators;
mod mut_iterators;
mod mutator;
mod reader;
mod registry;
mod update;
mod writer;
pub(crate) use base::EventInstance;
pub use base::{Event, EventId};
pub use bevy_ecs_macros::Event;
pub use collections::{Events, SendBatchIds};
pub use event_cursor::EventCursor;
#[cfg(feature = "multi_threaded")]
pub use iterators::EventParIter;
pub use iterators::{EventIterator, EventIteratorWithId};
#[cfg(feature = "multi_threaded")]
pub use mut_iterators::EventMutParIter;
pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
pub use mutator::EventMutator;
pub use reader::EventReader;
pub use registry::{EventRegistry, ShouldUpdateEvents};
pub use update::{
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
};
pub use writer::EventWriter;
#[cfg(test)]
mod tests {
use alloc::{vec, vec::Vec};
use bevy_ecs::{event::*, system::assert_is_read_only_system};
use bevy_ecs_macros::Event;
#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
struct TestEvent {
i: usize,
}
#[derive(Event, Clone, PartialEq, Debug, Default)]
struct EmptyTestEvent;
fn get_events<E: Event + Clone>(events: &Events<E>, cursor: &mut EventCursor<E>) -> Vec<E> {
cursor.read(events).cloned().collect::<Vec<E>>()
}
#[test]
fn test_events() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
// this reader will miss event_0 and event_1 because it wont read them over the course of
// two updates
let mut reader_missed: EventCursor<TestEvent> = events.get_cursor();
let mut reader_a: EventCursor<TestEvent> = events.get_cursor();
events.send(event_0);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_0],
"reader_a created before event receives event"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![],
"second iteration of reader_a created before event results in zero events"
);
let mut reader_b: EventCursor<TestEvent> = events.get_cursor();
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_0],
"reader_b created after event receives event"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![],
"second iteration of reader_b created after event results in zero events"
);
events.send(event_1);
let mut reader_c = events.get_cursor();
assert_eq!(
get_events(&events, &mut reader_c),
vec![event_0, event_1],
"reader_c created after two events receives both events"
);
assert_eq!(
get_events(&events, &mut reader_c),
vec![],
"second iteration of reader_c created after two event results in zero events"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_1],
"reader_a receives next unread event"
);
events.update();
let mut reader_d = events.get_cursor();
events.send(event_2);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_2],
"reader_a receives event created after update"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_1, event_2],
"reader_b receives events created before and after update"
);
assert_eq!(
get_events(&events, &mut reader_d),
vec![event_0, event_1, event_2],
"reader_d receives all events created before and after update"
);
events.update();
assert_eq!(
get_events(&events, &mut reader_missed),
vec![event_2],
"reader_missed missed events unread after two update() calls"
);
}
// Events Collection
fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events<TestEvent>)) {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
assert!(reader.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
assert_eq!(*reader.read(&events).next().unwrap(), TestEvent { i: 0 });
assert_eq!(reader.read(&events).next(), None);
events.send(TestEvent { i: 1 });
clear_func(&mut events);
assert!(reader.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
events.update();
events.send(TestEvent { i: 3 });
assert!(reader
.read(&events)
.eq([TestEvent { i: 2 }, TestEvent { i: 3 }].iter()));
}
#[test]
fn test_events_clear_and_read() {
events_clear_and_read_impl(Events::clear);
}
#[test]
fn test_events_drain_and_read() {
events_clear_and_read_impl(|events| {
assert!(events
.drain()
.eq(vec![TestEvent { i: 0 }, TestEvent { i: 1 }].into_iter()));
});
}
#[test]
fn test_events_send_default() {
let mut events = Events::<EmptyTestEvent>::default();
events.send_default();
let mut reader = events.get_cursor();
assert_eq!(get_events(&events, &mut reader), vec![EmptyTestEvent]);
}
#[test]
fn test_send_events_ids() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
let event_0_id = events.send(event_0);
assert_eq!(
events.get_event(event_0_id.id),
Some((&event_0, event_0_id)),
"Getting a sent event by ID should return the original event"
);
let mut event_ids = events.send_batch([event_1, event_2]);
let event_id = event_ids.next().expect("Event 1 must have been sent");
assert_eq!(
events.get_event(event_id.id),
Some((&event_1, event_id)),
"Getting a sent event by ID should return the original event"
);
let event_id = event_ids.next().expect("Event 2 must have been sent");
assert_eq!(
events.get_event(event_id.id),
Some((&event_2, event_id)),
"Getting a sent event by ID should return the original event"
);
assert!(
event_ids.next().is_none(),
"Only sent two events; got more than two IDs"
);
}
#[test]
fn test_event_registry_can_add_and_remove_events_to_world() {
use bevy_ecs::prelude::*;
let mut world = World::new();
EventRegistry::register_event::<TestEvent>(&mut world);
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
assert!(has_events, "Should have the events resource");
EventRegistry::deregister_events::<TestEvent>(&mut world);
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
assert!(!has_events, "Should not have the events resource");
}
#[test]
fn test_events_update_drain() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 1 });
assert_eq!(reader.read(&events).count(), 2);
let mut old_events = Vec::from_iter(events.update_drain());
assert!(old_events.is_empty());
events.send(TestEvent { i: 2 });
assert_eq!(reader.read(&events).count(), 1);
old_events.extend(events.update_drain());
assert_eq!(old_events.len(), 2);
old_events.extend(events.update_drain());
assert_eq!(
old_events,
&[TestEvent { i: 0 }, TestEvent { i: 1 }, TestEvent { i: 2 }]
);
}
#[test]
fn test_events_empty() {
let mut events = Events::<TestEvent>::default();
assert!(events.is_empty());
events.send(TestEvent { i: 0 });
assert!(!events.is_empty());
events.update();
assert!(!events.is_empty());
// events are only empty after the second call to update
// due to double buffering.
events.update();
assert!(events.is_empty());
}
#[test]
fn test_events_extend_impl() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.extend(vec![TestEvent { i: 0 }, TestEvent { i: 1 }]);
assert!(reader
.read(&events)
.eq([TestEvent { i: 0 }, TestEvent { i: 1 }].iter()));
}
// Cursor
#[test]
fn test_event_cursor_read() {
let mut events = Events::<TestEvent>::default();
let mut cursor = events.get_cursor();
assert!(cursor.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
let sent_event = cursor.read(&events).next().unwrap();
assert_eq!(sent_event, &TestEvent { i: 0 });
assert!(cursor.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
let sent_event = cursor.read(&events).next().unwrap();
assert_eq!(sent_event, &TestEvent { i: 2 });
assert!(cursor.read(&events).next().is_none());
events.clear();
assert!(cursor.read(&events).next().is_none());
}
#[test]
fn test_event_cursor_read_mut() {
let mut events = Events::<TestEvent>::default();
let mut write_cursor = events.get_cursor();
let mut read_cursor = events.get_cursor();
assert!(write_cursor.read_mut(&mut events).next().is_none());
assert!(read_cursor.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
assert_eq!(sent_event, &mut TestEvent { i: 0 });
*sent_event = TestEvent { i: 1 }; // Mutate whole event
assert_eq!(
read_cursor.read(&events).next().unwrap(),
&TestEvent { i: 1 }
);
assert!(read_cursor.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
assert_eq!(sent_event, &mut TestEvent { i: 2 });
sent_event.i = 3; // Mutate sub value
assert_eq!(
read_cursor.read(&events).next().unwrap(),
&TestEvent { i: 3 }
);
assert!(read_cursor.read(&events).next().is_none());
events.clear();
assert!(write_cursor.read(&events).next().is_none());
assert!(read_cursor.read(&events).next().is_none());
}
#[test]
fn test_event_cursor_clear() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 1);
reader.clear(&events);
assert_eq!(reader.len(&events), 0);
}
#[test]
fn test_event_cursor_len_update() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 0 });
let reader = events.get_cursor();
assert_eq!(reader.len(&events), 2);
events.update();
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 3);
events.update();
assert_eq!(reader.len(&events), 1);
events.update();
assert!(reader.is_empty(&events));
}
#[test]
fn test_event_cursor_len_current() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
let reader = events.get_cursor_current();
assert!(reader.is_empty(&events));
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 1);
assert!(!reader.is_empty(&events));
}
#[test]
fn test_event_cursor_iter_len_updated() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 1 });
events.send(TestEvent { i: 2 });
let mut reader = events.get_cursor();
let mut iter = reader.read(&events);
assert_eq!(iter.len(), 3);
iter.next();
assert_eq!(iter.len(), 2);
iter.next();
assert_eq!(iter.len(), 1);
iter.next();
assert_eq!(iter.len(), 0);
}
#[test]
fn test_event_cursor_len_empty() {
let events = Events::<TestEvent>::default();
assert_eq!(events.get_cursor().len(&events), 0);
assert!(events.get_cursor().is_empty(&events));
}
#[test]
fn test_event_cursor_len_filled() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
assert_eq!(events.get_cursor().len(&events), 1);
assert!(!events.get_cursor().is_empty(&events));
}
#[cfg(feature = "multi_threaded")]
#[test]
fn test_event_cursor_par_read() {
use crate::prelude::*;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Resource)]
struct Counter(AtomicUsize);
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
for _ in 0..100 {
world.send_event(TestEvent { i: 1 });
}
let mut schedule = Schedule::default();
schedule.add_systems(
|mut cursor: Local<EventCursor<TestEvent>>,
events: Res<Events<TestEvent>>,
counter: ResMut<Counter>| {
cursor.par_read(&events).for_each(|event| {
counter.0.fetch_add(event.i, Ordering::Relaxed);
});
},
);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(counter.0.into_inner(), 100);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(
counter.0.into_inner(),
0,
"par_read should have consumed events but didn't"
);
}
#[cfg(feature = "multi_threaded")]
#[test]
fn test_event_cursor_par_read_mut() {
use crate::prelude::*;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Resource)]
struct Counter(AtomicUsize);
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
for _ in 0..100 {
world.send_event(TestEvent { i: 1 });
}
let mut schedule = Schedule::default();
schedule.add_systems(
|mut cursor: Local<EventCursor<TestEvent>>,
mut events: ResMut<Events<TestEvent>>,
counter: ResMut<Counter>| {
cursor.par_read_mut(&mut events).for_each(|event| {
event.i += 1;
counter.0.fetch_add(event.i, Ordering::Relaxed);
});
},
);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(counter.0.into_inner(), 200, "Initial run failed");
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(
counter.0.into_inner(),
0,
"par_read_mut should have consumed events but didn't"
);
}
// Reader & Mutator
#[test]
fn ensure_reader_readonly() {
fn reader_system(_: EventReader<EmptyTestEvent>) {}
assert_is_read_only_system(reader_system);
}
#[test]
fn test_event_reader_iter_last() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
let mut reader =
IntoSystem::into_system(|mut events: EventReader<TestEvent>| -> Option<TestEvent> {
events.read().last().copied()
});
reader.initialize(&mut world);
let last = reader.run((), &mut world);
assert!(last.is_none(), "EventReader should be empty");
world.send_event(TestEvent { i: 0 });
let last = reader.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 0 }));
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
let last = reader.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));
let last = reader.run((), &mut world);
assert!(last.is_none(), "EventReader should be empty");
}
#[test]
fn test_event_mutator_iter_last() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
let mut mutator =
IntoSystem::into_system(|mut events: EventMutator<TestEvent>| -> Option<TestEvent> {
events.read().last().copied()
});
mutator.initialize(&mut world);
let last = mutator.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");
world.send_event(TestEvent { i: 0 });
let last = mutator.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 0 }));
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
let last = mutator.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));
let last = mutator.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");
}
#[test]
fn test_event_reader_iter_nth() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
world.send_event(TestEvent { i: 0 });
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
world.send_event(TestEvent { i: 4 });
let mut schedule = Schedule::default();
schedule.add_systems(|mut events: EventReader<TestEvent>| {
let mut iter = events.read();
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
assert_eq!(iter.nth(1), None);
assert!(events.is_empty());
});
schedule.run(&mut world);
}
#[test]
fn test_event_mutator_iter_nth() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
world.send_event(TestEvent { i: 0 });
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
world.send_event(TestEvent { i: 4 });
let mut schedule = Schedule::default();
schedule.add_systems(|mut events: EventReader<TestEvent>| {
let mut iter = events.read();
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
assert_eq!(iter.nth(1), None);
assert!(events.is_empty());
});
schedule.run(&mut world);
}
}

View File

@@ -0,0 +1,284 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::batching::BatchingStrategy;
use bevy_ecs::event::{Event, EventCursor, EventId, EventInstance, Events};
use core::{iter::Chain, slice::IterMut};
/// An iterator that yields any unread events from an [`EventMutator`] or [`EventCursor`].
///
/// [`EventMutator`]: super::EventMutator
#[derive(Debug)]
pub struct EventMutIterator<'a, E: Event> {
iter: EventMutIteratorWithId<'a, E>,
}
impl<'a, E: Event> Iterator for EventMutIterator<'a, E> {
type Item = &'a mut E;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(event, _)| event)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
self.iter.last().map(|(event, _)| event)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n).map(|(event, _)| event)
}
}
impl<'a, E: Event> ExactSizeIterator for EventMutIterator<'a, E> {
fn len(&self) -> usize {
self.iter.len()
}
}
/// An iterator that yields any unread events (and their IDs) from an [`EventMutator`] or [`EventCursor`].
///
/// [`EventMutator`]: super::EventMutator
#[derive(Debug)]
pub struct EventMutIteratorWithId<'a, E: Event> {
mutator: &'a mut EventCursor<E>,
chain: Chain<IterMut<'a, EventInstance<E>>, IterMut<'a, EventInstance<E>>>,
unread: usize,
}
impl<'a, E: Event> EventMutIteratorWithId<'a, E> {
/// Creates a new iterator that yields any `events` that have not yet been seen by `mutator`.
pub fn new(mutator: &'a mut EventCursor<E>, events: &'a mut Events<E>) -> Self {
let a_index = mutator
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = mutator
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get_mut(a_index..).unwrap_or_default();
let b = events.events_b.get_mut(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
mutator.last_event_count = events.event_count - unread_count;
// Iterate the oldest first, then the newer events
let chain = a.iter_mut().chain(b.iter_mut());
Self {
mutator,
chain,
unread: unread_count,
}
}
/// Iterate over only the events.
pub fn without_id(self) -> EventMutIterator<'a, E> {
EventMutIterator { iter: self }
}
}
impl<'a, E: Event> Iterator for EventMutIteratorWithId<'a, E> {
type Item = (&'a mut E, EventId<E>);
fn next(&mut self) -> Option<Self::Item> {
match self
.chain
.next()
.map(|instance| (&mut instance.event, instance.event_id))
{
Some(item) => {
#[cfg(feature = "detailed_trace")]
tracing::trace!("EventMutator::iter() -> {}", item.1);
self.mutator.last_event_count += 1;
self.unread -= 1;
Some(item)
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.chain.size_hint()
}
fn count(self) -> usize {
self.mutator.last_event_count += self.unread;
self.unread
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
let EventInstance { event_id, event } = self.chain.last()?;
self.mutator.last_event_count += self.unread;
Some((event, *event_id))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if let Some(EventInstance { event_id, event }) = self.chain.nth(n) {
self.mutator.last_event_count += n + 1;
self.unread -= n + 1;
Some((event, *event_id))
} else {
self.mutator.last_event_count += self.unread;
self.unread = 0;
None
}
}
}
impl<'a, E: Event> ExactSizeIterator for EventMutIteratorWithId<'a, E> {
fn len(&self) -> usize {
self.unread
}
}
/// A parallel iterator over `Event`s.
#[derive(Debug)]
#[cfg(feature = "multi_threaded")]
pub struct EventMutParIter<'a, E: Event> {
mutator: &'a mut EventCursor<E>,
slices: [&'a mut [EventInstance<E>]; 2],
batching_strategy: BatchingStrategy,
#[cfg(not(target_arch = "wasm32"))]
unread: usize,
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> EventMutParIter<'a, E> {
/// Creates a new parallel iterator over `events` that have not yet been seen by `mutator`.
pub fn new(mutator: &'a mut EventCursor<E>, events: &'a mut Events<E>) -> Self {
let a_index = mutator
.last_event_count
.saturating_sub(events.events_a.start_event_count);
let b_index = mutator
.last_event_count
.saturating_sub(events.events_b.start_event_count);
let a = events.events_a.get_mut(a_index..).unwrap_or_default();
let b = events.events_b.get_mut(b_index..).unwrap_or_default();
let unread_count = a.len() + b.len();
mutator.last_event_count = events.event_count - unread_count;
Self {
mutator,
slices: [a, b],
batching_strategy: BatchingStrategy::default(),
#[cfg(not(target_arch = "wasm32"))]
unread: unread_count,
}
}
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs the provided closure for each unread event in parallel.
///
/// Unlike normal iteration, the event order is not guaranteed in any form.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
pub fn for_each<FN: Fn(&'a mut E) + Send + Sync + Clone>(self, func: FN) {
self.for_each_with_id(move |e, _| func(e));
}
/// Runs the provided closure for each unread event in parallel, like [`for_each`](Self::for_each),
/// but additionally provides the `EventId` to the closure.
///
/// Note that the order of iteration is not guaranteed, but `EventId`s are ordered by send order.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from an event reader that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[cfg_attr(
target_arch = "wasm32",
expect(unused_mut, reason = "not mutated on this target")
)]
pub fn for_each_with_id<FN: Fn(&'a mut E, EventId<E>) + Send + Sync + Clone>(
mut self,
func: FN,
) {
#[cfg(target_arch = "wasm32")]
{
self.into_iter().for_each(|(e, i)| func(e, i));
}
#[cfg(not(target_arch = "wasm32"))]
{
let pool = bevy_tasks::ComputeTaskPool::get();
let thread_count = pool.thread_num();
if thread_count <= 1 {
return self.into_iter().for_each(|(e, i)| func(e, i));
}
let batch_size = self
.batching_strategy
.calc_batch_size(|| self.len(), thread_count);
let chunks = self.slices.map(|s| s.chunks_mut(batch_size));
pool.scope(|scope| {
for batch in chunks.into_iter().flatten() {
let func = func.clone();
scope.spawn(async move {
for event in batch {
func(&mut event.event, event.event_id);
}
});
}
});
// Events are guaranteed to be read at this point.
self.mutator.last_event_count += self.unread;
self.unread = 0;
}
}
/// Returns the number of [`Event`]s to be iterated.
pub fn len(&self) -> usize {
self.slices.iter().map(|s| s.len()).sum()
}
/// Returns [`true`] if there are no events remaining in this iterator.
pub fn is_empty(&self) -> bool {
self.slices.iter().all(|x| x.is_empty())
}
}
#[cfg(feature = "multi_threaded")]
impl<'a, E: Event> IntoIterator for EventMutParIter<'a, E> {
type IntoIter = EventMutIteratorWithId<'a, E>;
type Item = <Self::IntoIter as Iterator>::Item;
fn into_iter(self) -> Self::IntoIter {
let EventMutParIter {
mutator: reader,
slices: [a, b],
..
} = self;
let unread = a.len() + b.len();
let chain = a.iter_mut().chain(b);
EventMutIteratorWithId {
mutator: reader,
chain,
unread,
}
}
}

143
vendor/bevy_ecs/src/event/mutator.rs vendored Normal file
View File

@@ -0,0 +1,143 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::EventMutParIter;
use bevy_ecs::{
event::{Event, EventCursor, EventMutIterator, EventMutIteratorWithId, Events},
system::{Local, ResMut, SystemParam},
};
/// Mutably reads events of type `T` keeping track of which events have already been read
/// by each system allowing multiple systems to read the same events. Ideal for chains of systems
/// that all want to modify the same events.
///
/// # Usage
///
/// `EventMutators`s are usually declared as a [`SystemParam`].
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Event, Debug)]
/// pub struct MyEvent(pub u32); // Custom event type.
/// fn my_system(mut reader: EventMutator<MyEvent>) {
/// for event in reader.read() {
/// event.0 += 1;
/// println!("received event: {:?}", event);
/// }
/// }
/// ```
///
/// # Concurrency
///
/// Multiple systems with `EventMutator<T>` of the same event type can not run concurrently.
/// They also can not be executed in parallel with [`EventReader`] or [`EventWriter`].
///
/// # Clearing, Reading, and Peeking
///
/// Events are stored in a double buffered queue that switches each frame. This switch also clears the previous
/// frame's events. Events should be read each frame otherwise they may be lost. For manual control over this
/// behavior, see [`Events`].
///
/// Most of the time systems will want to use [`EventMutator::read()`]. This function creates an iterator over
/// all events that haven't been read yet by this system, marking the event as read in the process.
///
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[derive(SystemParam, Debug)]
pub struct EventMutator<'w, 's, E: Event> {
pub(super) reader: Local<'s, EventCursor<E>>,
#[system_param(validation_message = "Event not initialized")]
events: ResMut<'w, Events<E>>,
}
impl<'w, 's, E: Event> EventMutator<'w, 's, E> {
/// Iterates over the events this [`EventMutator`] has not seen yet. This updates the
/// [`EventMutator`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> EventMutIterator<'_, E> {
self.reader.read_mut(&mut self.events)
}
/// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.
pub fn read_with_id(&mut self) -> EventMutIteratorWithId<'_, E> {
self.reader.read_mut_with_id(&mut self.events)
}
/// Returns a parallel iterator over the events this [`EventMutator`] has not seen yet.
/// See also [`for_each`](super::EventParIter::for_each).
///
/// # Example
/// ```
/// # use bevy_ecs::prelude::*;
/// # use std::sync::atomic::{AtomicUsize, Ordering};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize,
/// }
///
/// #[derive(Resource, Default)]
/// struct Counter(AtomicUsize);
///
/// // setup
/// let mut world = World::new();
/// world.init_resource::<Events<MyEvent>>();
/// world.insert_resource(Counter::default());
///
/// let mut schedule = Schedule::default();
/// schedule.add_systems(|mut events: EventMutator<MyEvent>, counter: Res<Counter>| {
/// events.par_read().for_each(|MyEvent { value }| {
/// counter.0.fetch_add(*value, Ordering::Relaxed);
/// });
/// });
/// for value in 0..100 {
/// world.send_event(MyEvent { value });
/// }
/// schedule.run(&mut world);
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
/// // all events were processed
/// assert_eq!(counter.into_inner(), 4950);
/// ```
#[cfg(feature = "multi_threaded")]
pub fn par_read(&mut self) -> EventMutParIter<'_, E> {
self.reader.par_read_mut(&mut self.events)
}
/// Determines the number of events available to be read from this [`EventMutator`] without consuming any.
pub fn len(&self) -> usize {
self.reader.len(&self.events)
}
/// Returns `true` if there are no events available to read.
///
/// # Example
///
/// The following example shows a useful pattern where some behavior is triggered if new events are available.
/// [`EventMutator::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(Event)]
/// struct CollisionEvent;
///
/// fn play_collision_sound(mut events: EventMutator<CollisionEvent>) {
/// if !events.is_empty() {
/// events.clear();
/// // Play a sound
/// }
/// }
/// # bevy_ecs::system::assert_is_system(play_collision_sound);
/// ```
pub fn is_empty(&self) -> bool {
self.reader.is_empty(&self.events)
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`EventMutator::read()`] or
/// [`EventMutator::read_with_id()`] and [`EventMutator::is_empty()`] will return `true`.
///
/// For usage, see [`EventMutator::is_empty()`].
pub fn clear(&mut self) {
self.reader.clear(&self.events);
}
}

115
vendor/bevy_ecs/src/event/reader.rs vendored Normal file
View File

@@ -0,0 +1,115 @@
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::EventParIter;
use bevy_ecs::{
event::{Event, EventCursor, EventIterator, EventIteratorWithId, Events},
system::{Local, Res, SystemParam},
};
/// Reads events of type `T` in order and tracks which events have already been read.
///
/// # Concurrency
///
/// Unlike [`EventWriter<T>`], systems with `EventReader<T>` param can be executed concurrently
/// (but not concurrently with `EventWriter<T>` or `EventMutator<T>` systems for the same event type).
///
/// [`EventWriter<T>`]: super::EventWriter
#[derive(SystemParam, Debug)]
pub struct EventReader<'w, 's, E: Event> {
pub(super) reader: Local<'s, EventCursor<E>>,
#[system_param(validation_message = "Event not initialized")]
events: Res<'w, Events<E>>,
}
impl<'w, 's, E: Event> EventReader<'w, 's, E> {
/// Iterates over the events this [`EventReader`] has not seen yet. This updates the
/// [`EventReader`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> EventIterator<'_, E> {
self.reader.read(&self.events)
}
/// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.
pub fn read_with_id(&mut self) -> EventIteratorWithId<'_, E> {
self.reader.read_with_id(&self.events)
}
/// Returns a parallel iterator over the events this [`EventReader`] has not seen yet.
/// See also [`for_each`](EventParIter::for_each).
///
/// # Example
/// ```
/// # use bevy_ecs::prelude::*;
/// # use std::sync::atomic::{AtomicUsize, Ordering};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize,
/// }
///
/// #[derive(Resource, Default)]
/// struct Counter(AtomicUsize);
///
/// // setup
/// let mut world = World::new();
/// world.init_resource::<Events<MyEvent>>();
/// world.insert_resource(Counter::default());
///
/// let mut schedule = Schedule::default();
/// schedule.add_systems(|mut events: EventReader<MyEvent>, counter: Res<Counter>| {
/// events.par_read().for_each(|MyEvent { value }| {
/// counter.0.fetch_add(*value, Ordering::Relaxed);
/// });
/// });
/// for value in 0..100 {
/// world.send_event(MyEvent { value });
/// }
/// schedule.run(&mut world);
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
/// // all events were processed
/// assert_eq!(counter.into_inner(), 4950);
/// ```
#[cfg(feature = "multi_threaded")]
pub fn par_read(&mut self) -> EventParIter<'_, E> {
self.reader.par_read(&self.events)
}
/// Determines the number of events available to be read from this [`EventReader`] without consuming any.
pub fn len(&self) -> usize {
self.reader.len(&self.events)
}
/// Returns `true` if there are no events available to read.
///
/// # Example
///
/// The following example shows a useful pattern where some behavior is triggered if new events are available.
/// [`EventReader::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(Event)]
/// struct CollisionEvent;
///
/// fn play_collision_sound(mut events: EventReader<CollisionEvent>) {
/// if !events.is_empty() {
/// events.clear();
/// // Play a sound
/// }
/// }
/// # bevy_ecs::system::assert_is_system(play_collision_sound);
/// ```
pub fn is_empty(&self) -> bool {
self.reader.is_empty(&self.events)
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`EventReader::read()`] or
/// [`EventReader::read_with_id()`] and [`EventReader::is_empty()`] will return `true`.
///
/// For usage, see [`EventReader::is_empty()`].
pub fn clear(&mut self) {
self.reader.clear(&self.events);
}
}

93
vendor/bevy_ecs/src/event/registry.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
use alloc::vec::Vec;
use bevy_ecs::{
change_detection::{DetectChangesMut, MutUntyped},
component::{ComponentId, Tick},
event::{Event, Events},
resource::Resource,
world::World,
};
#[doc(hidden)]
struct RegisteredEvent {
component_id: ComponentId,
// Required to flush the secondary buffer and drop events even if left unchanged.
previously_updated: bool,
// SAFETY: The component ID and the function must be used to fetch the Events<T> resource
// of the same type initialized in `register_event`, or improper type casts will occur.
update: unsafe fn(MutUntyped),
}
/// A registry of all of the [`Events`] in the [`World`], used by [`event_update_system`](crate::event::update::event_update_system)
/// to update all of the events.
#[derive(Resource, Default)]
pub struct EventRegistry {
/// Should the events be updated?
///
/// This field is generally automatically updated by the [`signal_event_update_system`](crate::event::update::signal_event_update_system).
pub should_update: ShouldUpdateEvents,
event_updates: Vec<RegisteredEvent>,
}
/// Controls whether or not the events in an [`EventRegistry`] should be updated.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShouldUpdateEvents {
/// Without any fixed timestep, events should always be updated each frame.
#[default]
Always,
/// We need to wait until at least one pass of the fixed update schedules to update the events.
Waiting,
/// At least one pass of the fixed update schedules has occurred, and the events are ready to be updated.
Ready,
}
impl EventRegistry {
/// Registers an event type to be updated in a given [`World`]
///
/// If no instance of the [`EventRegistry`] exists in the world, this will add one - otherwise it will use
/// the existing instance.
pub fn register_event<T: Event>(world: &mut World) {
// By initializing the resource here, we can be sure that it is present,
// and receive the correct, up-to-date `ComponentId` even if it was previously removed.
let component_id = world.init_resource::<Events<T>>();
let mut registry = world.get_resource_or_init::<Self>();
registry.event_updates.push(RegisteredEvent {
component_id,
previously_updated: false,
update: |ptr| {
// SAFETY: The resource was initialized with the type Events<T>.
unsafe { ptr.with_type::<Events<T>>() }
.bypass_change_detection()
.update();
},
});
}
/// Updates all of the registered events in the World.
pub fn run_updates(&mut self, world: &mut World, last_change_tick: Tick) {
for registered_event in &mut self.event_updates {
// Bypass the type ID -> Component ID lookup with the cached component ID.
if let Some(events) = world.get_resource_mut_by_id(registered_event.component_id) {
let has_changed = events.has_changed_since(last_change_tick);
if registered_event.previously_updated || has_changed {
// SAFETY: The update function pointer is called with the resource
// fetched from the same component ID.
unsafe { (registered_event.update)(events) };
// Always set to true if the events have changed, otherwise disable running on the second invocation
// to wait for more changes.
registered_event.previously_updated =
has_changed || !registered_event.previously_updated;
}
}
}
}
/// Removes an event from the world and it's associated [`EventRegistry`].
pub fn deregister_events<T: Event>(world: &mut World) {
let component_id = world.init_resource::<Events<T>>();
let mut registry = world.get_resource_or_init::<Self>();
registry
.event_updates
.retain(|e| e.component_id != component_id);
world.remove_resource::<Events<T>>();
}
}

61
vendor/bevy_ecs/src/event/update.rs vendored Normal file
View File

@@ -0,0 +1,61 @@
use bevy_ecs::{
change_detection::Mut,
component::Tick,
event::EventRegistry,
system::{Local, Res, ResMut},
world::World,
};
use bevy_ecs_macros::SystemSet;
#[cfg(feature = "bevy_reflect")]
use core::hash::Hash;
use super::registry::ShouldUpdateEvents;
#[doc(hidden)]
#[derive(SystemSet, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventUpdates;
/// Signals the [`event_update_system`] to run after `FixedUpdate` systems.
///
/// This will change the behavior of the [`EventRegistry`] to only run after a fixed update cycle has passed.
/// Normally, this will simply run every frame.
pub fn signal_event_update_system(signal: Option<ResMut<EventRegistry>>) {
if let Some(mut registry) = signal {
registry.should_update = ShouldUpdateEvents::Ready;
}
}
/// A system that calls [`Events::update`](super::Events::update) on all registered [`Events`][super::Events] in the world.
pub fn event_update_system(world: &mut World, mut last_change_tick: Local<Tick>) {
if world.contains_resource::<EventRegistry>() {
world.resource_scope(|world, mut registry: Mut<EventRegistry>| {
registry.run_updates(world, *last_change_tick);
registry.should_update = match registry.should_update {
// If we're always updating, keep doing so.
ShouldUpdateEvents::Always => ShouldUpdateEvents::Always,
// Disable the system until signal_event_update_system runs again.
ShouldUpdateEvents::Waiting | ShouldUpdateEvents::Ready => {
ShouldUpdateEvents::Waiting
}
};
});
}
*last_change_tick = world.change_tick();
}
/// A run condition for [`event_update_system`].
///
/// If [`signal_event_update_system`] has been run at least once,
/// we will wait for it to be run again before updating the events.
///
/// Otherwise, we will always update the events.
pub fn event_update_condition(maybe_signal: Option<Res<EventRegistry>>) -> bool {
match maybe_signal {
Some(signal) => match signal.should_update {
ShouldUpdateEvents::Always | ShouldUpdateEvents::Ready => true,
ShouldUpdateEvents::Waiting => false,
},
None => true,
}
}

135
vendor/bevy_ecs/src/event/writer.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
use bevy_ecs::{
event::{Event, EventId, Events, SendBatchIds},
system::{ResMut, SystemParam},
};
/// Sends events of type `T`.
///
/// # Usage
///
/// `EventWriter`s are usually declared as a [`SystemParam`].
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Event)]
/// pub struct MyEvent; // Custom event type.
/// fn my_system(mut writer: EventWriter<MyEvent>) {
/// writer.write(MyEvent);
/// }
///
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
/// # Observers
///
/// "Buffered" Events, such as those sent directly in [`Events`] or written using [`EventWriter`], do _not_ automatically
/// trigger any [`Observer`]s watching for that event, as each [`Event`] has different requirements regarding _if_ it will
/// be triggered, and if so, _when_ it will be triggered in the schedule.
///
/// # Concurrency
///
/// `EventWriter` param has [`ResMut<Events<T>>`](Events) inside. So two systems declaring `EventWriter<T>` params
/// for the same event type won't be executed concurrently.
///
/// # Untyped events
///
/// `EventWriter` can only write events of one specific type, which must be known at compile-time.
/// This is not a problem most of the time, but you may find a situation where you cannot know
/// ahead of time every kind of event you'll need to send. In this case, you can use the "type-erased event" pattern.
///
/// ```
/// # use bevy_ecs::{prelude::*, event::Events};
/// # #[derive(Event)]
/// # pub struct MyEvent;
/// fn send_untyped(mut commands: Commands) {
/// // Send an event of a specific type without having to declare that
/// // type as a SystemParam.
/// //
/// // Effectively, we're just moving the type parameter from the /type/ to the /method/,
/// // which allows one to do all kinds of clever things with type erasure, such as sending
/// // custom events to unknown 3rd party plugins (modding API).
/// //
/// // NOTE: the event won't actually be sent until commands get applied during
/// // apply_deferred.
/// commands.queue(|w: &mut World| {
/// w.send_event(MyEvent);
/// });
/// }
/// ```
/// Note that this is considered *non-idiomatic*, and should only be used when `EventWriter` will not work.
///
/// [`Observer`]: crate::observer::Observer
#[derive(SystemParam)]
pub struct EventWriter<'w, E: Event> {
#[system_param(validation_message = "Event not initialized")]
events: ResMut<'w, Events<E>>,
}
impl<'w, E: Event> EventWriter<'w, E> {
/// Writes an `event`, which can later be read by [`EventReader`](super::EventReader)s.
/// This method returns the [ID](`EventId`) of the written `event`.
///
/// See [`Events`] for details.
#[doc(alias = "send")]
#[track_caller]
pub fn write(&mut self, event: E) -> EventId<E> {
self.events.send(event)
}
/// Sends a list of `events` all at once, which can later be read by [`EventReader`](super::EventReader)s.
/// This is more efficient than sending each event individually.
/// This method returns the [IDs](`EventId`) of the written `events`.
///
/// See [`Events`] for details.
#[doc(alias = "send_batch")]
#[track_caller]
pub fn write_batch(&mut self, events: impl IntoIterator<Item = E>) -> SendBatchIds<E> {
self.events.send_batch(events)
}
/// Writes the default value of the event. Useful when the event is an empty struct.
/// This method returns the [ID](`EventId`) of the written `event`.
///
/// See [`Events`] for details.
#[doc(alias = "send_default")]
#[track_caller]
pub fn write_default(&mut self) -> EventId<E>
where
E: Default,
{
self.events.send_default()
}
/// Sends an `event`, which can later be read by [`EventReader`](super::EventReader)s.
/// This method returns the [ID](`EventId`) of the sent `event`.
///
/// See [`Events`] for details.
#[deprecated(since = "0.16.0", note = "Use `EventWriter::write` instead.")]
#[track_caller]
pub fn send(&mut self, event: E) -> EventId<E> {
self.write(event)
}
/// Sends a list of `events` all at once, which can later be read by [`EventReader`](super::EventReader)s.
/// This is more efficient than sending each event individually.
/// This method returns the [IDs](`EventId`) of the sent `events`.
///
/// See [`Events`] for details.
#[deprecated(since = "0.16.0", note = "Use `EventWriter::write_batch` instead.")]
#[track_caller]
pub fn send_batch(&mut self, events: impl IntoIterator<Item = E>) -> SendBatchIds<E> {
self.write_batch(events)
}
/// Sends the default value of the event. Useful when the event is an empty struct.
/// This method returns the [ID](`EventId`) of the sent `event`.
///
/// See [`Events`] for details.
#[deprecated(since = "0.16.0", note = "Use `EventWriter::write_default` instead.")]
#[track_caller]
pub fn send_default(&mut self) -> EventId<E>
where
E: Default,
{
self.write_default()
}
}

1073
vendor/bevy_ecs/src/hierarchy.rs vendored Normal file

File diff suppressed because it is too large Load Diff

29
vendor/bevy_ecs/src/identifier/error.rs vendored Normal file
View File

@@ -0,0 +1,29 @@
//! Error types for [`super::Identifier`] conversions. An ID can be converted
//! to various kinds, but these can fail if they are not valid forms of those
//! kinds. The error type in this module encapsulates the various failure modes.
use core::fmt;
/// An Error type for [`super::Identifier`], mostly for providing error
/// handling for conversions of an ID to a type abstracting over the ID bits.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
pub enum IdentifierError {
/// A given ID has an invalid value for initializing to a [`crate::identifier::Identifier`].
InvalidIdentifier,
/// A given ID has an invalid configuration of bits for converting to an [`crate::entity::Entity`].
InvalidEntityId(u64),
}
impl fmt::Display for IdentifierError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidIdentifier => write!(
f,
"The given id contains a zero value high component, which is invalid"
),
Self::InvalidEntityId(_) => write!(f, "The given id is not a valid entity."),
}
}
}
impl core::error::Error for IdentifierError {}

11
vendor/bevy_ecs/src/identifier/kinds.rs vendored Normal file
View File

@@ -0,0 +1,11 @@
/// The kinds of ID that [`super::Identifier`] can represent. Each
/// variant imposes different usages of the low/high segments
/// of the ID.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum IdKind {
/// An ID variant that is compatible with [`crate::entity::Entity`].
Entity = 0,
/// A future ID variant.
Placeholder = 0b1000_0000,
}

233
vendor/bevy_ecs/src/identifier/masks.rs vendored Normal file
View File

@@ -0,0 +1,233 @@
use core::num::NonZero;
use super::kinds::IdKind;
/// Mask for extracting the value portion of a 32-bit high segment. This
/// yields 31-bits of total value, as the final bit (the most significant)
/// is reserved as a flag bit. Can be negated to extract the flag bit.
pub(crate) const HIGH_MASK: u32 = 0x7FFF_FFFF;
/// Abstraction over masks needed to extract values/components of an [`super::Identifier`].
pub(crate) struct IdentifierMask;
impl IdentifierMask {
/// Returns the low component from a `u64` value
#[inline(always)]
pub(crate) const fn get_low(value: u64) -> u32 {
// This will truncate to the lowest 32 bits
value as u32
}
/// Returns the high component from a `u64` value
#[inline(always)]
pub(crate) const fn get_high(value: u64) -> u32 {
// This will discard the lowest 32 bits
(value >> u32::BITS) as u32
}
/// Pack a low and high `u32` values into a single `u64` value.
#[inline(always)]
pub(crate) const fn pack_into_u64(low: u32, high: u32) -> u64 {
((high as u64) << u32::BITS) | (low as u64)
}
/// Pack the [`IdKind`] bits into a high segment.
#[inline(always)]
pub(crate) const fn pack_kind_into_high(value: u32, kind: IdKind) -> u32 {
value | ((kind as u32) << 24)
}
/// Extract the value component from a high segment of an [`super::Identifier`].
#[inline(always)]
pub(crate) const fn extract_value_from_high(value: u32) -> u32 {
value & HIGH_MASK
}
/// Extract the ID kind component from a high segment of an [`super::Identifier`].
#[inline(always)]
pub(crate) const fn extract_kind_from_high(value: u32) -> IdKind {
// The negated HIGH_MASK will extract just the bit we need for kind.
let kind_mask = !HIGH_MASK;
let bit = value & kind_mask;
if bit == kind_mask {
IdKind::Placeholder
} else {
IdKind::Entity
}
}
/// Offsets a masked generation value by the specified amount, wrapping to 1 instead of 0.
/// Will never be greater than [`HIGH_MASK`] or less than `1`, and increments are masked to
/// never be greater than [`HIGH_MASK`].
#[inline(always)]
pub(crate) const fn inc_masked_high_by(lhs: NonZero<u32>, rhs: u32) -> NonZero<u32> {
let lo = (lhs.get() & HIGH_MASK).wrapping_add(rhs & HIGH_MASK);
// Checks high 32 bit for whether we have overflowed 31 bits.
let overflowed = lo >> 31;
// SAFETY:
// - Adding the overflow flag will offset overflows to start at 1 instead of 0
// - The sum of `0x7FFF_FFFF` + `u32::MAX` + 1 (overflow) == `0x7FFF_FFFF`
// - If the operation doesn't overflow at 31 bits, no offsetting takes place
unsafe { NonZero::<u32>::new_unchecked(lo.wrapping_add(overflowed) & HIGH_MASK) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_u64_parts() {
// Two distinct bit patterns per low/high component
let value: u64 = 0x7FFF_FFFF_0000_000C;
assert_eq!(IdentifierMask::get_low(value), 0x0000_000C);
assert_eq!(IdentifierMask::get_high(value), 0x7FFF_FFFF);
}
#[test]
fn extract_kind() {
// All bits are ones.
let high: u32 = 0xFFFF_FFFF;
assert_eq!(
IdentifierMask::extract_kind_from_high(high),
IdKind::Placeholder
);
// Second and second to last bits are ones.
let high: u32 = 0x4000_0002;
assert_eq!(IdentifierMask::extract_kind_from_high(high), IdKind::Entity);
}
#[test]
fn extract_high_value() {
// All bits are ones.
let high: u32 = 0xFFFF_FFFF;
// Excludes the most significant bit as that is a flag bit.
assert_eq!(IdentifierMask::extract_value_from_high(high), 0x7FFF_FFFF);
// Start bit and end bit are ones.
let high: u32 = 0x8000_0001;
assert_eq!(IdentifierMask::extract_value_from_high(high), 0x0000_0001);
// Classic bit pattern.
let high: u32 = 0xDEAD_BEEF;
assert_eq!(IdentifierMask::extract_value_from_high(high), 0x5EAD_BEEF);
}
#[test]
fn pack_kind_bits() {
// All bits are ones expect the most significant bit, which is zero
let high: u32 = 0x7FFF_FFFF;
assert_eq!(
IdentifierMask::pack_kind_into_high(high, IdKind::Placeholder),
0xFFFF_FFFF
);
// Arbitrary bit pattern
let high: u32 = 0x00FF_FF00;
assert_eq!(
IdentifierMask::pack_kind_into_high(high, IdKind::Entity),
// Remains unchanged as before
0x00FF_FF00
);
// Bit pattern that almost spells a word
let high: u32 = 0x40FF_EEEE;
assert_eq!(
IdentifierMask::pack_kind_into_high(high, IdKind::Placeholder),
0xC0FF_EEEE // Milk and no sugar, please.
);
}
#[test]
fn pack_into_u64() {
let high: u32 = 0x7FFF_FFFF;
let low: u32 = 0x0000_00CC;
assert_eq!(
IdentifierMask::pack_into_u64(low, high),
0x7FFF_FFFF_0000_00CC
);
}
#[test]
fn incrementing_masked_nonzero_high_is_safe() {
// Adding from lowest value with lowest to highest increment
// No result should ever be greater than 0x7FFF_FFFF or HIGH_MASK
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, 0)
);
assert_eq!(
NonZero::<u32>::new(2).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, 1)
);
assert_eq!(
NonZero::<u32>::new(3).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, 2)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, HIGH_MASK)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MIN, u32::MAX)
);
// Adding from absolute highest value with lowest to highest increment
// No result should ever be greater than 0x7FFF_FFFF or HIGH_MASK
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, 0)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, 1)
);
assert_eq!(
NonZero::<u32>::new(2).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, 2)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, HIGH_MASK)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::MAX, u32::MAX)
);
// Adding from actual highest value with lowest to highest increment
// No result should ever be greater than 0x7FFF_FFFF or HIGH_MASK
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), 0)
);
assert_eq!(
NonZero::<u32>::MIN,
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), 1)
);
assert_eq!(
NonZero::<u32>::new(2).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), 2)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), HIGH_MASK)
);
assert_eq!(
NonZero::<u32>::new(HIGH_MASK).unwrap(),
IdentifierMask::inc_masked_high_by(NonZero::<u32>::new(HIGH_MASK).unwrap(), u32::MAX)
);
}
}

249
vendor/bevy_ecs/src/identifier/mod.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
//! A module for the unified [`Identifier`] ID struct, for use as a representation
//! of multiple types of IDs in a single, packed type. Allows for describing an [`crate::entity::Entity`],
//! or other IDs that can be packed and expressed within a `u64` sized type.
//! [`Identifier`]s cannot be created directly, only able to be converted from other
//! compatible IDs.
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use self::{error::IdentifierError, kinds::IdKind, masks::IdentifierMask};
use core::{hash::Hash, num::NonZero};
pub mod error;
pub(crate) mod kinds;
pub(crate) mod masks;
/// A unified identifier for all entity and similar IDs.
///
/// Has the same size as a `u64` integer, but the layout is split between a 32-bit low
/// segment, a 31-bit high segment, and the significant bit reserved as type flags to denote
/// entity kinds.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Hash, PartialEq, Clone))]
// Alignment repr necessary to allow LLVM to better output
// optimized codegen for `to_bits`, `PartialEq` and `Ord`.
#[repr(C, align(8))]
pub struct Identifier {
// Do not reorder the fields here. The ordering is explicitly used by repr(C)
// to make this struct equivalent to a u64.
#[cfg(target_endian = "little")]
low: u32,
high: NonZero<u32>,
#[cfg(target_endian = "big")]
low: u32,
}
impl Identifier {
/// Construct a new [`Identifier`]. The `high` parameter is masked with the
/// `kind` so to pack the high value and bit flags into the same field.
#[inline(always)]
pub const fn new(low: u32, high: u32, kind: IdKind) -> Result<Self, IdentifierError> {
// the high bits are masked to cut off the most significant bit
// as these are used for the type flags. This means that the high
// portion is only 31 bits, but this still provides 2^31
// values/kinds/ids that can be stored in this segment.
let masked_value = IdentifierMask::extract_value_from_high(high);
let packed_high = IdentifierMask::pack_kind_into_high(masked_value, kind);
// If the packed high component ends up being zero, that means that we tried
// to initialize an Identifier into an invalid state.
if packed_high == 0 {
Err(IdentifierError::InvalidIdentifier)
} else {
// SAFETY: The high value has been checked to ensure it is never
// zero.
unsafe {
Ok(Self {
low,
high: NonZero::<u32>::new_unchecked(packed_high),
})
}
}
}
/// Returns the value of the low segment of the [`Identifier`].
#[inline(always)]
pub const fn low(self) -> u32 {
self.low
}
/// Returns the value of the high segment of the [`Identifier`]. This
/// does not apply any masking.
#[inline(always)]
pub const fn high(self) -> NonZero<u32> {
self.high
}
/// Returns the masked value of the high segment of the [`Identifier`].
/// Does not include the flag bits.
#[inline(always)]
pub const fn masked_high(self) -> u32 {
IdentifierMask::extract_value_from_high(self.high.get())
}
/// Returns the kind of [`Identifier`] from the high segment.
#[inline(always)]
pub const fn kind(self) -> IdKind {
IdentifierMask::extract_kind_from_high(self.high.get())
}
/// Convert the [`Identifier`] into a `u64`.
#[inline(always)]
pub const fn to_bits(self) -> u64 {
IdentifierMask::pack_into_u64(self.low, self.high.get())
}
/// Convert a `u64` into an [`Identifier`].
///
/// # Panics
///
/// This method will likely panic if given `u64` values that did not come from [`Identifier::to_bits`].
#[inline(always)]
pub const fn from_bits(value: u64) -> Self {
let id = Self::try_from_bits(value);
match id {
Ok(id) => id,
Err(_) => panic!("Attempted to initialize invalid bits as an id"),
}
}
/// Convert a `u64` into an [`Identifier`].
///
/// This method is the fallible counterpart to [`Identifier::from_bits`].
#[inline(always)]
pub const fn try_from_bits(value: u64) -> Result<Self, IdentifierError> {
let high = NonZero::<u32>::new(IdentifierMask::get_high(value));
match high {
Some(high) => Ok(Self {
low: IdentifierMask::get_low(value),
high,
}),
None => Err(IdentifierError::InvalidIdentifier),
}
}
}
// By not short-circuiting in comparisons, we get better codegen.
// See <https://github.com/rust-lang/rust/issues/117800>
impl PartialEq for Identifier {
#[inline]
fn eq(&self, other: &Self) -> bool {
// By using `to_bits`, the codegen can be optimized out even
// further potentially. Relies on the correct alignment/field
// order of `Entity`.
self.to_bits() == other.to_bits()
}
}
impl Eq for Identifier {}
// The derive macro codegen output is not optimal and can't be optimized as well
// by the compiler. This impl resolves the issue of non-optimal codegen by relying
// on comparing against the bit representation of `Entity` instead of comparing
// the fields. The result is then LLVM is able to optimize the codegen for Entity
// far beyond what the derive macro can.
// See <https://github.com/rust-lang/rust/issues/106107>
impl PartialOrd for Identifier {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
// Make use of our `Ord` impl to ensure optimal codegen output
Some(self.cmp(other))
}
}
// The derive macro codegen output is not optimal and can't be optimized as well
// by the compiler. This impl resolves the issue of non-optimal codegen by relying
// on comparing against the bit representation of `Entity` instead of comparing
// the fields. The result is then LLVM is able to optimize the codegen for Entity
// far beyond what the derive macro can.
// See <https://github.com/rust-lang/rust/issues/106107>
impl Ord for Identifier {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
// This will result in better codegen for ordering comparisons, plus
// avoids pitfalls with regards to macro codegen relying on property
// position when we want to compare against the bit representation.
self.to_bits().cmp(&other.to_bits())
}
}
impl Hash for Identifier {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.to_bits().hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn id_construction() {
let id = Identifier::new(12, 55, IdKind::Entity).unwrap();
assert_eq!(id.low(), 12);
assert_eq!(id.high().get(), 55);
assert_eq!(
IdentifierMask::extract_kind_from_high(id.high().get()),
IdKind::Entity
);
}
#[test]
fn from_bits() {
// This high value should correspond to the max high() value
// and also Entity flag.
let high = 0x7FFFFFFF;
let low = 0xC;
let bits: u64 = (high << u32::BITS) | low;
let id = Identifier::try_from_bits(bits).unwrap();
assert_eq!(id.to_bits(), 0x7FFFFFFF0000000C);
assert_eq!(id.low(), low as u32);
assert_eq!(id.high().get(), 0x7FFFFFFF);
assert_eq!(
IdentifierMask::extract_kind_from_high(id.high().get()),
IdKind::Entity
);
}
#[rustfmt::skip]
#[test]
#[expect(
clippy::nonminimal_bool,
reason = "This intentionally tests all possible comparison operators as separate functions; thus, we don't want to rewrite these comparisons to use different operators."
)]
fn id_comparison() {
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() == Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Placeholder).unwrap() == Identifier::new(123, 456, IdKind::Placeholder).unwrap());
assert!(Identifier::new(123, 789, IdKind::Entity).unwrap() != Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() != Identifier::new(123, 789, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() != Identifier::new(456, 123, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() != Identifier::new(123, 456, IdKind::Placeholder).unwrap());
// ordering is by flag then high then by low
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() >= Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(Identifier::new(123, 456, IdKind::Entity).unwrap() <= Identifier::new(123, 456, IdKind::Entity).unwrap());
assert!(!(Identifier::new(123, 456, IdKind::Entity).unwrap() < Identifier::new(123, 456, IdKind::Entity).unwrap()));
assert!(!(Identifier::new(123, 456, IdKind::Entity).unwrap() > Identifier::new(123, 456, IdKind::Entity).unwrap()));
assert!(Identifier::new(9, 1, IdKind::Entity).unwrap() < Identifier::new(1, 9, IdKind::Entity).unwrap());
assert!(Identifier::new(1, 9, IdKind::Entity).unwrap() > Identifier::new(9, 1, IdKind::Entity).unwrap());
assert!(Identifier::new(9, 1, IdKind::Entity).unwrap() < Identifier::new(9, 1, IdKind::Placeholder).unwrap());
assert!(Identifier::new(1, 9, IdKind::Placeholder).unwrap() > Identifier::new(1, 9, IdKind::Entity).unwrap());
assert!(Identifier::new(1, 1, IdKind::Entity).unwrap() < Identifier::new(2, 1, IdKind::Entity).unwrap());
assert!(Identifier::new(1, 1, IdKind::Entity).unwrap() <= Identifier::new(2, 1, IdKind::Entity).unwrap());
assert!(Identifier::new(2, 2, IdKind::Entity).unwrap() > Identifier::new(1, 2, IdKind::Entity).unwrap());
assert!(Identifier::new(2, 2, IdKind::Entity).unwrap() >= Identifier::new(1, 2, IdKind::Entity).unwrap());
}
}

280
vendor/bevy_ecs/src/intern.rs vendored Normal file
View File

@@ -0,0 +1,280 @@
//! Provides types used to statically intern immutable values.
//!
//! Interning is a pattern used to save memory by deduplicating identical values,
//! speed up code by shrinking the stack size of large types,
//! and make comparisons for any type as fast as integers.
use alloc::{borrow::ToOwned, boxed::Box};
use bevy_platform::{
collections::HashSet,
hash::FixedHasher,
sync::{PoisonError, RwLock},
};
use core::{fmt::Debug, hash::Hash, ops::Deref};
/// An interned value. Will stay valid until the end of the program and will not drop.
///
/// For details on interning, see [the module level docs](self).
///
/// # Comparisons
///
/// Interned values use reference equality, meaning they implement [`Eq`]
/// and [`Hash`] regardless of whether `T` implements these traits.
/// Two interned values are only guaranteed to compare equal if they were interned using
/// the same [`Interner`] instance.
// NOTE: This type must NEVER implement Borrow since it does not obey that trait's invariants.
/// ```
/// # use bevy_ecs::intern::*;
/// #[derive(PartialEq, Eq, Hash, Debug)]
/// struct Value(i32);
/// impl Internable for Value {
/// // ...
/// # fn leak(&self) -> &'static Self { Box::leak(Box::new(Value(self.0))) }
/// # fn ref_eq(&self, other: &Self) -> bool { std::ptr::eq(self, other ) }
/// # fn ref_hash<H: std::hash::Hasher>(&self, state: &mut H) { std::ptr::hash(self, state); }
/// }
/// let interner_1 = Interner::new();
/// let interner_2 = Interner::new();
/// // Even though both values are identical, their interned forms do not
/// // compare equal as they use different interner instances.
/// assert_ne!(interner_1.intern(&Value(42)), interner_2.intern(&Value(42)));
/// ```
pub struct Interned<T: ?Sized + 'static>(pub &'static T);
impl<T: ?Sized> Deref for Interned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<T: ?Sized> Clone for Interned<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Interned<T> {}
// Two Interned<T> should only be equal if they are clones from the same instance.
// Therefore, we only use the pointer to determine equality.
impl<T: ?Sized + Internable> PartialEq for Interned<T> {
fn eq(&self, other: &Self) -> bool {
self.0.ref_eq(other.0)
}
}
impl<T: ?Sized + Internable> Eq for Interned<T> {}
// Important: This must be kept in sync with the PartialEq/Eq implementation
impl<T: ?Sized + Internable> Hash for Interned<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.0.ref_hash(state);
}
}
impl<T: ?Sized + Debug> Debug for Interned<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<T> From<&Interned<T>> for Interned<T> {
fn from(value: &Interned<T>) -> Self {
*value
}
}
/// A trait for internable values.
///
/// This is used by [`Interner<T>`] to create static references for values that are interned.
pub trait Internable: Hash + Eq {
/// Creates a static reference to `self`, possibly leaking memory.
fn leak(&self) -> &'static Self;
/// Returns `true` if the two references point to the same value.
fn ref_eq(&self, other: &Self) -> bool;
/// Feeds the reference to the hasher.
fn ref_hash<H: core::hash::Hasher>(&self, state: &mut H);
}
impl Internable for str {
fn leak(&self) -> &'static Self {
let str = self.to_owned().into_boxed_str();
Box::leak(str)
}
fn ref_eq(&self, other: &Self) -> bool {
self.as_ptr() == other.as_ptr() && self.len() == other.len()
}
fn ref_hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.len().hash(state);
self.as_ptr().hash(state);
}
}
/// A thread-safe interner which can be used to create [`Interned<T>`] from `&T`
///
/// For details on interning, see [the module level docs](self).
///
/// The implementation ensures that two equal values return two equal [`Interned<T>`] values.
///
/// To use an [`Interner<T>`], `T` must implement [`Internable`].
pub struct Interner<T: ?Sized + 'static>(RwLock<HashSet<&'static T>>);
impl<T: ?Sized> Interner<T> {
/// Creates a new empty interner
pub const fn new() -> Self {
Self(RwLock::new(HashSet::with_hasher(FixedHasher)))
}
}
impl<T: Internable + ?Sized> Interner<T> {
/// Return the [`Interned<T>`] corresponding to `value`.
///
/// If it is called the first time for `value`, it will possibly leak the value and return an
/// [`Interned<T>`] using the obtained static reference. Subsequent calls for the same `value`
/// will return [`Interned<T>`] using the same static reference.
pub fn intern(&self, value: &T) -> Interned<T> {
{
let set = self.0.read().unwrap_or_else(PoisonError::into_inner);
if let Some(value) = set.get(value) {
return Interned(*value);
}
}
{
let mut set = self.0.write().unwrap_or_else(PoisonError::into_inner);
if let Some(value) = set.get(value) {
Interned(*value)
} else {
let leaked = value.leak();
set.insert(leaked);
Interned(leaked)
}
}
}
}
impl<T: ?Sized> Default for Interner<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use alloc::{boxed::Box, string::ToString};
use bevy_platform::hash::FixedHasher;
use core::hash::{BuildHasher, Hash, Hasher};
use crate::intern::{Internable, Interned, Interner};
#[test]
fn zero_sized_type() {
#[derive(PartialEq, Eq, Hash, Debug)]
pub struct A;
impl Internable for A {
fn leak(&self) -> &'static Self {
&A
}
fn ref_eq(&self, other: &Self) -> bool {
core::ptr::eq(self, other)
}
fn ref_hash<H: Hasher>(&self, state: &mut H) {
core::ptr::hash(self, state);
}
}
let interner = Interner::default();
let x = interner.intern(&A);
let y = interner.intern(&A);
assert_eq!(x, y);
}
#[test]
fn fieldless_enum() {
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub enum A {
X,
Y,
}
impl Internable for A {
fn leak(&self) -> &'static Self {
match self {
A::X => &A::X,
A::Y => &A::Y,
}
}
fn ref_eq(&self, other: &Self) -> bool {
core::ptr::eq(self, other)
}
fn ref_hash<H: Hasher>(&self, state: &mut H) {
core::ptr::hash(self, state);
}
}
let interner = Interner::default();
let x = interner.intern(&A::X);
let y = interner.intern(&A::Y);
assert_ne!(x, y);
}
#[test]
fn static_sub_strings() {
let str = "ABC ABC";
let a = &str[0..3];
let b = &str[4..7];
// Same contents
assert_eq!(a, b);
let x = Interned(a);
let y = Interned(b);
// Different pointers
assert_ne!(x, y);
let interner = Interner::default();
let x = interner.intern(a);
let y = interner.intern(b);
// Same pointers returned by interner
assert_eq!(x, y);
}
#[test]
fn same_interned_instance() {
let a = Interned("A");
let b = a;
assert_eq!(a, b);
let hash_a = FixedHasher.hash_one(a);
let hash_b = FixedHasher.hash_one(b);
assert_eq!(hash_a, hash_b);
}
#[test]
fn same_interned_content() {
let a = Interned::<str>(Box::leak(Box::new("A".to_string())));
let b = Interned::<str>(Box::leak(Box::new("A".to_string())));
assert_ne!(a, b);
}
#[test]
fn different_interned_content() {
let a = Interned::<str>("A");
let b = Interned::<str>("B");
assert_ne!(a, b);
}
}

210
vendor/bevy_ecs/src/label.rs vendored Normal file
View File

@@ -0,0 +1,210 @@
//! Traits used by label implementations
use core::{
any::Any,
hash::{Hash, Hasher},
};
// Re-exported for use within `define_label!`
#[doc(hidden)]
pub use alloc::boxed::Box;
/// An object safe version of [`Eq`]. This trait is automatically implemented
/// for any `'static` type that implements `Eq`.
pub trait DynEq: Any {
/// Casts the type to `dyn Any`.
fn as_any(&self) -> &dyn Any;
/// This method tests for `self` and `other` values to be equal.
///
/// Implementers should avoid returning `true` when the underlying types are
/// not the same.
fn dyn_eq(&self, other: &dyn DynEq) -> bool;
}
// Tests that this trait is dyn-compatible
const _: Option<Box<dyn DynEq>> = None;
impl<T> DynEq for T
where
T: Any + Eq,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_eq(&self, other: &dyn DynEq) -> bool {
if let Some(other) = other.as_any().downcast_ref::<T>() {
return self == other;
}
false
}
}
/// An object safe version of [`Hash`]. This trait is automatically implemented
/// for any `'static` type that implements `Hash`.
pub trait DynHash: DynEq {
/// Casts the type to `dyn Any`.
fn as_dyn_eq(&self) -> &dyn DynEq;
/// Feeds this value into the given [`Hasher`].
fn dyn_hash(&self, state: &mut dyn Hasher);
}
// Tests that this trait is dyn-compatible
const _: Option<Box<dyn DynHash>> = None;
impl<T> DynHash for T
where
T: DynEq + Hash,
{
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
T::hash(self, &mut state);
self.type_id().hash(&mut state);
}
}
/// Macro to define a new label trait
///
/// # Example
///
/// ```
/// # use bevy_ecs::define_label;
/// define_label!(
/// /// Documentation of label trait
/// MyNewLabelTrait,
/// MY_NEW_LABEL_TRAIT_INTERNER
/// );
///
/// define_label!(
/// /// Documentation of another label trait
/// MyNewExtendedLabelTrait,
/// MY_NEW_EXTENDED_LABEL_TRAIT_INTERNER,
/// extra_methods: {
/// // Extra methods for the trait can be defined here
/// fn additional_method(&self) -> i32;
/// },
/// extra_methods_impl: {
/// // Implementation of the extra methods for Interned<dyn MyNewExtendedLabelTrait>
/// fn additional_method(&self) -> i32 {
/// 0
/// }
/// }
/// );
/// ```
#[macro_export]
macro_rules! define_label {
(
$(#[$label_attr:meta])*
$label_trait_name:ident,
$interner_name:ident
) => {
$crate::define_label!(
$(#[$label_attr])*
$label_trait_name,
$interner_name,
extra_methods: {},
extra_methods_impl: {}
);
};
(
$(#[$label_attr:meta])*
$label_trait_name:ident,
$interner_name:ident,
extra_methods: { $($trait_extra_methods:tt)* },
extra_methods_impl: { $($interned_extra_methods_impl:tt)* }
) => {
$(#[$label_attr])*
pub trait $label_trait_name: 'static + Send + Sync + ::core::fmt::Debug {
$($trait_extra_methods)*
/// Clones this `
#[doc = stringify!($label_trait_name)]
///`.
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name>;
/// Casts this value to a form where it can be compared with other type-erased values.
fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq;
/// Feeds this value into the given [`Hasher`].
fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher);
/// Returns an [`Interned`] value corresponding to `self`.
fn intern(&self) -> $crate::intern::Interned<dyn $label_trait_name>
where Self: Sized {
$interner_name.intern(self)
}
}
#[diagnostic::do_not_recommend]
impl $label_trait_name for $crate::intern::Interned<dyn $label_trait_name> {
$($interned_extra_methods_impl)*
fn dyn_clone(&self) -> $crate::label::Box<dyn $label_trait_name> {
(**self).dyn_clone()
}
/// Casts this value to a form where it can be compared with other type-erased values.
fn as_dyn_eq(&self) -> &dyn $crate::label::DynEq {
(**self).as_dyn_eq()
}
fn dyn_hash(&self, state: &mut dyn ::core::hash::Hasher) {
(**self).dyn_hash(state);
}
fn intern(&self) -> Self {
*self
}
}
impl PartialEq for dyn $label_trait_name {
fn eq(&self, other: &Self) -> bool {
self.as_dyn_eq().dyn_eq(other.as_dyn_eq())
}
}
impl Eq for dyn $label_trait_name {}
impl ::core::hash::Hash for dyn $label_trait_name {
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
self.dyn_hash(state);
}
}
impl $crate::intern::Internable for dyn $label_trait_name {
fn leak(&self) -> &'static Self {
$crate::label::Box::leak(self.dyn_clone())
}
fn ref_eq(&self, other: &Self) -> bool {
use ::core::ptr;
// Test that both the type id and pointer address are equivalent.
self.as_dyn_eq().type_id() == other.as_dyn_eq().type_id()
&& ptr::addr_eq(ptr::from_ref::<Self>(self), ptr::from_ref::<Self>(other))
}
fn ref_hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
use ::core::{hash::Hash, ptr};
// Hash the type id...
self.as_dyn_eq().type_id().hash(state);
// ...and the pointer address.
// Cast to a unit `()` first to discard any pointer metadata.
ptr::from_ref::<Self>(self).cast::<()>().hash(state);
}
}
static $interner_name: $crate::intern::Interner<dyn $label_trait_name> =
$crate::intern::Interner::new();
};
}

2846
vendor/bevy_ecs/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

296
vendor/bevy_ecs/src/name.rs vendored Normal file
View File

@@ -0,0 +1,296 @@
//! Provides the [`Name`] [`Component`], used for identifying an [`Entity`].
use crate::{component::Component, entity::Entity, query::QueryData};
use alloc::{
borrow::{Cow, ToOwned},
string::String,
};
use bevy_platform::hash::FixedHasher;
use core::{
hash::{BuildHasher, Hash, Hasher},
ops::Deref,
};
#[cfg(feature = "serialize")]
use {
alloc::string::ToString,
serde::{
de::{Error, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
},
};
#[cfg(feature = "bevy_reflect")]
use {
crate::reflect::ReflectComponent,
bevy_reflect::{std_traits::ReflectDefault, Reflect},
};
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
/// Component used to identify an entity. Stores a hash for faster comparisons.
///
/// The hash is eagerly re-computed upon each update to the name.
///
/// [`Name`] should not be treated as a globally unique identifier for entities,
/// as multiple entities can have the same name. [`Entity`] should be
/// used instead as the default unique identifier.
#[derive(Component, Clone)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Component, Default, Debug, Clone, Hash, PartialEq)
)]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Deserialize, Serialize)
)]
pub struct Name {
hash: u64, // Won't be serialized
name: Cow<'static, str>,
}
impl Default for Name {
fn default() -> Self {
Name::new("")
}
}
impl Name {
/// Creates a new [`Name`] from any string-like type.
///
/// The internal hash will be computed immediately.
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
let name = name.into();
let mut name = Name { name, hash: 0 };
name.update_hash();
name
}
/// Sets the entity's name.
///
/// The internal hash will be re-computed.
#[inline(always)]
pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
*self = Name::new(name);
}
/// Updates the name of the entity in place.
///
/// This will allocate a new string if the name was previously
/// created from a borrow.
#[inline(always)]
pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
f(self.name.to_mut());
self.update_hash();
}
/// Gets the name of the entity as a `&str`.
#[inline(always)]
pub fn as_str(&self) -> &str {
&self.name
}
fn update_hash(&mut self) {
self.hash = FixedHasher.hash_one(&self.name);
}
}
impl core::fmt::Display for Name {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(&self.name, f)
}
}
impl core::fmt::Debug for Name {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.name, f)
}
}
/// Convenient query for giving a human friendly name to an entity.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component)] pub struct Score(f32);
/// fn increment_score(mut scores: Query<(NameOrEntity, &mut Score)>) {
/// for (name, mut score) in &mut scores {
/// score.0 += 1.0;
/// if score.0.is_nan() {
/// log::error!("Score for {name} is invalid");
/// }
/// }
/// }
/// # bevy_ecs::system::assert_is_system(increment_score);
/// ```
///
/// # Implementation
///
/// The `Display` impl for `NameOrEntity` returns the `Name` where there is one
/// or {index}v{generation} for entities without one.
#[derive(QueryData)]
#[query_data(derive(Debug))]
pub struct NameOrEntity {
/// A [`Name`] that the entity might have that is displayed if available.
pub name: Option<&'static Name>,
/// The unique identifier of the entity as a fallback.
pub entity: Entity,
}
impl<'a> core::fmt::Display for NameOrEntityItem<'a> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self.name {
Some(name) => core::fmt::Display::fmt(name, f),
None => core::fmt::Display::fmt(&self.entity, f),
}
}
}
// Conversions from strings
impl From<&str> for Name {
#[inline(always)]
fn from(name: &str) -> Self {
Name::new(name.to_owned())
}
}
impl From<String> for Name {
#[inline(always)]
fn from(name: String) -> Self {
Name::new(name)
}
}
// Conversions to strings
impl AsRef<str> for Name {
#[inline(always)]
fn as_ref(&self) -> &str {
&self.name
}
}
impl From<&Name> for String {
#[inline(always)]
fn from(val: &Name) -> String {
val.as_str().to_owned()
}
}
impl From<Name> for String {
#[inline(always)]
fn from(val: Name) -> String {
val.name.into_owned()
}
}
impl Hash for Name {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for Name {
fn eq(&self, other: &Self) -> bool {
if self.hash != other.hash {
// Makes the common case of two strings not been equal very fast
return false;
}
self.name.eq(&other.name)
}
}
impl Eq for Name {}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.name.cmp(&other.name)
}
}
impl Deref for Name {
type Target = str;
fn deref(&self) -> &Self::Target {
self.name.as_ref()
}
}
#[cfg(feature = "serialize")]
impl Serialize for Name {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
#[cfg(feature = "serialize")]
impl<'de> Deserialize<'de> for Name {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(NameVisitor)
}
}
#[cfg(feature = "serialize")]
struct NameVisitor;
#[cfg(feature = "serialize")]
impl<'de> Visitor<'de> for NameVisitor {
type Value = Name;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str(core::any::type_name::<Name>())
}
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(Name::new(v.to_string()))
}
fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
Ok(Name::new(v))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::world::World;
use alloc::string::ToString;
#[test]
fn test_display_of_debug_name() {
let mut world = World::new();
let e1 = world.spawn_empty().id();
let name = Name::new("MyName");
let e2 = world.spawn(name.clone()).id();
let mut query = world.query::<NameOrEntity>();
let d1 = query.get(&world, e1).unwrap();
let d2 = query.get(&world, e2).unwrap();
// NameOrEntity Display for entities without a Name should be {index}v{generation}
assert_eq!(d1.to_string(), "0v1");
// NameOrEntity Display for entities with a Name should be the Name
assert_eq!(d2.to_string(), "MyName");
}
}
#[cfg(all(test, feature = "serialize"))]
mod serde_tests {
use super::Name;
use serde_test::{assert_tokens, Token};
#[test]
fn test_serde_name() {
let name = Name::new("MyComponent");
assert_tokens(&name, &[Token::String("MyComponent")]);
}
}

39
vendor/bevy_ecs/src/never.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
//! A workaround for the `!` type in stable Rust.
//!
//! This approach is taken from the [`never_say_never`] crate,
//! reimplemented here to avoid adding a new dependency.
//!
//! This module exists due to a change in [never type fallback inference] in the Rust 2024 edition.
//! This caused failures in `bevy_ecs`'s traits which are implemented for functions
//! (like [`System`](crate::system::System)) when working with panicking closures.
//!
//! Note that using this hack is not recommended in general;
//! by doing so you are knowingly opting out of rustc's stability guarantees.
//! Code that compiles due to this hack may break in future versions of Rust.
//!
//! Please read [issue #18778](https://github.com/bevyengine/bevy/issues/18778) for an explanation of why
//! Bevy has chosen to use this workaround.
//!
//! [`never_say_never`]: https://crates.io/crates/never_say_never
//! [never type fallback inference]: https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html
mod fn_ret {
/// A helper trait for naming the ! type.
#[doc(hidden)]
pub trait FnRet {
/// The return type of the function.
type Output;
}
/// This blanket implementation allows us to name the never type,
/// by using the associated type of this trait for `fn() -> !`.
impl<R> FnRet for fn() -> R {
type Output = R;
}
}
/// A hacky type alias for the `!` (never) type.
///
/// This knowingly opts out of rustc's stability guarantees.
/// Read the module documentation carefully before using this!
pub type Never = <fn() -> ! as fn_ret::FnRet>::Output;

View File

@@ -0,0 +1,144 @@
use crate::{
component::{
Component, ComponentCloneBehavior, ComponentHook, HookContext, Mutable, StorageType,
},
entity::{ComponentCloneCtx, Entity, EntityClonerBuilder, EntityMapper, SourceComponent},
observer::ObserverState,
world::World,
};
use alloc::vec::Vec;
/// Tracks a list of entity observers for the [`Entity`] [`ObservedBy`] is added to.
#[derive(Default)]
pub struct ObservedBy(pub(crate) Vec<Entity>);
impl Component for ObservedBy {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
type Mutability = Mutable;
fn on_remove() -> Option<ComponentHook> {
Some(|mut world, HookContext { entity, .. }| {
let observed_by = {
let mut component = world.get_mut::<ObservedBy>(entity).unwrap();
core::mem::take(&mut component.0)
};
for e in observed_by {
let (total_entities, despawned_watched_entities) = {
let Ok(mut entity_mut) = world.get_entity_mut(e) else {
continue;
};
let Some(mut state) = entity_mut.get_mut::<ObserverState>() else {
continue;
};
state.despawned_watched_entities += 1;
(
state.descriptor.entities.len(),
state.despawned_watched_entities as usize,
)
};
// Despawn Observer if it has no more active sources.
if total_entities == despawned_watched_entities {
world.commands().entity(e).despawn();
}
}
})
}
fn clone_behavior() -> ComponentCloneBehavior {
ComponentCloneBehavior::Ignore
}
}
impl EntityClonerBuilder<'_> {
/// Sets the option to automatically add cloned entities to the observers targeting source entity.
pub fn add_observers(&mut self, add_observers: bool) -> &mut Self {
if add_observers {
self.override_clone_behavior::<ObservedBy>(ComponentCloneBehavior::Custom(
component_clone_observed_by,
))
} else {
self.remove_clone_behavior_override::<ObservedBy>()
}
}
}
fn component_clone_observed_by(_source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
let target = ctx.target();
let source = ctx.source();
ctx.queue_deferred(move |world: &mut World, _mapper: &mut dyn EntityMapper| {
let observed_by = world
.get::<ObservedBy>(source)
.map(|observed_by| observed_by.0.clone())
.expect("Source entity must have ObservedBy");
world
.entity_mut(target)
.insert(ObservedBy(observed_by.clone()));
for observer in &observed_by {
let mut observer_state = world
.get_mut::<ObserverState>(*observer)
.expect("Source observer entity must have ObserverState");
observer_state.descriptor.entities.push(target);
let event_types = observer_state.descriptor.events.clone();
let components = observer_state.descriptor.components.clone();
for event_type in event_types {
let observers = world.observers.get_observers(event_type);
if components.is_empty() {
if let Some(map) = observers.entity_observers.get(&source).cloned() {
observers.entity_observers.insert(target, map);
}
} else {
for component in &components {
let Some(observers) = observers.component_observers.get_mut(component)
else {
continue;
};
if let Some(map) = observers.entity_map.get(&source).cloned() {
observers.entity_map.insert(target, map);
}
}
}
}
}
});
}
#[cfg(test)]
mod tests {
use crate::{
entity::EntityCloner, event::Event, observer::Trigger, resource::Resource, system::ResMut,
world::World,
};
#[derive(Resource, Default)]
struct Num(usize);
#[derive(Event)]
struct E;
#[test]
fn clone_entity_with_observer() {
let mut world = World::default();
world.init_resource::<Num>();
let e = world
.spawn_empty()
.observe(|_: Trigger<E>, mut res: ResMut<Num>| res.0 += 1)
.id();
world.flush();
world.trigger_targets(E, e);
let e_clone = world.spawn_empty().id();
EntityCloner::build(&mut world)
.add_observers(true)
.clone_entity(e, e_clone);
world.trigger_targets(E, [e, e_clone]);
assert_eq!(world.resource::<Num>().0, 3);
}
}

1789
vendor/bevy_ecs/src/observer/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

532
vendor/bevy_ecs/src/observer/runner.rs vendored Normal file
View File

@@ -0,0 +1,532 @@
use alloc::{boxed::Box, vec, vec::Vec};
use core::any::Any;
use crate::{
component::{ComponentHook, ComponentId, HookContext, Mutable, StorageType},
error::{default_error_handler, ErrorContext},
observer::{ObserverDescriptor, ObserverTrigger},
prelude::*,
query::DebugCheckedUnwrap,
system::{IntoObserverSystem, ObserverSystem},
world::DeferredWorld,
};
use bevy_ptr::PtrMut;
/// Contains [`Observer`] information. This defines how a given observer behaves. It is the
/// "source of truth" for a given observer entity's behavior.
pub struct ObserverState {
pub(crate) descriptor: ObserverDescriptor,
pub(crate) runner: ObserverRunner,
pub(crate) last_trigger_id: u32,
pub(crate) despawned_watched_entities: u32,
}
impl Default for ObserverState {
fn default() -> Self {
Self {
runner: |_, _, _, _| {},
last_trigger_id: 0,
despawned_watched_entities: 0,
descriptor: Default::default(),
}
}
}
impl ObserverState {
/// Observe the given `event`. This will cause the [`Observer`] to run whenever an event with the given [`ComponentId`]
/// is triggered.
pub fn with_event(mut self, event: ComponentId) -> Self {
self.descriptor.events.push(event);
self
}
/// Observe the given event list. This will cause the [`Observer`] to run whenever an event with any of the given [`ComponentId`]s
/// is triggered.
pub fn with_events(mut self, events: impl IntoIterator<Item = ComponentId>) -> Self {
self.descriptor.events.extend(events);
self
}
/// Observe the given [`Entity`] list. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for any [`Entity`] target in the list.
pub fn with_entities(mut self, entities: impl IntoIterator<Item = Entity>) -> Self {
self.descriptor.entities.extend(entities);
self
}
/// Observe the given [`ComponentId`] list. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for any [`ComponentId`] target in the list.
pub fn with_components(mut self, components: impl IntoIterator<Item = ComponentId>) -> Self {
self.descriptor.components.extend(components);
self
}
}
impl Component for ObserverState {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
type Mutability = Mutable;
fn on_add() -> Option<ComponentHook> {
Some(|mut world, HookContext { entity, .. }| {
world.commands().queue(move |world: &mut World| {
world.register_observer(entity);
});
})
}
fn on_remove() -> Option<ComponentHook> {
Some(|mut world, HookContext { entity, .. }| {
let descriptor = core::mem::take(
&mut world
.entity_mut(entity)
.get_mut::<ObserverState>()
.unwrap()
.as_mut()
.descriptor,
);
world.commands().queue(move |world: &mut World| {
world.unregister_observer(entity, descriptor);
});
})
}
}
/// Type for function that is run when an observer is triggered.
///
/// Typically refers to the default runner that runs the system stored in the associated [`Observer`] component,
/// but can be overridden for custom behavior.
pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate: &mut bool);
/// An [`Observer`] system. Add this [`Component`] to an [`Entity`] to turn it into an "observer".
///
/// Observers listen for a "trigger" of a specific [`Event`]. Events are triggered by calling [`World::trigger`] or [`World::trigger_targets`].
///
/// Note that "buffered" events sent using [`EventReader`] and [`EventWriter`] are _not_ automatically triggered. They must be triggered at a specific
/// point in the schedule.
///
/// # Usage
///
/// The simplest usage
/// of the observer pattern looks like this:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// #[derive(Event)]
/// struct Speak {
/// message: String,
/// }
///
/// world.add_observer(|trigger: Trigger<Speak>| {
/// println!("{}", trigger.event().message);
/// });
///
/// // Observers currently require a flush() to be registered. In the context of schedules,
/// // this will generally be done for you.
/// world.flush();
///
/// world.trigger(Speak {
/// message: "Hello!".into(),
/// });
/// ```
///
/// Notice that we used [`World::add_observer`]. This is just a shorthand for spawning an [`Observer`] manually:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct Speak;
/// // These are functionally the same:
/// world.add_observer(|trigger: Trigger<Speak>| {});
/// world.spawn(Observer::new(|trigger: Trigger<Speak>| {}));
/// ```
///
/// Observers are systems. They can access arbitrary [`World`] data by adding [`SystemParam`]s:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct PrintNames;
/// # #[derive(Component, Debug)]
/// # struct Name;
/// world.add_observer(|trigger: Trigger<PrintNames>, names: Query<&Name>| {
/// for name in &names {
/// println!("{name:?}");
/// }
/// });
/// ```
///
/// Note that [`Trigger`] must always be the first parameter.
///
/// You can also add [`Commands`], which means you can spawn new entities, insert new components, etc:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct SpawnThing;
/// # #[derive(Component, Debug)]
/// # struct Thing;
/// world.add_observer(|trigger: Trigger<SpawnThing>, mut commands: Commands| {
/// commands.spawn(Thing);
/// });
/// ```
///
/// Observers can also trigger new events:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # #[derive(Event)]
/// # struct A;
/// # #[derive(Event)]
/// # struct B;
/// world.add_observer(|trigger: Trigger<A>, mut commands: Commands| {
/// commands.trigger(B);
/// });
/// ```
///
/// When the commands are flushed (including these "nested triggers") they will be
/// recursively evaluated until there are no commands left, meaning nested triggers all
/// evaluate at the same time!
///
/// Events can be triggered for entities, which will be passed to the [`Observer`]:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # let entity = world.spawn_empty().id();
/// #[derive(Event)]
/// struct Explode;
///
/// world.add_observer(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Entity {} goes BOOM!", trigger.target());
/// commands.entity(trigger.target()).despawn();
/// });
///
/// world.flush();
///
/// world.trigger_targets(Explode, entity);
/// ```
///
/// You can trigger multiple entities at once:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # let e1 = world.spawn_empty().id();
/// # let e2 = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// world.trigger_targets(Explode, [e1, e2]);
/// ```
///
/// Observers can also watch _specific_ entities, which enables you to assign entity-specific logic:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component, Debug)]
/// # struct Name(String);
/// # let mut world = World::default();
/// # let e1 = world.spawn_empty().id();
/// # let e2 = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// world.entity_mut(e1).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("Boom!");
/// commands.entity(trigger.target()).despawn();
/// });
///
/// world.entity_mut(e2).observe(|trigger: Trigger<Explode>, mut commands: Commands| {
/// println!("The explosion fizzles! This entity is immune!");
/// });
/// ```
///
/// If all entities watched by a given [`Observer`] are despawned, the [`Observer`] entity will also be despawned.
/// This protects against observer "garbage" building up over time.
///
/// The examples above calling [`EntityWorldMut::observe`] to add entity-specific observer logic are (once again)
/// just shorthand for spawning an [`Observer`] directly:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut world = World::default();
/// # let entity = world.spawn_empty().id();
/// # #[derive(Event)]
/// # struct Explode;
/// let mut observer = Observer::new(|trigger: Trigger<Explode>| {});
/// observer.watch_entity(entity);
/// world.spawn(observer);
/// ```
///
/// Note that the [`Observer`] component is not added to the entity it is observing. Observers should always be their own entities!
///
/// You can call [`Observer::watch_entity`] more than once, which allows you to watch multiple entities with the same [`Observer`].
///
/// When first added, [`Observer`] will also create an [`ObserverState`] component, which registers the observer with the [`World`] and
/// serves as the "source of truth" of the observer.
///
/// [`SystemParam`]: crate::system::SystemParam
pub struct Observer {
system: Box<dyn Any + Send + Sync + 'static>,
descriptor: ObserverDescriptor,
hook_on_add: ComponentHook,
error_handler: Option<fn(BevyError, ErrorContext)>,
}
impl Observer {
/// Creates a new [`Observer`], which defaults to a "global" observer. This means it will run whenever the event `E` is triggered
/// for _any_ entity (or no entity).
pub fn new<E: Event, B: Bundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {
Self {
system: Box::new(IntoObserverSystem::into_system(system)),
descriptor: Default::default(),
hook_on_add: hook_on_add::<E, B, I::System>,
error_handler: None,
}
}
/// Observe the given `entity`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for the `entity`.
pub fn with_entity(mut self, entity: Entity) -> Self {
self.descriptor.entities.push(entity);
self
}
/// Observe the given `entity`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// for the `entity`.
/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.
pub fn watch_entity(&mut self, entity: Entity) {
self.descriptor.entities.push(entity);
}
/// Observe the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] is triggered
/// with the given component target.
pub fn with_component(mut self, component: ComponentId) -> Self {
self.descriptor.components.push(component);
self
}
/// Observe the given `event`. This will cause the [`Observer`] to run whenever an event with the given [`ComponentId`]
/// is triggered.
/// # Safety
/// The type of the `event` [`ComponentId`] _must_ match the actual value
/// of the event passed into the observer system.
pub unsafe fn with_event(mut self, event: ComponentId) -> Self {
self.descriptor.events.push(event);
self
}
/// Set the error handler to use for this observer.
///
/// See the [`error` module-level documentation](crate::error) for more information.
pub fn with_error_handler(mut self, error_handler: fn(BevyError, ErrorContext)) -> Self {
self.error_handler = Some(error_handler);
self
}
/// Returns the [`ObserverDescriptor`] for this [`Observer`].
pub fn descriptor(&self) -> &ObserverDescriptor {
&self.descriptor
}
}
impl Component for Observer {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
type Mutability = Mutable;
fn on_add() -> Option<ComponentHook> {
Some(|world, context| {
let Some(observe) = world.get::<Self>(context.entity) else {
return;
};
let hook = observe.hook_on_add;
hook(world, context);
})
}
}
fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
mut world: DeferredWorld,
observer_trigger: ObserverTrigger,
ptr: PtrMut,
propagate: &mut bool,
) {
let world = world.as_unsafe_world_cell();
// SAFETY: Observer was triggered so must still exist in world
let observer_cell = unsafe {
world
.get_entity(observer_trigger.observer)
.debug_checked_unwrap()
};
// SAFETY: Observer was triggered so must have an `ObserverState`
let mut state = unsafe {
observer_cell
.get_mut::<ObserverState>()
.debug_checked_unwrap()
};
// TODO: Move this check into the observer cache to avoid dynamic dispatch
let last_trigger = world.last_trigger_id();
if state.last_trigger_id == last_trigger {
return;
}
state.last_trigger_id = last_trigger;
// SAFETY: Observer was triggered so must have an `Observer` component.
let error_handler = unsafe {
observer_cell
.get::<Observer>()
.debug_checked_unwrap()
.error_handler
.debug_checked_unwrap()
};
let trigger: Trigger<E, B> = Trigger::new(
// SAFETY: Caller ensures `ptr` is castable to `&mut T`
unsafe { ptr.deref_mut() },
propagate,
observer_trigger,
);
// SAFETY:
// - observer was triggered so must have an `Observer` component.
// - observer cannot be dropped or mutated until after the system pointer is already dropped.
let system: *mut dyn ObserverSystem<E, B> = unsafe {
let mut observe = observer_cell.get_mut::<Observer>().debug_checked_unwrap();
let system = observe.system.downcast_mut::<S>().unwrap();
&mut *system
};
// SAFETY:
// - `update_archetype_component_access` is called first
// - there are no outstanding references to world except a private component
// - system is an `ObserverSystem` so won't mutate world beyond the access of a `DeferredWorld`
// and is never exclusive
// - system is the same type erased system from above
unsafe {
(*system).update_archetype_component_access(world);
match (*system).validate_param_unsafe(world) {
Ok(()) => {
if let Err(err) = (*system).run_unsafe(trigger, world) {
error_handler(
err,
ErrorContext::Observer {
name: (*system).name(),
last_run: (*system).get_last_run(),
},
);
};
(*system).queue_deferred(world.into_deferred());
}
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::Observer {
name: (*system).name(),
last_run: (*system).get_last_run(),
},
);
}
}
}
}
}
/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::component::ComponentHooks::on_add`).
///
/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters
/// erased.
///
/// The type parameters of this function _must_ match those used to create the [`Observer`].
/// As such, it is recommended to only use this function within the [`Observer::new`] method to
/// ensure type parameters match.
fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
mut world: DeferredWorld<'_>,
HookContext { entity, .. }: HookContext,
) {
world.commands().queue(move |world: &mut World| {
let event_id = E::register_component_id(world);
let mut components = Vec::new();
B::component_ids(&mut world.components_registrator(), &mut |id| {
components.push(id);
});
let mut descriptor = ObserverDescriptor {
events: vec![event_id],
components,
..Default::default()
};
let error_handler = default_error_handler();
// Initialize System
let system: *mut dyn ObserverSystem<E, B> =
if let Some(mut observe) = world.get_mut::<Observer>(entity) {
descriptor.merge(&observe.descriptor);
if observe.error_handler.is_none() {
observe.error_handler = Some(error_handler);
}
let system = observe.system.downcast_mut::<S>().unwrap();
&mut *system
} else {
return;
};
// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias
unsafe {
(*system).initialize(world);
}
{
let mut entity = world.entity_mut(entity);
if let crate::world::Entry::Vacant(entry) = entity.entry::<ObserverState>() {
entry.insert(ObserverState {
descriptor,
runner: observer_system_runner::<E, B, S>,
..Default::default()
});
}
}
});
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{event::Event, observer::Trigger};
#[derive(Event)]
struct TriggerEvent;
#[test]
#[should_panic(expected = "I failed!")]
fn test_fallible_observer() {
fn system(_: Trigger<TriggerEvent>) -> Result {
Err("I failed!".into())
}
let mut world = World::default();
world.add_observer(system);
Schedule::default().run(&mut world);
world.trigger(TriggerEvent);
}
#[test]
fn test_fallible_observer_ignored_errors() {
#[derive(Resource, Default)]
struct Ran(bool);
fn system(_: Trigger<TriggerEvent>, mut ran: ResMut<Ran>) -> Result {
ran.0 = true;
Err("I failed!".into())
}
let mut world = World::default();
world.init_resource::<Ran>();
let observer = Observer::new(system).with_error_handler(crate::error::ignore);
world.spawn(observer);
Schedule::default().run(&mut world);
world.trigger(TriggerEvent);
assert!(world.resource::<Ran>().0);
}
}

1765
vendor/bevy_ecs/src/query/access.rs vendored Normal file

File diff suppressed because it is too large Load Diff

447
vendor/bevy_ecs/src/query/builder.rs vendored Normal file
View File

@@ -0,0 +1,447 @@
use core::marker::PhantomData;
use crate::{
component::{ComponentId, StorageType},
prelude::*,
};
use super::{FilteredAccess, QueryData, QueryFilter};
/// Builder struct to create [`QueryState`] instances at runtime.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct A;
/// #
/// # #[derive(Component)]
/// # struct B;
/// #
/// # #[derive(Component)]
/// # struct C;
/// #
/// let mut world = World::new();
/// let entity_a = world.spawn((A, B)).id();
/// let entity_b = world.spawn((A, C)).id();
///
/// // Instantiate the builder using the type signature of the iterator you will consume
/// let mut query = QueryBuilder::<(Entity, &B)>::new(&mut world)
/// // Add additional terms through builder methods
/// .with::<A>()
/// .without::<C>()
/// .build();
///
/// // Consume the QueryState
/// let (entity, b) = query.single(&world).unwrap();
/// ```
pub struct QueryBuilder<'w, D: QueryData = (), F: QueryFilter = ()> {
access: FilteredAccess<ComponentId>,
world: &'w mut World,
or: bool,
first: bool,
_marker: PhantomData<(D, F)>,
}
impl<'w, D: QueryData, F: QueryFilter> QueryBuilder<'w, D, F> {
/// Creates a new builder with the accesses required for `Q` and `F`
pub fn new(world: &'w mut World) -> Self {
let fetch_state = D::init_state(world);
let filter_state = F::init_state(world);
let mut access = FilteredAccess::default();
D::update_component_access(&fetch_state, &mut access);
// Use a temporary empty FilteredAccess for filters. This prevents them from conflicting with the
// main Query's `fetch_state` access. Filters are allowed to conflict with the main query fetch
// because they are evaluated *before* a specific reference is constructed.
let mut filter_access = FilteredAccess::default();
F::update_component_access(&filter_state, &mut filter_access);
// Merge the temporary filter access with the main access. This ensures that filter access is
// properly considered in a global "cross-query" context (both within systems and across systems).
access.extend(&filter_access);
Self {
access,
world,
or: false,
first: false,
_marker: PhantomData,
}
}
pub(super) fn is_dense(&self) -> bool {
// Note: `component_id` comes from the user in safe code, so we cannot trust it to
// exist. If it doesn't exist we pessimistically assume it's sparse.
let is_dense = |component_id| {
self.world()
.components()
.get_info(component_id)
.is_some_and(|info| info.storage_type() == StorageType::Table)
};
let Ok(component_accesses) = self.access.access().try_iter_component_access() else {
// Access is unbounded, pessimistically assume it's sparse.
return false;
};
component_accesses
.map(|access| *access.index())
.all(is_dense)
&& !self.access.access().has_read_all_components()
&& self.access.with_filters().all(is_dense)
&& self.access.without_filters().all(is_dense)
}
/// Returns a reference to the world passed to [`Self::new`].
pub fn world(&self) -> &World {
self.world
}
/// Returns a mutable reference to the world passed to [`Self::new`].
pub fn world_mut(&mut self) -> &mut World {
self.world
}
/// Adds access to self's underlying [`FilteredAccess`] respecting [`Self::or`] and [`Self::and`]
pub fn extend_access(&mut self, mut access: FilteredAccess<ComponentId>) {
if self.or {
if self.first {
access.required.clear();
self.access.extend(&access);
self.first = false;
} else {
self.access.append_or(&access);
}
} else {
self.access.extend(&access);
}
}
/// Adds accesses required for `T` to self.
pub fn data<T: QueryData>(&mut self) -> &mut Self {
let state = T::init_state(self.world);
let mut access = FilteredAccess::default();
T::update_component_access(&state, &mut access);
self.extend_access(access);
self
}
/// Adds filter from `T` to self.
pub fn filter<T: QueryFilter>(&mut self) -> &mut Self {
let state = T::init_state(self.world);
let mut access = FilteredAccess::default();
T::update_component_access(&state, &mut access);
self.extend_access(access);
self
}
/// Adds [`With<T>`] to the [`FilteredAccess`] of self.
pub fn with<T: Component>(&mut self) -> &mut Self {
self.filter::<With<T>>();
self
}
/// Adds [`With<T>`] to the [`FilteredAccess`] of self from a runtime [`ComponentId`].
pub fn with_id(&mut self, id: ComponentId) -> &mut Self {
let mut access = FilteredAccess::default();
access.and_with(id);
self.extend_access(access);
self
}
/// Adds [`Without<T>`] to the [`FilteredAccess`] of self.
pub fn without<T: Component>(&mut self) -> &mut Self {
self.filter::<Without<T>>();
self
}
/// Adds [`Without<T>`] to the [`FilteredAccess`] of self from a runtime [`ComponentId`].
pub fn without_id(&mut self, id: ComponentId) -> &mut Self {
let mut access = FilteredAccess::default();
access.and_without(id);
self.extend_access(access);
self
}
/// Adds `&T` to the [`FilteredAccess`] of self.
pub fn ref_id(&mut self, id: ComponentId) -> &mut Self {
self.with_id(id);
self.access.add_component_read(id);
self
}
/// Adds `&mut T` to the [`FilteredAccess`] of self.
pub fn mut_id(&mut self, id: ComponentId) -> &mut Self {
self.with_id(id);
self.access.add_component_write(id);
self
}
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
/// on an empty builder and then adds all accesses from that builder to self as optional.
pub fn optional(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
f(&mut builder);
self.access.extend_access(builder.access());
self
}
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
/// on an empty builder and then adds all accesses from that builder to self.
///
/// Primarily used when inside a [`Self::or`] closure to group several terms.
pub fn and(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
f(&mut builder);
let access = builder.access().clone();
self.extend_access(access);
self
}
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
/// on an empty builder, all accesses added to that builder will become terms in an or expression.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct A;
/// #
/// # #[derive(Component)]
/// # struct B;
/// #
/// # let mut world = World::new();
/// #
/// QueryBuilder::<Entity>::new(&mut world).or(|builder| {
/// builder.with::<A>();
/// builder.with::<B>();
/// });
/// // is equivalent to
/// QueryBuilder::<Entity>::new(&mut world).filter::<Or<(With<A>, With<B>)>>();
/// ```
pub fn or(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
let mut builder = QueryBuilder::new(self.world);
builder.or = true;
builder.first = true;
f(&mut builder);
self.access.extend(builder.access());
self
}
/// Returns a reference to the [`FilteredAccess`] that will be provided to the built [`Query`].
pub fn access(&self) -> &FilteredAccess<ComponentId> {
&self.access
}
/// Transmute the existing builder adding required accesses.
/// This will maintain all existing accesses.
///
/// If including a filter type see [`Self::transmute_filtered`]
pub fn transmute<NewD: QueryData>(&mut self) -> &mut QueryBuilder<'w, NewD> {
self.transmute_filtered::<NewD, ()>()
}
/// Transmute the existing builder adding required accesses.
/// This will maintain all existing accesses.
pub fn transmute_filtered<NewD: QueryData, NewF: QueryFilter>(
&mut self,
) -> &mut QueryBuilder<'w, NewD, NewF> {
let mut fetch_state = NewD::init_state(self.world);
let filter_state = NewF::init_state(self.world);
NewD::set_access(&mut fetch_state, &self.access);
let mut access = FilteredAccess::default();
NewD::update_component_access(&fetch_state, &mut access);
NewF::update_component_access(&filter_state, &mut access);
self.extend_access(access);
// SAFETY:
// - We have included all required accesses for NewQ and NewF
// - The layout of all QueryBuilder instances is the same
unsafe { core::mem::transmute(self) }
}
/// Create a [`QueryState`] with the accesses of the builder.
///
/// Takes `&mut self` to access the inner world reference while initializing
/// state for the new [`QueryState`]
pub fn build(&mut self) -> QueryState<D, F> {
QueryState::<D, F>::from_builder(self)
}
}
#[cfg(test)]
mod tests {
use crate::{prelude::*, world::FilteredEntityRef};
use std::dbg;
#[derive(Component, PartialEq, Debug)]
struct A(usize);
#[derive(Component, PartialEq, Debug)]
struct B(usize);
#[derive(Component, PartialEq, Debug)]
struct C(usize);
#[test]
fn builder_with_without_static() {
let mut world = World::new();
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<C>()
.build();
assert_eq!(entity_a, query_a.single(&world).unwrap());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.with::<A>()
.without::<B>()
.build();
assert_eq!(entity_b, query_b.single(&world).unwrap());
}
#[test]
fn builder_with_without_dynamic() {
let mut world = World::new();
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();
let component_id_a = world.register_component::<A>();
let component_id_b = world.register_component::<B>();
let component_id_c = world.register_component::<C>();
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.with_id(component_id_a)
.without_id(component_id_c)
.build();
assert_eq!(entity_a, query_a.single(&world).unwrap());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.with_id(component_id_a)
.without_id(component_id_b)
.build();
assert_eq!(entity_b, query_b.single(&world).unwrap());
}
#[test]
fn builder_or() {
let mut world = World::new();
world.spawn((A(0), B(0)));
world.spawn(B(0));
world.spawn(C(0));
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.with::<B>();
})
.build();
assert_eq!(2, query_a.iter(&world).count());
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.without::<B>();
})
.build();
dbg!(&query_b.component_access);
assert_eq!(2, query_b.iter(&world).count());
let mut query_c = QueryBuilder::<Entity>::new(&mut world)
.or(|builder| {
builder.with::<A>();
builder.with::<B>();
builder.with::<C>();
})
.build();
assert_eq!(3, query_c.iter(&world).count());
}
#[test]
fn builder_transmute() {
let mut world = World::new();
world.spawn(A(0));
world.spawn((A(1), B(0)));
let mut query = QueryBuilder::<()>::new(&mut world)
.with::<B>()
.transmute::<&A>()
.build();
query.iter(&world).for_each(|a| assert_eq!(a.0, 1));
}
#[test]
fn builder_static_components() {
let mut world = World::new();
let entity = world.spawn((A(0), B(1))).id();
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.data::<&A>()
.data::<&B>()
.build();
let entity_ref = query.single(&world).unwrap();
assert_eq!(entity, entity_ref.id());
let a = entity_ref.get::<A>().unwrap();
let b = entity_ref.get::<B>().unwrap();
assert_eq!(0, a.0);
assert_eq!(1, b.0);
}
#[test]
fn builder_dynamic_components() {
let mut world = World::new();
let entity = world.spawn((A(0), B(1))).id();
let component_id_a = world.register_component::<A>();
let component_id_b = world.register_component::<B>();
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
.ref_id(component_id_a)
.ref_id(component_id_b)
.build();
let entity_ref = query.single(&world).unwrap();
assert_eq!(entity, entity_ref.id());
let a = entity_ref.get_by_id(component_id_a).unwrap();
let b = entity_ref.get_by_id(component_id_b).unwrap();
// SAFETY: We set these pointers to point to these components
unsafe {
assert_eq!(0, a.deref::<A>().0);
assert_eq!(1, b.deref::<B>().0);
}
}
/// Regression test for issue #14348
#[test]
fn builder_static_dense_dynamic_sparse() {
#[derive(Component)]
struct Dense;
#[derive(Component)]
#[component(storage = "SparseSet")]
struct Sparse;
let mut world = World::new();
world.spawn(Dense);
world.spawn((Dense, Sparse));
let mut query = QueryBuilder::<&Dense>::new(&mut world)
.with::<Sparse>()
.build();
let matched = query.iter(&world).count();
assert_eq!(matched, 1);
}
}

90
vendor/bevy_ecs/src/query/error.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
use thiserror::Error;
use crate::{
archetype::ArchetypeId,
entity::{Entity, EntityDoesNotExistError},
};
/// An error that occurs when retrieving a specific [`Entity`]'s query result from [`Query`](crate::system::Query) or [`QueryState`](crate::query::QueryState).
// TODO: return the type_name as part of this error
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum QueryEntityError {
/// The given [`Entity`]'s components do not match the query.
///
/// Either it does not have a requested component, or it has a component which the query filters out.
QueryDoesNotMatch(Entity, ArchetypeId),
/// The given [`Entity`] does not exist.
EntityDoesNotExist(EntityDoesNotExistError),
/// The [`Entity`] was requested mutably more than once.
///
/// See [`Query::get_many_mut`](crate::system::Query::get_many_mut) for an example.
AliasedMutability(Entity),
}
impl From<EntityDoesNotExistError> for QueryEntityError {
fn from(error: EntityDoesNotExistError) -> Self {
QueryEntityError::EntityDoesNotExist(error)
}
}
impl core::error::Error for QueryEntityError {}
impl core::fmt::Display for QueryEntityError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
Self::QueryDoesNotMatch(entity, _) => {
write!(f, "The query does not match entity {entity}")
}
Self::EntityDoesNotExist(error) => {
write!(f, "{error}")
}
Self::AliasedMutability(entity) => {
write!(
f,
"The entity with ID {entity} was requested mutably more than once"
)
}
}
}
}
/// An error that occurs when evaluating a [`Query`](crate::system::Query) or [`QueryState`](crate::query::QueryState) as a single expected result via
/// [`single`](crate::system::Query::single) or [`single_mut`](crate::system::Query::single_mut).
#[derive(Debug, Error)]
pub enum QuerySingleError {
/// No entity fits the query.
#[error("No entities fit the query {0}")]
NoEntities(&'static str),
/// Multiple entities fit the query.
#[error("Multiple entities fit the query {0}")]
MultipleEntities(&'static str),
}
#[cfg(test)]
mod test {
use crate::{prelude::World, query::QueryEntityError};
use bevy_ecs_macros::Component;
#[test]
fn query_does_not_match() {
let mut world = World::new();
#[derive(Component)]
struct Present1;
#[derive(Component)]
struct Present2;
#[derive(Component, Debug, PartialEq)]
struct NotPresent;
let entity = world.spawn((Present1, Present2));
let (entity, archetype_id) = (entity.id(), entity.archetype().id());
let result = world.query::<&NotPresent>().get(&world, entity);
assert_eq!(
result,
Err(QueryEntityError::QueryDoesNotMatch(entity, archetype_id))
);
}
}

2593
vendor/bevy_ecs/src/query/fetch.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1058
vendor/bevy_ecs/src/query/filter.rs vendored Normal file

File diff suppressed because it is too large Load Diff

2952
vendor/bevy_ecs/src/query/iter.rs vendored Normal file

File diff suppressed because it is too large Load Diff

931
vendor/bevy_ecs/src/query/mod.rs vendored Normal file
View File

@@ -0,0 +1,931 @@
//! Contains APIs for retrieving component data from the world.
mod access;
mod builder;
mod error;
mod fetch;
mod filter;
mod iter;
mod par_iter;
mod state;
mod world_query;
pub use access::*;
pub use bevy_ecs_macros::{QueryData, QueryFilter};
pub use builder::*;
pub use error::*;
pub use fetch::*;
pub use filter::*;
pub use iter::*;
pub use par_iter::*;
pub use state::*;
pub use world_query::*;
/// A debug checked version of [`Option::unwrap_unchecked`]. Will panic in
/// debug modes if unwrapping a `None` or `Err` value in debug mode, but is
/// equivalent to `Option::unwrap_unchecked` or `Result::unwrap_unchecked`
/// in release mode.
pub(crate) trait DebugCheckedUnwrap {
type Item;
/// # Panics
/// Panics if the value is `None` or `Err`, only in debug mode.
///
/// # Safety
/// This must never be called on a `None` or `Err` value. This can
/// only be called on `Some` or `Ok` values.
unsafe fn debug_checked_unwrap(self) -> Self::Item;
}
// These two impls are explicitly split to ensure that the unreachable! macro
// does not cause inlining to fail when compiling in release mode.
#[cfg(debug_assertions)]
impl<T> DebugCheckedUnwrap for Option<T> {
type Item = T;
#[inline(always)]
#[track_caller]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Some(inner) = self {
inner
} else {
unreachable!()
}
}
}
// These two impls are explicitly split to ensure that the unreachable! macro
// does not cause inlining to fail when compiling in release mode.
#[cfg(debug_assertions)]
impl<T, U> DebugCheckedUnwrap for Result<T, U> {
type Item = T;
#[inline(always)]
#[track_caller]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Ok(inner) = self {
inner
} else {
unreachable!()
}
}
}
// These two impls are explicitly split to ensure that the unreachable! macro
// does not cause inlining to fail when compiling in release mode.
#[cfg(not(debug_assertions))]
impl<T, U> DebugCheckedUnwrap for Result<T, U> {
type Item = T;
#[inline(always)]
#[track_caller]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Ok(inner) = self {
inner
} else {
core::hint::unreachable_unchecked()
}
}
}
#[cfg(not(debug_assertions))]
impl<T> DebugCheckedUnwrap for Option<T> {
type Item = T;
#[inline(always)]
unsafe fn debug_checked_unwrap(self) -> Self::Item {
if let Some(inner) = self {
inner
} else {
core::hint::unreachable_unchecked()
}
}
}
#[cfg(test)]
#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
mod tests {
use crate::{
archetype::Archetype,
component::{Component, ComponentId, Components, Tick},
prelude::{AnyOf, Changed, Entity, Or, QueryState, Res, ResMut, Resource, With, Without},
query::{
ArchetypeFilter, FilteredAccess, Has, QueryCombinationIter, QueryData,
ReadOnlyQueryData, WorldQuery,
},
schedule::{IntoScheduleConfigs, Schedule},
storage::{Table, TableRow},
system::{assert_is_system, IntoSystem, Query, System, SystemState},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use alloc::{vec, vec::Vec};
use bevy_ecs_macros::QueryFilter;
use core::{any::type_name, fmt::Debug, hash::Hash};
use std::{collections::HashSet, println};
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
struct A(usize);
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
struct B(usize);
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
struct C(usize);
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
struct D(usize);
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
#[component(storage = "SparseSet")]
struct Sparse(usize);
#[test]
fn query() {
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
let values = world.query::<&A>().iter(&world).collect::<HashSet<&A>>();
assert!(values.contains(&A(1)));
assert!(values.contains(&A(2)));
for (_a, mut b) in world.query::<(&A, &mut B)>().iter_mut(&mut world) {
b.0 = 3;
}
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
assert_eq!(values, vec![&B(3)]);
}
#[test]
fn query_filtered_exactsizeiterator_len() {
fn choose(n: usize, k: usize) -> usize {
if n == 0 || k == 0 || n < k {
return 0;
}
let ks = 1..=k;
let ns = (n - k + 1..=n).rev();
ks.zip(ns).fold(1, |acc, (k, n)| acc * n / k)
}
fn assert_combination<D, F, const K: usize>(world: &mut World, expected_size: usize)
where
D: ReadOnlyQueryData,
F: ArchetypeFilter,
{
let mut query = world.query_filtered::<D, F>();
let query_type = type_name::<QueryCombinationIter<D, F, K>>();
let iter = query.iter_combinations::<K>(world);
assert_all_sizes_iterator_equal(iter, expected_size, 0, query_type);
let iter = query.iter_combinations::<K>(world);
assert_all_sizes_iterator_equal(iter, expected_size, 1, query_type);
let iter = query.iter_combinations::<K>(world);
assert_all_sizes_iterator_equal(iter, expected_size, 5, query_type);
}
fn assert_all_sizes_equal<D, F>(world: &mut World, expected_size: usize)
where
D: ReadOnlyQueryData,
F: ArchetypeFilter,
{
let mut query = world.query_filtered::<D, F>();
let query_type = type_name::<QueryState<D, F>>();
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 0, query_type);
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 1, query_type);
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 5, query_type);
let expected = expected_size;
assert_combination::<D, F, 1>(world, choose(expected, 1));
assert_combination::<D, F, 2>(world, choose(expected, 2));
assert_combination::<D, F, 5>(world, choose(expected, 5));
assert_combination::<D, F, 43>(world, choose(expected, 43));
assert_combination::<D, F, 64>(world, choose(expected, 64));
}
fn assert_all_exact_sizes_iterator_equal(
iterator: impl ExactSizeIterator,
expected_size: usize,
skip: usize,
query_type: &'static str,
) {
let len = iterator.len();
println!("len: {len}");
assert_all_sizes_iterator_equal(iterator, expected_size, skip, query_type);
assert_eq!(len, expected_size);
}
fn assert_all_sizes_iterator_equal(
mut iterator: impl Iterator,
expected_size: usize,
skip: usize,
query_type: &'static str,
) {
let expected_size = expected_size.saturating_sub(skip);
for _ in 0..skip {
iterator.next();
}
let size_hint_0 = iterator.size_hint().0;
let size_hint_1 = iterator.size_hint().1;
// `count` tests that not only it is the expected value, but also
// the value is accurate to what the query returns.
let count = iterator.count();
// This will show up when one of the asserts in this function fails
println!(
"query declared sizes: \n\
for query: {query_type} \n\
expected: {expected_size} \n\
size_hint().0: {size_hint_0} \n\
size_hint().1: {size_hint_1:?} \n\
count(): {count}"
);
assert_eq!(size_hint_0, expected_size);
assert_eq!(size_hint_1, Some(expected_size));
assert_eq!(count, expected_size);
}
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn(A(3));
assert_all_sizes_equal::<&A, With<B>>(&mut world, 1);
assert_all_sizes_equal::<&A, Without<B>>(&mut world, 2);
let mut world = World::new();
world.spawn((A(1), B(1), C(1)));
world.spawn((A(2), B(2)));
world.spawn((A(3), B(3)));
world.spawn((A(4), C(4)));
world.spawn((A(5), C(5)));
world.spawn((A(6), C(6)));
world.spawn(A(7));
world.spawn(A(8));
world.spawn(A(9));
world.spawn(A(10));
// With/Without for B and C
assert_all_sizes_equal::<&A, With<B>>(&mut world, 3);
assert_all_sizes_equal::<&A, With<C>>(&mut world, 4);
assert_all_sizes_equal::<&A, Without<B>>(&mut world, 7);
assert_all_sizes_equal::<&A, Without<C>>(&mut world, 6);
// With/Without (And) combinations
assert_all_sizes_equal::<&A, (With<B>, With<C>)>(&mut world, 1);
assert_all_sizes_equal::<&A, (With<B>, Without<C>)>(&mut world, 2);
assert_all_sizes_equal::<&A, (Without<B>, With<C>)>(&mut world, 3);
assert_all_sizes_equal::<&A, (Without<B>, Without<C>)>(&mut world, 4);
// With/Without Or<()> combinations
assert_all_sizes_equal::<&A, Or<(With<B>, With<C>)>>(&mut world, 6);
assert_all_sizes_equal::<&A, Or<(With<B>, Without<C>)>>(&mut world, 7);
assert_all_sizes_equal::<&A, Or<(Without<B>, With<C>)>>(&mut world, 8);
assert_all_sizes_equal::<&A, Or<(Without<B>, Without<C>)>>(&mut world, 9);
assert_all_sizes_equal::<&A, (Or<(With<B>,)>, Or<(With<C>,)>)>(&mut world, 1);
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 6);
for i in 11..14 {
world.spawn((A(i), D(i)));
}
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 9);
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, Without<D>)>>(&mut world, 10);
// a fair amount of entities
for i in 14..20 {
world.spawn((C(i), D(i)));
}
assert_all_sizes_equal::<Entity, (With<C>, With<D>)>(&mut world, 6);
}
// the order of the combinations is not guaranteed, but each unique combination is present
fn check_combinations<T: Ord + Hash + Debug, const K: usize>(
values: HashSet<[&T; K]>,
expected: HashSet<[&T; K]>,
) {
values.iter().for_each(|pair| {
let mut sorted = *pair;
sorted.sort();
assert!(expected.contains(&sorted),
"the results of iter_combinations should contain this combination {:?}. Expected: {:?}, got: {:?}",
&sorted, &expected, &values);
});
}
#[test]
fn query_iter_combinations() {
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn(A(3));
world.spawn(A(4));
let values: HashSet<[&A; 2]> = world.query::<&A>().iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&A(1), &A(2)],
[&A(1), &A(3)],
[&A(1), &A(4)],
[&A(2), &A(3)],
[&A(2), &A(4)],
[&A(3), &A(4)],
]),
);
let mut a_query = world.query::<&A>();
let values: HashSet<[&A; 3]> = a_query.iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&A(1), &A(2), &A(3)],
[&A(1), &A(2), &A(4)],
[&A(1), &A(3), &A(4)],
[&A(2), &A(3), &A(4)],
]),
);
let mut b_query = world.query::<&B>();
assert_eq!(
b_query.iter_combinations::<2>(&world).size_hint(),
(0, Some(0))
);
let values: Vec<[&B; 2]> = b_query.iter_combinations(&world).collect();
assert_eq!(values, Vec::<[&B; 2]>::new());
}
#[test]
fn query_filtered_iter_combinations() {
use bevy_ecs::query::{Added, Or, With, Without};
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn(A(3));
world.spawn(A(4));
let mut a_wout_b = world.query_filtered::<&A, Without<B>>();
let values: HashSet<[&A; 2]> = a_wout_b.iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([[&A(2), &A(3)], [&A(2), &A(4)], [&A(3), &A(4)]]),
);
let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
check_combinations(values, HashSet::from([[&A(2), &A(3), &A(4)]]));
let mut query = world.query_filtered::<&A, Or<(With<A>, With<B>)>>();
let values: HashSet<[&A; 2]> = query.iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&A(1), &A(2)],
[&A(1), &A(3)],
[&A(1), &A(4)],
[&A(2), &A(3)],
[&A(2), &A(4)],
[&A(3), &A(4)],
]),
);
let mut query = world.query_filtered::<&mut A, Without<B>>();
let mut combinations = query.iter_combinations_mut(&mut world);
while let Some([mut a, mut b, mut c]) = combinations.fetch_next() {
a.0 += 10;
b.0 += 100;
c.0 += 1000;
}
let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
check_combinations(values, HashSet::from([[&A(12), &A(103), &A(1004)]]));
// Check if Added<T>, Changed<T> works
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn((A(2), B(2)));
world.spawn((A(3), B(3)));
world.spawn((A(4), B(4)));
let mut query_added = world.query_filtered::<&A, Added<A>>();
world.clear_trackers();
world.spawn(A(5));
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 0);
world.clear_trackers();
world.spawn(A(6));
world.spawn(A(7));
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 1);
world.clear_trackers();
world.spawn(A(8));
world.spawn(A(9));
world.spawn(A(10));
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 3);
}
#[test]
fn query_iter_combinations_sparse() {
let mut world = World::new();
world.spawn_batch((1..=4).map(Sparse));
let values: HashSet<[&Sparse; 3]> =
world.query::<&Sparse>().iter_combinations(&world).collect();
check_combinations(
values,
HashSet::from([
[&Sparse(1), &Sparse(2), &Sparse(3)],
[&Sparse(1), &Sparse(2), &Sparse(4)],
[&Sparse(1), &Sparse(3), &Sparse(4)],
[&Sparse(2), &Sparse(3), &Sparse(4)],
]),
);
}
#[test]
fn get_many_only_mut_checks_duplicates() {
let mut world = World::new();
let id = world.spawn(A(10)).id();
let mut query_state = world.query::<&mut A>();
let mut query = query_state.query_mut(&mut world);
let result = query.get_many([id, id]);
assert_eq!(result, Ok([&A(10), &A(10)]));
let mut_result = query.get_many_mut([id, id]);
assert!(mut_result.is_err());
}
#[test]
fn multi_storage_query() {
let mut world = World::new();
world.spawn((Sparse(1), B(2)));
world.spawn(Sparse(2));
let values = world
.query::<&Sparse>()
.iter(&world)
.collect::<HashSet<&Sparse>>();
assert!(values.contains(&Sparse(1)));
assert!(values.contains(&Sparse(2)));
for (_a, mut b) in world.query::<(&Sparse, &mut B)>().iter_mut(&mut world) {
b.0 = 3;
}
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
assert_eq!(values, vec![&B(3)]);
}
#[test]
fn any_query() {
let mut world = World::new();
world.spawn((A(1), B(2)));
world.spawn(A(2));
world.spawn(C(3));
let values: Vec<(Option<&A>, Option<&B>)> =
world.query::<AnyOf<(&A, &B)>>().iter(&world).collect();
assert_eq!(
values,
vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
);
}
#[test]
fn has_query() {
let mut world = World::new();
world.spawn((A(1), B(1)));
world.spawn(A(2));
world.spawn((A(3), B(1)));
world.spawn(A(4));
let values: HashSet<(&A, bool)> = world.query::<(&A, Has<B>)>().iter(&world).collect();
assert!(values.contains(&(&A(1), true)));
assert!(values.contains(&(&A(2), false)));
assert!(values.contains(&(&A(3), true)));
assert!(values.contains(&(&A(4), false)));
}
#[test]
#[should_panic = "&mut bevy_ecs::query::tests::A conflicts with a previous access in this query."]
fn self_conflicting_worldquery() {
#[derive(QueryData)]
#[query_data(mutable)]
struct SelfConflicting {
a: &'static mut A,
b: &'static mut A,
}
let mut world = World::new();
world.query::<SelfConflicting>();
}
#[test]
fn derived_worldqueries() {
let mut world = World::new();
world.spawn((A(10), B(18), C(3), Sparse(4)));
world.spawn((A(101), B(148), C(13)));
world.spawn((A(51), B(46), Sparse(72)));
world.spawn((A(398), C(6), Sparse(9)));
world.spawn((B(11), C(28), Sparse(92)));
world.spawn((C(18348), Sparse(101)));
world.spawn((B(839), Sparse(5)));
world.spawn((B(6721), C(122)));
world.spawn((A(220), Sparse(63)));
world.spawn((A(1092), C(382)));
world.spawn((A(2058), B(3019)));
world.spawn((B(38), C(8), Sparse(100)));
world.spawn((A(111), C(52), Sparse(1)));
world.spawn((A(599), B(39), Sparse(13)));
world.spawn((A(55), B(66), C(77)));
world.spawn_empty();
{
#[derive(QueryData)]
struct CustomAB {
a: &'static A,
b: &'static B,
}
let custom_param_data = world
.query::<CustomAB>()
.iter(&world)
.map(|item| (*item.a, *item.b))
.collect::<Vec<_>>();
let normal_data = world
.query::<(&A, &B)>()
.iter(&world)
.map(|(a, b)| (*a, *b))
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(QueryData)]
struct FancyParam {
e: Entity,
b: &'static B,
opt: Option<&'static Sparse>,
}
let custom_param_data = world
.query::<FancyParam>()
.iter(&world)
.map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
.collect::<Vec<_>>();
let normal_data = world
.query::<(Entity, &B, Option<&Sparse>)>()
.iter(&world)
.map(|(e, b, opt)| (e, *b, opt.copied()))
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(QueryData)]
struct MaybeBSparse {
blah: Option<(&'static B, &'static Sparse)>,
}
#[derive(QueryData)]
struct MatchEverything {
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
opt_bsparse: MaybeBSparse,
}
let custom_param_data = world
.query::<MatchEverything>()
.iter(&world)
.map(
|MatchEverythingItem {
abcs: (a, b, c),
opt_bsparse: MaybeBSparseItem { blah: bsparse },
}| {
(
(a.copied(), b.copied(), c.copied()),
bsparse.map(|(b, sparse)| (*b, *sparse)),
)
},
)
.collect::<Vec<_>>();
let normal_data = world
.query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
.iter(&world)
.map(|((a, b, c), bsparse)| {
(
(a.copied(), b.copied(), c.copied()),
bsparse.map(|(b, sparse)| (*b, *sparse)),
)
})
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(QueryFilter)]
struct AOrBFilter {
a: Or<(With<A>, With<B>)>,
}
#[derive(QueryFilter)]
struct NoSparseThatsSlow {
no: Without<Sparse>,
}
let custom_param_entities = world
.query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(QueryFilter)]
struct CSparseFilter {
tuple_structs_pls: With<C>,
ugh: With<Sparse>,
}
let custom_param_entities = world
.query_filtered::<Entity, CSparseFilter>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (With<C>, With<Sparse>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(QueryFilter)]
struct WithoutComps {
_1: Without<A>,
_2: Without<B>,
_3: Without<C>,
}
let custom_param_entities = world
.query_filtered::<Entity, WithoutComps>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(QueryData)]
struct IterCombAB {
a: &'static A,
b: &'static B,
}
let custom_param_data = world
.query::<IterCombAB>()
.iter_combinations::<2>(&world)
.map(|[item0, item1]| [(*item0.a, *item0.b), (*item1.a, *item1.b)])
.collect::<Vec<_>>();
let normal_data = world
.query::<(&A, &B)>()
.iter_combinations(&world)
.map(|[(a0, b0), (a1, b1)]| [(*a0, *b0), (*a1, *b1)])
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
}
#[test]
fn many_entities() {
let mut world = World::new();
world.spawn((A(0), B(0)));
world.spawn((A(0), B(0)));
world.spawn(A(0));
world.spawn(B(0));
{
fn system(has_a: Query<Entity, With<A>>, has_a_and_b: Query<(&A, &B)>) {
assert_eq!(has_a_and_b.iter_many(&has_a).count(), 2);
}
let mut system = IntoSystem::into_system(system);
system.initialize(&mut world);
system.run((), &mut world);
}
{
fn system(has_a: Query<Entity, With<A>>, mut b_query: Query<&mut B>) {
let mut iter = b_query.iter_many_mut(&has_a);
while let Some(mut b) = iter.fetch_next() {
b.0 = 1;
}
}
let mut system = IntoSystem::into_system(system);
system.initialize(&mut world);
system.run((), &mut world);
}
{
fn system(query: Query<(Option<&A>, &B)>) {
for (maybe_a, b) in &query {
match maybe_a {
Some(_) => assert_eq!(b.0, 1),
None => assert_eq!(b.0, 0),
}
}
}
let mut system = IntoSystem::into_system(system);
system.initialize(&mut world);
system.run((), &mut world);
}
}
#[test]
fn mut_to_immut_query_methods_have_immut_item() {
#[derive(Component)]
struct Foo;
let mut world = World::new();
let e = world.spawn(Foo).id();
// state
let mut q = world.query::<&mut Foo>();
let _: Option<&Foo> = q.iter(&world).next();
let _: Option<[&Foo; 2]> = q.iter_combinations::<2>(&world).next();
let _: Option<&Foo> = q.iter_manual(&world).next();
let _: Option<&Foo> = q.iter_many(&world, [e]).next();
q.iter(&world).for_each(|_: &Foo| ());
let _: Option<&Foo> = q.get(&world, e).ok();
let _: Option<&Foo> = q.get_manual(&world, e).ok();
let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok();
let _: Option<&Foo> = q.single(&world).ok();
let _: &Foo = q.single(&world).unwrap();
// system param
let mut q = SystemState::<Query<&mut Foo>>::new(&mut world);
let q = q.get_mut(&mut world);
let _: Option<&Foo> = q.iter().next();
let _: Option<[&Foo; 2]> = q.iter_combinations::<2>().next();
let _: Option<&Foo> = q.iter_many([e]).next();
q.iter().for_each(|_: &Foo| ());
let _: Option<&Foo> = q.get(e).ok();
let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
let _: Option<&Foo> = q.single().ok();
let _: &Foo = q.single().unwrap();
}
// regression test for https://github.com/bevyengine/bevy/pull/8029
#[test]
fn par_iter_mut_change_detection() {
let mut world = World::new();
world.spawn((A(1), B(1)));
fn propagate_system(mut query: Query<(&A, &mut B), Changed<A>>) {
query.par_iter_mut().for_each(|(a, mut b)| {
b.0 = a.0;
});
}
fn modify_system(mut query: Query<&mut A>) {
for mut a in &mut query {
a.0 = 2;
}
}
let mut schedule = Schedule::default();
schedule.add_systems((propagate_system, modify_system).chain());
schedule.run(&mut world);
world.clear_trackers();
schedule.run(&mut world);
world.clear_trackers();
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
assert_eq!(values, vec![&B(2)]);
}
#[derive(Resource)]
struct R;
/// `QueryData` that performs read access on R to test that resource access is tracked
struct ReadsRData;
/// SAFETY:
/// `update_component_access` adds resource read access for `R`.
/// `update_archetype_component_access` does nothing, as this accesses no components.
unsafe impl WorldQuery for ReadsRData {
type Fetch<'w> = ();
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
unsafe fn init_fetch<'w>(
_world: UnsafeWorldCell<'w>,
_state: &Self::State,
_last_run: Tick,
_this_run: Tick,
) -> Self::Fetch<'w> {
}
const IS_DENSE: bool = true;
#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &Table,
) {
}
#[inline]
unsafe fn set_table<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_table: &'w Table,
) {
}
fn update_component_access(
&component_id: &Self::State,
access: &mut FilteredAccess<ComponentId>,
) {
assert!(
!access.access().has_resource_write(component_id),
"ReadsRData conflicts with a previous access in this query. Shared access cannot coincide with exclusive access."
);
access.add_resource_read(component_id);
}
fn init_state(world: &mut World) -> Self::State {
world.components_registrator().register_resource::<R>()
}
fn get_state(components: &Components) -> Option<Self::State> {
components.resource_id::<R>()
}
fn matches_component_set(
_state: &Self::State,
_set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
true
}
}
/// SAFETY: `Self` is the same as `Self::ReadOnly`
unsafe impl QueryData for ReadsRData {
const IS_READ_ONLY: bool = true;
type ReadOnly = Self;
type Item<'w> = ();
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
}
}
/// SAFETY: access is read only
unsafe impl ReadOnlyQueryData for ReadsRData {}
#[test]
fn read_res_read_res_no_conflict() {
fn system(_q1: Query<ReadsRData, With<A>>, _q2: Query<ReadsRData, Without<A>>) {}
assert_is_system(system);
}
#[test]
fn read_res_sets_archetype_component_access() {
let mut world = World::new();
fn read_query(_q: Query<ReadsRData, With<A>>) {}
let mut read_query = IntoSystem::into_system(read_query);
read_query.initialize(&mut world);
fn read_res(_r: Res<R>) {}
let mut read_res = IntoSystem::into_system(read_res);
read_res.initialize(&mut world);
fn write_res(_r: ResMut<R>) {}
let mut write_res = IntoSystem::into_system(write_res);
write_res.initialize(&mut world);
assert!(read_query
.archetype_component_access()
.is_compatible(read_res.archetype_component_access()));
assert!(!read_query
.archetype_component_access()
.is_compatible(write_res.archetype_component_access()));
}
}

463
vendor/bevy_ecs/src/query/par_iter.rs vendored Normal file
View File

@@ -0,0 +1,463 @@
use crate::{
batching::BatchingStrategy,
component::Tick,
entity::{EntityEquivalent, UniqueEntityEquivalentVec},
world::unsafe_world_cell::UnsafeWorldCell,
};
use super::{QueryData, QueryFilter, QueryItem, QueryState, ReadOnlyQueryData};
use alloc::vec::Vec;
/// A parallel iterator over query results of a [`Query`](crate::system::Query).
///
/// This struct is created by the [`Query::par_iter`](crate::system::Query::par_iter) and
/// [`Query::par_iter_mut`](crate::system::Query::par_iter_mut) methods.
pub struct QueryParIter<'w, 's, D: QueryData, F: QueryFilter> {
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) state: &'s QueryState<D, F>,
pub(crate) last_run: Tick,
pub(crate) this_run: Tick,
pub(crate) batching_strategy: BatchingStrategy,
}
impl<'w, 's, D: QueryData, F: QueryFilter> QueryParIter<'w, 's, D, F> {
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs `func` on each query result in parallel.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
self.for_each_init(|| {}, |_, item| func(item));
}
/// Runs `func` on each query result in parallel on a value returned by `init`.
///
/// `init` may be called multiple times per thread, and the values returned may be discarded between tasks on any given thread.
/// Callers should avoid using this function as if it were a parallel version
/// of [`Iterator::fold`].
///
/// # Example
///
/// ```
/// use bevy_utils::Parallel;
/// use crate::{bevy_ecs::prelude::Component, bevy_ecs::system::Query};
/// #[derive(Component)]
/// struct T;
/// fn system(query: Query<&T>){
/// let mut queue: Parallel<usize> = Parallel::default();
/// // queue.borrow_local_mut() will get or create a thread_local queue for each task/thread;
/// query.par_iter().for_each_init(|| queue.borrow_local_mut(),|local_queue, item| {
/// **local_queue += 1;
/// });
///
/// // collect value from every thread
/// let entity_count: usize = queue.iter_mut().map(|v| *v).sum();
/// }
/// ```
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
where
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
INIT: Fn() -> T + Sync + Send + Clone,
{
let func = |mut init, item| {
func(&mut init, item);
init
};
#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]
{
let init = init();
// SAFETY:
// This method can only be called once per instance of QueryParIter,
// which ensures that mutable queries cannot be executed multiple times at once.
// Mutable instances of QueryParIter can only be created via an exclusive borrow of a
// Query or a World, which ensures that multiple aliasing QueryParIters cannot exist
// at the same time.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.into_iter()
.fold(init, func);
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
{
let thread_count = bevy_tasks::ComputeTaskPool::get().thread_num();
if thread_count <= 1 {
let init = init();
// SAFETY: See the safety comment above.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.into_iter()
.fold(init, func);
}
} else {
// Need a batch size of at least 1.
let batch_size = self.get_batch_size(thread_count).max(1);
// SAFETY: See the safety comment above.
unsafe {
self.state.par_fold_init_unchecked_manual(
init,
self.world,
batch_size,
func,
self.last_run,
self.this_run,
);
}
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
fn get_batch_size(&self, thread_count: usize) -> usize {
let max_items = || {
let id_iter = self.state.matched_storage_ids.iter();
if self.state.is_dense {
// SAFETY: We only access table metadata.
let tables = unsafe { &self.world.world_metadata().storages().tables };
id_iter
// SAFETY: The if check ensures that matched_storage_ids stores TableIds
.map(|id| unsafe { tables[id.table_id].entity_count() })
.max()
} else {
let archetypes = &self.world.archetypes();
id_iter
// SAFETY: The if check ensures that matched_storage_ids stores ArchetypeIds
.map(|id| unsafe { archetypes[id.archetype_id].len() })
.max()
}
.unwrap_or(0)
};
self.batching_strategy
.calc_batch_size(max_items, thread_count)
}
}
/// A parallel iterator over the unique query items generated from an [`Entity`] list.
///
/// This struct is created by the [`Query::par_iter_many`] method.
///
/// [`Entity`]: crate::entity::Entity
/// [`Query::par_iter_many`]: crate::system::Query::par_iter_many
pub struct QueryParManyIter<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent> {
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) state: &'s QueryState<D, F>,
pub(crate) entity_list: Vec<E>,
pub(crate) last_run: Tick,
pub(crate) this_run: Tick,
pub(crate) batching_strategy: BatchingStrategy,
}
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, E: EntityEquivalent + Sync>
QueryParManyIter<'w, 's, D, F, E>
{
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs `func` on each query result in parallel.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
self.for_each_init(|| {}, |_, item| func(item));
}
/// Runs `func` on each query result in parallel on a value returned by `init`.
///
/// `init` may be called multiple times per thread, and the values returned may be discarded between tasks on any given thread.
/// Callers should avoid using this function as if it were a parallel version
/// of [`Iterator::fold`].
///
/// # Example
///
/// ```
/// use bevy_utils::Parallel;
/// use crate::{bevy_ecs::prelude::{Component, Res, Resource, Entity}, bevy_ecs::system::Query};
/// # use core::slice;
/// use bevy_platform::prelude::Vec;
/// # fn some_expensive_operation(_item: &T) -> usize {
/// # 0
/// # }
///
/// #[derive(Component)]
/// struct T;
///
/// #[derive(Resource)]
/// struct V(Vec<Entity>);
///
/// impl<'a> IntoIterator for &'a V {
/// // ...
/// # type Item = &'a Entity;
/// # type IntoIter = slice::Iter<'a, Entity>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # self.0.iter()
/// # }
/// }
///
/// fn system(query: Query<&T>, entities: Res<V>){
/// let mut queue: Parallel<usize> = Parallel::default();
/// // queue.borrow_local_mut() will get or create a thread_local queue for each task/thread;
/// query.par_iter_many(&entities).for_each_init(|| queue.borrow_local_mut(),|local_queue, item| {
/// **local_queue += some_expensive_operation(item);
/// });
///
/// // collect value from every thread
/// let final_value: usize = queue.iter_mut().map(|v| *v).sum();
/// }
/// ```
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
where
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
INIT: Fn() -> T + Sync + Send + Clone,
{
let func = |mut init, item| {
func(&mut init, item);
init
};
#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]
{
let init = init();
// SAFETY:
// This method can only be called once per instance of QueryParManyIter,
// which ensures that mutable queries cannot be executed multiple times at once.
// Mutable instances of QueryParManyUniqueIter can only be created via an exclusive borrow of a
// Query or a World, which ensures that multiple aliasing QueryParManyIters cannot exist
// at the same time.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_inner(&self.entity_list)
.fold(init, func);
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
{
let thread_count = bevy_tasks::ComputeTaskPool::get().thread_num();
if thread_count <= 1 {
let init = init();
// SAFETY: See the safety comment above.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_inner(&self.entity_list)
.fold(init, func);
}
} else {
// Need a batch size of at least 1.
let batch_size = self.get_batch_size(thread_count).max(1);
// SAFETY: See the safety comment above.
unsafe {
self.state.par_many_fold_init_unchecked_manual(
init,
self.world,
&self.entity_list,
batch_size,
func,
self.last_run,
self.this_run,
);
}
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
fn get_batch_size(&self, thread_count: usize) -> usize {
self.batching_strategy
.calc_batch_size(|| self.entity_list.len(), thread_count)
}
}
/// A parallel iterator over the unique query items generated from an [`EntitySet`].
///
/// This struct is created by the [`Query::par_iter_many_unique`] and [`Query::par_iter_many_unique_mut`] methods.
///
/// [`EntitySet`]: crate::entity::EntitySet
/// [`Query::par_iter_many_unique`]: crate::system::Query::par_iter_many_unique
/// [`Query::par_iter_many_unique_mut`]: crate::system::Query::par_iter_many_unique_mut
pub struct QueryParManyUniqueIter<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent + Sync>
{
pub(crate) world: UnsafeWorldCell<'w>,
pub(crate) state: &'s QueryState<D, F>,
pub(crate) entity_list: UniqueEntityEquivalentVec<E>,
pub(crate) last_run: Tick,
pub(crate) this_run: Tick,
pub(crate) batching_strategy: BatchingStrategy,
}
impl<'w, 's, D: QueryData, F: QueryFilter, E: EntityEquivalent + Sync>
QueryParManyUniqueIter<'w, 's, D, F, E>
{
/// Changes the batching strategy used when iterating.
///
/// For more information on how this affects the resultant iteration, see
/// [`BatchingStrategy`].
pub fn batching_strategy(mut self, strategy: BatchingStrategy) -> Self {
self.batching_strategy = strategy;
self
}
/// Runs `func` on each query result in parallel.
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each<FN: Fn(QueryItem<'w, D>) + Send + Sync + Clone>(self, func: FN) {
self.for_each_init(|| {}, |_, item| func(item));
}
/// Runs `func` on each query result in parallel on a value returned by `init`.
///
/// `init` may be called multiple times per thread, and the values returned may be discarded between tasks on any given thread.
/// Callers should avoid using this function as if it were a parallel version
/// of [`Iterator::fold`].
///
/// # Example
///
/// ```
/// use bevy_utils::Parallel;
/// use crate::{bevy_ecs::{prelude::{Component, Res, Resource, Entity}, entity::UniqueEntityVec, system::Query}};
/// # use core::slice;
/// # use crate::bevy_ecs::entity::UniqueEntityIter;
/// # fn some_expensive_operation(_item: &T) -> usize {
/// # 0
/// # }
///
/// #[derive(Component)]
/// struct T;
///
/// #[derive(Resource)]
/// struct V(UniqueEntityVec);
///
/// impl<'a> IntoIterator for &'a V {
/// // ...
/// # type Item = &'a Entity;
/// # type IntoIter = UniqueEntityIter<slice::Iter<'a, Entity>>;
/// #
/// # fn into_iter(self) -> Self::IntoIter {
/// # self.0.iter()
/// # }
/// }
///
/// fn system(query: Query<&T>, entities: Res<V>){
/// let mut queue: Parallel<usize> = Parallel::default();
/// // queue.borrow_local_mut() will get or create a thread_local queue for each task/thread;
/// query.par_iter_many_unique(&entities).for_each_init(|| queue.borrow_local_mut(),|local_queue, item| {
/// **local_queue += some_expensive_operation(item);
/// });
///
/// // collect value from every thread
/// let final_value: usize = queue.iter_mut().map(|v| *v).sum();
/// }
/// ```
///
/// # Panics
/// If the [`ComputeTaskPool`] is not initialized. If using this from a query that is being
/// initialized and run from the ECS scheduler, this should never panic.
///
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
#[inline]
pub fn for_each_init<FN, INIT, T>(self, init: INIT, func: FN)
where
FN: Fn(&mut T, QueryItem<'w, D>) + Send + Sync + Clone,
INIT: Fn() -> T + Sync + Send + Clone,
{
let func = |mut init, item| {
func(&mut init, item);
init
};
#[cfg(any(target_arch = "wasm32", not(feature = "multi_threaded")))]
{
let init = init();
// SAFETY:
// This method can only be called once per instance of QueryParManyUniqueIter,
// which ensures that mutable queries cannot be executed multiple times at once.
// Mutable instances of QueryParManyUniqueIter can only be created via an exclusive borrow of a
// Query or a World, which ensures that multiple aliasing QueryParManyUniqueIters cannot exist
// at the same time.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_unique_inner(self.entity_list)
.fold(init, func);
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
{
let thread_count = bevy_tasks::ComputeTaskPool::get().thread_num();
if thread_count <= 1 {
let init = init();
// SAFETY: See the safety comment above.
unsafe {
self.state
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
.iter_many_unique_inner(self.entity_list)
.fold(init, func);
}
} else {
// Need a batch size of at least 1.
let batch_size = self.get_batch_size(thread_count).max(1);
// SAFETY: See the safety comment above.
unsafe {
self.state.par_many_unique_fold_init_unchecked_manual(
init,
self.world,
&self.entity_list,
batch_size,
func,
self.last_run,
self.this_run,
);
}
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
fn get_batch_size(&self, thread_count: usize) -> usize {
self.batching_strategy
.calc_batch_size(|| self.entity_list.len(), thread_count)
}
}

2366
vendor/bevy_ecs/src/query/state.rs vendored Normal file

File diff suppressed because it is too large Load Diff

229
vendor/bevy_ecs/src/query/world_query.rs vendored Normal file
View File

@@ -0,0 +1,229 @@
use crate::{
archetype::Archetype,
component::{ComponentId, Components, Tick},
query::FilteredAccess,
storage::Table,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use variadics_please::all_tuples;
/// Types that can be used as parameters in a [`Query`].
/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
///
/// # Safety
///
/// Implementor must ensure that
/// [`update_component_access`], [`matches_component_set`], [`QueryData::fetch`], [`QueryFilter::filter_fetch`] and [`init_fetch`]
/// obey the following:
///
/// - For each component mutably accessed by [`QueryData::fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
/// - For each component readonly accessed by [`QueryData::fetch`] or [`QueryFilter::filter_fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
/// - [`update_component_access`] may not add a `Without` filter for a component unless [`matches_component_set`] always returns `false` when the component set contains that component.
/// - [`update_component_access`] may not add a `With` filter for a component unless [`matches_component_set`] always returns `false` when the component set doesn't contain that component.
/// - In cases where the query represents a disjunction (such as an `Or` filter) where each element is a valid [`WorldQuery`], the following rules must be obeyed:
/// - [`matches_component_set`] must be a disjunction of the element's implementations
/// - [`update_component_access`] must replace the filters with a disjunction of filters
/// - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`
/// - For each resource readonly accessed by [`init_fetch`], [`update_component_access`] should add read access.
/// - Mutable resource access is not allowed.
///
/// When implementing [`update_component_access`], note that `add_read` and `add_write` both also add a `With` filter, whereas `extend_access` does not change the filters.
///
/// [`QueryData::fetch`]: crate::query::QueryData::fetch
/// [`QueryFilter::filter_fetch`]: crate::query::QueryFilter::filter_fetch
/// [`init_fetch`]: Self::init_fetch
/// [`matches_component_set`]: Self::matches_component_set
/// [`Query`]: crate::system::Query
/// [`update_component_access`]: Self::update_component_access
/// [`QueryData`]: crate::query::QueryData
/// [`QueryFilter`]: crate::query::QueryFilter
pub unsafe trait WorldQuery {
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
type Fetch<'a>: Clone;
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
/// so it is best to move as much data / computation here as possible to reduce the cost of
/// constructing [`Self::Fetch`](WorldQuery::Fetch).
type State: Send + Sync + Sized;
/// This function manually implements subtyping for the query fetches.
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
/// Creates a new instance of [`Self::Fetch`](WorldQuery::Fetch),
/// by combining data from the [`World`] with the cached [`Self::State`](WorldQuery::State).
/// Readonly accesses resources registered in [`WorldQuery::update_component_access`].
///
/// # Safety
///
/// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
/// in to this function.
/// - `world` must have the **right** to access any access registered in `update_component_access`.
/// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
state: &Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w>;
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
/// all of the matched components.
///
/// This is used to select a more efficient "table iterator"
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
/// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,
/// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for
/// iterators.
const IS_DENSE: bool;
/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
/// archetypes that match this [`WorldQuery`].
///
/// # Safety
///
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
/// - `table` must correspond to `archetype`.
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table,
);
/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
/// that match this [`WorldQuery`].
///
/// # Safety
///
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
/// Sets available accesses for implementors with dynamic access such as [`FilteredEntityRef`](crate::world::FilteredEntityRef)
/// or [`FilteredEntityMut`](crate::world::FilteredEntityMut).
///
/// Called when constructing a [`QueryLens`](crate::system::QueryLens) or calling [`QueryState::from_builder`](super::QueryState::from_builder)
fn set_access(_state: &mut Self::State, _access: &FilteredAccess<ComponentId>) {}
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
///
/// Used to check which queries are disjoint and can run in parallel
// This does not have a default body of `{}` because 99% of cases need to add accesses
// and forgetting to do so would be unsound.
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
/// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
fn init_state(world: &mut World) -> Self::State;
/// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
/// access to [`Components`].
fn get_state(components: &Components) -> Option<Self::State>;
/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
///
/// Used to check which [`Archetype`]s can be skipped by the query
/// (if none of the [`Component`](crate::component::Component)s match).
/// This is how archetypal query filters like `With` work.
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool;
}
macro_rules! impl_tuple_world_query {
($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such the lints below may not always apply."
)]
#[allow(
non_snake_case,
reason = "The names of some variables are provided by the macro's caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use any of the parameters."
)]
#[allow(
clippy::unused_unit,
reason = "Zero-length tuples will generate some function bodies equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
)]
$(#[$meta])*
/// SAFETY:
/// `fetch` accesses are the conjunction of the subqueries' accesses
/// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
/// `update_component_access` adds all `With` and `Without` filters from the subqueries.
/// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
type Fetch<'w> = ($($name::Fetch<'w>,)*);
type State = ($($name::State,)*);
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
let ($($name,)*) = fetch;
($(
$name::shrink_fetch($name),
)*)
}
#[inline]
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
let ($($name,)*) = state;
// SAFETY: The invariants are upheld by the caller.
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
}
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table
) {
let ($($name,)*) = fetch;
let ($($state,)*) = state;
// SAFETY: The invariants are upheld by the caller.
$(unsafe { $name::set_archetype($name, $state, archetype, table); })*
}
#[inline]
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
let ($($name,)*) = fetch;
let ($($state,)*) = state;
// SAFETY: The invariants are upheld by the caller.
$(unsafe { $name::set_table($name, $state, table); })*
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
let ($($name,)*) = state;
$($name::update_component_access($name, access);)*
}
fn init_state(world: &mut World) -> Self::State {
($($name::init_state(world),)*)
}
fn get_state(components: &Components) -> Option<Self::State> {
Some(($($name::get_state(components)?,)*))
}
fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
let ($($name,)*) = state;
true $(&& $name::matches_component_set($name, set_contains_id))*
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_tuple_world_query,
0,
15,
F,
S
);

299
vendor/bevy_ecs/src/reflect/bundle.rs vendored Normal file
View File

@@ -0,0 +1,299 @@
//! Definitions for [`Bundle`] reflection.
//! This allows inserting, updating and/or removing bundles whose type is only known at runtime.
//!
//! This module exports two types: [`ReflectBundleFns`] and [`ReflectBundle`].
//!
//! Same as [`super::component`], but for bundles.
use alloc::boxed::Box;
use core::any::{Any, TypeId};
use crate::{
bundle::BundleFromComponents,
entity::EntityMapper,
prelude::Bundle,
relationship::RelationshipHookMode,
world::{EntityMut, EntityWorldMut},
};
use bevy_reflect::{
FromReflect, FromType, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry,
};
use super::{from_reflect_with_fallback, ReflectComponent};
/// A struct used to operate on reflected [`Bundle`] trait of a type.
///
/// A [`ReflectBundle`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectBundle(ReflectBundleFns);
/// The raw function pointers needed to make up a [`ReflectBundle`].
///
/// The also [`super::component::ReflectComponentFns`].
#[derive(Clone)]
pub struct ReflectBundleFns {
/// Function pointer implementing [`ReflectBundle::insert`].
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply`].
pub apply: fn(EntityMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply_or_insert_mapped`].
pub apply_or_insert_mapped: fn(
&mut EntityWorldMut,
&dyn PartialReflect,
&TypeRegistry,
&mut dyn EntityMapper,
RelationshipHookMode,
),
/// Function pointer implementing [`ReflectBundle::remove`].
pub remove: fn(&mut EntityWorldMut),
/// Function pointer implementing [`ReflectBundle::take`].
pub take: fn(&mut EntityWorldMut) -> Option<Box<dyn Reflect>>,
}
impl ReflectBundleFns {
/// Get the default set of [`ReflectBundleFns`] for a specific bundle type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Bundle + FromReflect + TypePath + BundleFromComponents>() -> Self {
<ReflectBundle as FromType<T>>::from_type().0
}
}
impl ReflectBundle {
/// Insert a reflected [`Bundle`] into the entity like [`insert()`](EntityWorldMut::insert).
pub fn insert(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, bundle, registry);
}
/// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value.
///
/// # Panics
///
/// Panics if there is no [`Bundle`] of the given type.
pub fn apply<'a>(
&self,
entity: impl Into<EntityMut<'a>>,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply)(entity.into(), bundle, registry);
}
/// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value or insert a new one if it does not exist.
pub fn apply_or_insert_mapped(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
mapper: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
(self.0.apply_or_insert_mapped)(entity, bundle, registry, mapper, relationship_hook_mode);
}
/// Removes this [`Bundle`] type from the entity. Does nothing if it doesn't exist.
pub fn remove(&self, entity: &mut EntityWorldMut) -> &ReflectBundle {
(self.0.remove)(entity);
self
}
/// Removes all components in the [`Bundle`] from the entity and returns their previous values.
///
/// **Note:** If the entity does not have every component in the bundle, this method will not remove any of them.
#[must_use]
pub fn take(&self, entity: &mut EntityWorldMut) -> Option<Box<dyn Reflect>> {
(self.0.take)(entity)
}
/// Create a custom implementation of [`ReflectBundle`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Bundle)]` bundle
/// to generate a [`ReflectBundle`] implementation automatically.
///
/// See [`ReflectBundleFns`] for more information.
pub fn new(fns: ReflectBundleFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectBundle`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectBundle>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectBundle`] and keeping it
/// between frames, cloning a `ReflectBundle` is very cheap.
///
/// If you only need a subset of the methods on `ReflectBundle`,
/// use `fn_pointers` to get the underlying [`ReflectBundleFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectBundle>`]: bevy_reflect::TypeRegistration::data
pub fn fn_pointers(&self) -> &ReflectBundleFns {
&self.0
}
}
impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for ReflectBundle {
fn from_type() -> Self {
ReflectBundle(ReflectBundleFns {
insert: |entity, reflected_bundle, registry| {
let bundle = entity.world_scope(|world| {
from_reflect_with_fallback::<B>(reflected_bundle, world, registry)
});
entity.insert(bundle);
},
apply: |mut entity, reflected_bundle, registry| {
if let Some(reflect_component) =
registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
{
reflect_component.apply(entity, reflected_bundle);
} else {
match reflected_bundle.reflect_ref() {
ReflectRef::Struct(bundle) => bundle
.iter_fields()
.for_each(|field| apply_field(&mut entity, field, registry)),
ReflectRef::Tuple(bundle) => bundle
.iter_fields()
.for_each(|field| apply_field(&mut entity, field, registry)),
_ => panic!(
"expected bundle `{}` to be named struct or tuple",
// FIXME: once we have unique reflect, use `TypePath`.
core::any::type_name::<B>(),
),
}
}
},
apply_or_insert_mapped: |entity,
reflected_bundle,
registry,
mapper,
relationship_hook_mode| {
if let Some(reflect_component) =
registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
{
reflect_component.apply_or_insert_mapped(
entity,
reflected_bundle,
registry,
mapper,
relationship_hook_mode,
);
} else {
match reflected_bundle.reflect_ref() {
ReflectRef::Struct(bundle) => bundle.iter_fields().for_each(|field| {
apply_or_insert_field_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
}),
ReflectRef::Tuple(bundle) => bundle.iter_fields().for_each(|field| {
apply_or_insert_field_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
}),
_ => panic!(
"expected bundle `{}` to be a named struct or tuple",
// FIXME: once we have unique reflect, use `TypePath`.
core::any::type_name::<B>(),
),
}
}
},
remove: |entity| {
entity.remove::<B>();
},
take: |entity| {
entity
.take::<B>()
.map(|bundle| Box::new(bundle).into_reflect())
},
})
}
}
fn apply_field(entity: &mut EntityMut, field: &dyn PartialReflect, registry: &TypeRegistry) {
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply(entity.reborrow(), field);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply(entity.reborrow(), field, registry);
} else {
panic!(
"no `ReflectComponent` nor `ReflectBundle` registration found for `{}`",
field.reflect_type_path()
);
}
}
fn apply_or_insert_field_mapped(
entity: &mut EntityWorldMut,
field: &dyn PartialReflect,
registry: &TypeRegistry,
mapper: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply_or_insert_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply_or_insert_mapped(
entity,
field,
registry,
mapper,
relationship_hook_mode,
);
} else {
let is_component = entity.world().components().get_id(type_id).is_some();
if is_component {
panic!(
"no `ReflectComponent` registration found for `{}`",
field.reflect_type_path(),
);
} else {
panic!(
"no `ReflectBundle` registration found for `{}`",
field.reflect_type_path(),
)
}
}
}

392
vendor/bevy_ecs/src/reflect/component.rs vendored Normal file
View File

@@ -0,0 +1,392 @@
//! Definitions for [`Component`] reflection.
//! This allows inserting, updating, removing and generally interacting with components
//! whose types are only known at runtime.
//!
//! This module exports two types: [`ReflectComponentFns`] and [`ReflectComponent`].
//!
//! # Architecture
//!
//! [`ReflectComponent`] wraps a [`ReflectComponentFns`]. In fact, each method on
//! [`ReflectComponent`] wraps a call to a function pointer field in `ReflectComponentFns`.
//!
//! ## Who creates `ReflectComponent`s?
//!
//! When a user adds the `#[reflect(Component)]` attribute to their `#[derive(Reflect)]`
//! type, it tells the derive macro for `Reflect` to add the following single line to its
//! [`get_type_registration`] method (see the relevant code[^1]).
//!
//! ```
//! # use bevy_reflect::{FromType, Reflect};
//! # use bevy_ecs::prelude::{ReflectComponent, Component};
//! # #[derive(Default, Reflect, Component)]
//! # struct A;
//! # impl A {
//! # fn foo() {
//! # let mut registration = bevy_reflect::TypeRegistration::of::<A>();
//! registration.insert::<ReflectComponent>(FromType::<Self>::from_type());
//! # }
//! # }
//! ```
//!
//! This line adds a `ReflectComponent` to the registration data for the type in question.
//! The user can access the `ReflectComponent` for type `T` through the type registry,
//! as per the `trait_reflection.rs` example.
//!
//! The `FromType::<Self>::from_type()` in the previous line calls the `FromType<C>`
//! implementation of `ReflectComponent`.
//!
//! The `FromType<C>` impl creates a function per field of [`ReflectComponentFns`].
//! In those functions, we call generic methods on [`World`] and [`EntityWorldMut`].
//!
//! The result is a `ReflectComponent` completely independent of `C`, yet capable
//! of using generic ECS methods such as `entity.get::<C>()` to get `&dyn Reflect`
//! with underlying type `C`, without the `C` appearing in the type signature.
//!
//! ## A note on code generation
//!
//! A downside of this approach is that monomorphized code (ie: concrete code
//! for generics) is generated **unconditionally**, regardless of whether it ends
//! up used or not.
//!
//! Adding `N` fields on `ReflectComponentFns` will generate `N × M` additional
//! functions, where `M` is how many types derive `#[reflect(Component)]`.
//!
//! Those functions will increase the size of the final app binary.
//!
//! [^1]: `crates/bevy_reflect/bevy_reflect_derive/src/registration.rs`
//!
//! [`get_type_registration`]: bevy_reflect::GetTypeRegistration::get_type_registration
use super::from_reflect_with_fallback;
use crate::{
change_detection::Mut,
component::{ComponentId, ComponentMutability},
entity::{Entity, EntityMapper},
prelude::Component,
relationship::RelationshipHookMode,
world::{
unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut,
FilteredEntityRef, World,
},
};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
use disqualified::ShortName;
/// A struct used to operate on reflected [`Component`] trait of a type.
///
/// A [`ReflectComponent`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectComponent(ReflectComponentFns);
/// The raw function pointers needed to make up a [`ReflectComponent`].
///
/// This is used when creating custom implementations of [`ReflectComponent`] with
/// [`ReflectComponent::new()`].
///
/// > **Note:**
/// > Creating custom implementations of [`ReflectComponent`] is an advanced feature that most users
/// > will not need.
/// > Usually a [`ReflectComponent`] is created for a type by deriving [`Reflect`]
/// > and adding the `#[reflect(Component)]` attribute.
/// > After adding the component to the [`TypeRegistry`],
/// > its [`ReflectComponent`] can then be retrieved when needed.
///
/// Creating a custom [`ReflectComponent`] may be useful if you need to create new component types
/// at runtime, for example, for scripting implementations.
///
/// By creating a custom [`ReflectComponent`] and inserting it into a type's
/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
/// you can modify the way that reflected components of that type will be inserted into the Bevy
/// world.
#[derive(Clone)]
pub struct ReflectComponentFns {
/// Function pointer implementing [`ReflectComponent::insert()`].
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::apply()`].
pub apply: fn(EntityMut, &dyn PartialReflect),
/// Function pointer implementing [`ReflectComponent::apply_or_insert_mapped()`].
pub apply_or_insert_mapped: fn(
&mut EntityWorldMut,
&dyn PartialReflect,
&TypeRegistry,
&mut dyn EntityMapper,
RelationshipHookMode,
),
/// Function pointer implementing [`ReflectComponent::remove()`].
pub remove: fn(&mut EntityWorldMut),
/// Function pointer implementing [`ReflectComponent::contains()`].
pub contains: fn(FilteredEntityRef) -> bool,
/// Function pointer implementing [`ReflectComponent::reflect()`].
pub reflect: fn(FilteredEntityRef) -> Option<&dyn Reflect>,
/// Function pointer implementing [`ReflectComponent::reflect_mut()`].
pub reflect_mut: fn(FilteredEntityMut) -> Option<Mut<dyn Reflect>>,
/// Function pointer implementing [`ReflectComponent::map_entities()`].
pub map_entities: fn(&mut dyn Reflect, &mut dyn EntityMapper),
/// Function pointer implementing [`ReflectComponent::reflect_unchecked_mut()`].
///
/// # Safety
/// The function may only be called with an [`UnsafeEntityCell`] that can be used to mutably access the relevant component on the given entity.
pub reflect_unchecked_mut: unsafe fn(UnsafeEntityCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
/// Function pointer implementing [`ReflectComponent::copy()`].
pub copy: fn(&World, &mut World, Entity, Entity, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::register_component()`].
pub register_component: fn(&mut World) -> ComponentId,
}
impl ReflectComponentFns {
/// Get the default set of [`ReflectComponentFns`] for a specific component type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Component + FromReflect + TypePath>() -> Self {
<ReflectComponent as FromType<T>>::from_type().0
}
}
impl ReflectComponent {
/// Insert a reflected [`Component`] into the entity like [`insert()`](EntityWorldMut::insert).
pub fn insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, component, registry);
}
/// Uses reflection to set the value of this [`Component`] type in the entity to the given value.
///
/// # Panics
///
/// Panics if there is no [`Component`] of the given type.
///
/// Will also panic if [`Component`] is immutable.
pub fn apply<'a>(&self, entity: impl Into<EntityMut<'a>>, component: &dyn PartialReflect) {
(self.0.apply)(entity.into(), component);
}
/// Uses reflection to set the value of this [`Component`] type in the entity to the given value or insert a new one if it does not exist.
///
/// # Panics
///
/// Panics if [`Component`] is immutable.
pub fn apply_or_insert_mapped(
&self,
entity: &mut EntityWorldMut,
component: &dyn PartialReflect,
registry: &TypeRegistry,
map: &mut dyn EntityMapper,
relationship_hook_mode: RelationshipHookMode,
) {
(self.0.apply_or_insert_mapped)(entity, component, registry, map, relationship_hook_mode);
}
/// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist.
pub fn remove(&self, entity: &mut EntityWorldMut) {
(self.0.remove)(entity);
}
/// Returns whether entity contains this [`Component`]
pub fn contains<'a>(&self, entity: impl Into<FilteredEntityRef<'a>>) -> bool {
(self.0.contains)(entity.into())
}
/// Gets the value of this [`Component`] type from the entity as a reflected reference.
pub fn reflect<'a>(&self, entity: impl Into<FilteredEntityRef<'a>>) -> Option<&'a dyn Reflect> {
(self.0.reflect)(entity.into())
}
/// Gets the value of this [`Component`] type from the entity as a mutable reflected reference.
///
/// # Panics
///
/// Panics if [`Component`] is immutable.
pub fn reflect_mut<'a>(
&self,
entity: impl Into<FilteredEntityMut<'a>>,
) -> Option<Mut<'a, dyn Reflect>> {
(self.0.reflect_mut)(entity.into())
}
/// # Safety
/// This method does not prevent you from having two mutable pointers to the same data,
/// violating Rust's aliasing rules. To avoid this:
/// * Only call this method with a [`UnsafeEntityCell`] that may be used to mutably access the component on the entity `entity`
/// * Don't call this method more than once in the same scope for a given [`Component`].
///
/// # Panics
///
/// Panics if [`Component`] is immutable.
pub unsafe fn reflect_unchecked_mut<'a>(
&self,
entity: UnsafeEntityCell<'a>,
) -> Option<Mut<'a, dyn Reflect>> {
// SAFETY: safety requirements deferred to caller
unsafe { (self.0.reflect_unchecked_mut)(entity) }
}
/// Gets the value of this [`Component`] type from entity from `source_world` and [applies](Self::apply()) it to the value of this [`Component`] type in entity in `destination_world`.
///
/// # Panics
///
/// Panics if there is no [`Component`] of the given type or either entity does not exist.
pub fn copy(
&self,
source_world: &World,
destination_world: &mut World,
source_entity: Entity,
destination_entity: Entity,
registry: &TypeRegistry,
) {
(self.0.copy)(
source_world,
destination_world,
source_entity,
destination_entity,
registry,
);
}
/// Register the type of this [`Component`] in [`World`], returning its [`ComponentId`].
pub fn register_component(&self, world: &mut World) -> ComponentId {
(self.0.register_component)(world)
}
/// Create a custom implementation of [`ReflectComponent`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Component)]` component
/// to generate a [`ReflectComponent`] implementation automatically.
///
/// See [`ReflectComponentFns`] for more information.
pub fn new(fns: ReflectComponentFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectComponent`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectComponent>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectComponent`] and keeping it
/// between frames, cloning a `ReflectComponent` is very cheap.
///
/// If you only need a subset of the methods on `ReflectComponent`,
/// use `fn_pointers` to get the underlying [`ReflectComponentFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectComponent>`]: bevy_reflect::TypeRegistration::data
/// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
pub fn fn_pointers(&self) -> &ReflectComponentFns {
&self.0
}
/// Calls a dynamic version of [`Component::map_entities`].
pub fn map_entities(&self, component: &mut dyn Reflect, func: &mut dyn EntityMapper) {
(self.0.map_entities)(component, func);
}
}
impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
fn from_type() -> Self {
// TODO: Currently we panic if a component is immutable and you use
// reflection to mutate it. Perhaps the mutation methods should be fallible?
ReflectComponent(ReflectComponentFns {
insert: |entity, reflected_component, registry| {
let component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
entity.insert(component);
},
apply: |mut entity, reflected_component| {
if !C::Mutability::MUTABLE {
let name = ShortName::of::<C>();
panic!("Cannot call `ReflectComponent::apply` on component {name}. It is immutable, and cannot modified through reflection");
}
// SAFETY: guard ensures `C` is a mutable component
let mut component = unsafe { entity.get_mut_assume_mutable::<C>() }.unwrap();
component.apply(reflected_component);
},
apply_or_insert_mapped: |entity,
reflected_component,
registry,
mut mapper,
relationship_hook_mode| {
if C::Mutability::MUTABLE {
// SAFETY: guard ensures `C` is a mutable component
if let Some(mut component) = unsafe { entity.get_mut_assume_mutable::<C>() } {
component.apply(reflected_component.as_partial_reflect());
C::map_entities(&mut component, &mut mapper);
} else {
let mut component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
C::map_entities(&mut component, &mut mapper);
entity
.insert_with_relationship_hook_mode(component, relationship_hook_mode);
}
} else {
let mut component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
C::map_entities(&mut component, &mut mapper);
entity.insert_with_relationship_hook_mode(component, relationship_hook_mode);
}
},
remove: |entity| {
entity.remove::<C>();
},
contains: |entity| entity.contains::<C>(),
copy: |source_world, destination_world, source_entity, destination_entity, registry| {
let source_component = source_world.get::<C>(source_entity).unwrap();
let destination_component =
from_reflect_with_fallback::<C>(source_component, destination_world, registry);
destination_world
.entity_mut(destination_entity)
.insert(destination_component);
},
reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
reflect_mut: |entity| {
if !C::Mutability::MUTABLE {
let name = ShortName::of::<C>();
panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
}
// SAFETY: guard ensures `C` is a mutable component
unsafe {
entity
.into_mut_assume_mutable::<C>()
.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
}
},
reflect_unchecked_mut: |entity| {
if !C::Mutability::MUTABLE {
let name = ShortName::of::<C>();
panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
}
// SAFETY: reflect_unchecked_mut is an unsafe function pointer used by
// `reflect_unchecked_mut` which must be called with an UnsafeEntityCell with access to the component `C` on the `entity`
// guard ensures `C` is a mutable component
let c = unsafe { entity.get_mut_assume_mutable::<C>() };
c.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
},
register_component: |world: &mut World| -> ComponentId {
world.register_component::<C>()
},
map_entities: |reflect: &mut dyn Reflect, mut mapper: &mut dyn EntityMapper| {
let component = reflect.downcast_mut::<C>().unwrap();
Component::map_entities(component, &mut mapper);
},
})
}
}

View File

@@ -0,0 +1,697 @@
use crate::{
entity::Entity,
prelude::Mut,
reflect::{AppTypeRegistry, ReflectBundle, ReflectComponent},
resource::Resource,
system::EntityCommands,
world::{EntityWorldMut, World},
};
use alloc::{borrow::Cow, boxed::Box};
use bevy_reflect::{PartialReflect, TypeRegistry};
/// An extension trait for [`EntityCommands`] for reflection related functions
pub trait ReflectCommandExt {
/// Adds the given boxed reflect component or bundle to the entity using the reflection data in
/// [`AppTypeRegistry`].
///
/// This will overwrite any previous component(s) of the same type.
///
/// # Panics
///
/// - If the entity doesn't exist.
/// - If [`AppTypeRegistry`] does not have the reflection data for the given
/// [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
/// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
///
/// Prefer to use the typed [`EntityCommands::insert`] if possible. Adding a reflected component
/// is much slower.
///
/// # Example
///
/// ```
/// // Note that you need to register the component type in the AppTypeRegistry prior to using
/// // reflection. You can use the helpers on the App with `app.register_type::<ComponentA>()`
/// // or write to the TypeRegistry directly to register all your components
///
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle};
/// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
/// // A resource that can hold any component that implements reflect as a boxed reflect component
/// #[derive(Resource)]
/// struct Prefab {
/// data: Box<dyn Reflect>,
/// }
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentA(u32);
///
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentB(String);
///
/// #[derive(Bundle, Reflect, Default)]
/// #[reflect(Bundle)]
/// struct BundleA {
/// a: ComponentA,
/// b: ComponentB,
/// }
///
/// fn insert_reflect_component(
/// mut commands: Commands,
/// mut prefab: ResMut<Prefab>
/// ) {
/// // Create a set of new boxed reflect components to use
/// let boxed_reflect_component_a: Box<dyn Reflect> = Box::new(ComponentA(916));
/// let boxed_reflect_component_b: Box<dyn Reflect> = Box::new(ComponentB("NineSixteen".to_string()));
/// let boxed_reflect_bundle_a: Box<dyn Reflect> = Box::new(BundleA {
/// a: ComponentA(24),
/// b: ComponentB("Twenty-Four".to_string()),
/// });
///
/// // You can overwrite the component in the resource with either ComponentA or ComponentB
/// prefab.data = boxed_reflect_component_a;
/// prefab.data = boxed_reflect_component_b;
///
/// // Or even with BundleA
/// prefab.data = boxed_reflect_bundle_a;
///
/// // No matter which component or bundle is in the resource and without knowing the exact type, you can
/// // use the insert_reflect entity command to insert that component/bundle into an entity.
/// commands
/// .spawn_empty()
/// .insert_reflect(prefab.data.reflect_clone().unwrap().into_partial_reflect());
/// }
/// ```
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self;
/// Same as [`insert_reflect`](ReflectCommandExt::insert_reflect), but using the `T` resource as type registry instead of
/// `AppTypeRegistry`.
///
/// # Panics
///
/// - If the given [`Resource`] is not present in the [`World`].
///
/// # Note
///
/// - The given [`Resource`] is removed from the [`World`] before the command is applied.
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn PartialReflect>,
) -> &mut Self;
/// Removes from the entity the component or bundle with the given type name registered in [`AppTypeRegistry`].
///
/// If the type is a bundle, it will remove any components in that bundle regardless if the entity
/// contains all the components.
///
/// Does nothing if the type is a component and the entity does not have a component of the same type,
/// if the type is a bundle and the entity does not contain any of the components in the bundle,
/// if [`AppTypeRegistry`] does not contain the reflection data for the given component,
/// or if the entity does not exist.
///
/// # Note
///
/// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component
/// is much slower.
///
/// # Example
///
/// ```
/// // Note that you need to register the component/bundle type in the AppTypeRegistry prior to using
/// // reflection. You can use the helpers on the App with `app.register_type::<ComponentA>()`
/// // or write to the TypeRegistry directly to register all your components and bundles
///
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle};
/// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
///
/// // A resource that can hold any component or bundle that implements reflect as a boxed reflect
/// #[derive(Resource)]
/// struct Prefab{
/// entity: Entity,
/// data: Box<dyn Reflect>,
/// }
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentA(u32);
/// #[derive(Component, Reflect, Default)]
/// #[reflect(Component)]
/// struct ComponentB(String);
/// #[derive(Bundle, Reflect, Default)]
/// #[reflect(Bundle)]
/// struct BundleA {
/// a: ComponentA,
/// b: ComponentB,
/// }
///
/// fn remove_reflect_component(
/// mut commands: Commands,
/// prefab: Res<Prefab>
/// ) {
/// // Prefab can hold any boxed reflect component or bundle. In this case either
/// // ComponentA, ComponentB, or BundleA. No matter which component or bundle is in the resource though,
/// // we can attempt to remove any component (or set of components in the case of a bundle)
/// // of that same type from an entity.
/// commands.entity(prefab.entity)
/// .remove_reflect(prefab.data.reflect_type_path().to_owned());
/// }
/// ```
fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self;
/// Same as [`remove_reflect`](ReflectCommandExt::remove_reflect), but using the `T` resource as type registry instead of
/// `AppTypeRegistry`.
fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component_type_name: impl Into<Cow<'static, str>>,
) -> &mut Self;
}
impl ReflectCommandExt for EntityCommands<'_> {
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_reflect(component);
})
}
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn PartialReflect>,
) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_reflect_with_registry::<T>(component);
})
}
fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
let component_type_path: Cow<'static, str> = component_type_path.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_reflect(component_type_path);
})
}
fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component_type_path: impl Into<Cow<'static, str>>,
) -> &mut Self {
let component_type_path: Cow<'static, str> = component_type_path.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_reflect_with_registry::<T>(component_type_path);
})
}
}
impl<'w> EntityWorldMut<'w> {
/// Adds the given boxed reflect component or bundle to the entity using the reflection data in
/// [`AppTypeRegistry`].
///
/// This will overwrite any previous component(s) of the same type.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If [`AppTypeRegistry`] does not have the reflection data for the given
/// [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
/// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
///
/// Prefer to use the typed [`EntityWorldMut::insert`] if possible. Adding a reflected component
/// is much slower.
pub fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
let type_registry = &registry.as_ref().read();
insert_reflect_with_registry_ref(world, entity_id, type_registry, component);
});
world.flush();
});
self.update_location();
self
}
/// Same as [`insert_reflect`](EntityWorldMut::insert_reflect), but using
/// the `T` resource as type registry instead of [`AppTypeRegistry`].
///
/// This will overwrite any previous component(s) of the same type.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If the given [`Resource`] does not have the reflection data for the given
/// [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
/// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
/// - If the given [`Resource`] is not present in the [`World`].
pub fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn PartialReflect>,
) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<T>| {
let type_registry = registry.as_ref().as_ref();
insert_reflect_with_registry_ref(world, entity_id, type_registry, component);
});
world.flush();
});
self.update_location();
self
}
/// Removes from the entity the component or bundle with the given type name registered in [`AppTypeRegistry`].
///
/// If the type is a bundle, it will remove any components in that bundle regardless if the entity
/// contains all the components.
///
/// Does nothing if the type is a component and the entity does not have a component of the same type,
/// if the type is a bundle and the entity does not contain any of the components in the bundle,
/// or if [`AppTypeRegistry`] does not contain the reflection data for the given component.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
///
/// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component
/// is much slower.
pub fn remove_reflect(&mut self, component_type_path: Cow<'static, str>) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
let type_registry = &registry.as_ref().read();
remove_reflect_with_registry_ref(
world,
entity_id,
type_registry,
component_type_path,
);
});
world.flush();
});
self.update_location();
self
}
/// Same as [`remove_reflect`](EntityWorldMut::remove_reflect), but using
/// the `T` resource as type registry instead of `AppTypeRegistry`.
///
/// If the given type is a bundle, it will remove any components in that bundle regardless if the entity
/// contains all the components.
///
/// Does nothing if the type is a component and the entity does not have a component of the same type,
/// if the type is a bundle and the entity does not contain any of the components in the bundle,
/// or if [`AppTypeRegistry`] does not contain the reflection data for the given component.
///
/// # Panics
///
/// - If the entity has been despawned while this `EntityWorldMut` is still alive.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
pub fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component_type_path: Cow<'static, str>,
) -> &mut Self {
self.assert_not_despawned();
let entity_id = self.id();
self.world_scope(|world| {
world.resource_scope(|world, registry: Mut<T>| {
let type_registry = registry.as_ref().as_ref();
remove_reflect_with_registry_ref(
world,
entity_id,
type_registry,
component_type_path,
);
});
world.flush();
});
self.update_location();
self
}
}
/// Helper function to add a reflect component or bundle to a given entity
fn insert_reflect_with_registry_ref(
world: &mut World,
entity: Entity,
type_registry: &TypeRegistry,
component: Box<dyn PartialReflect>,
) {
let type_info = component
.get_represented_type_info()
.expect("component should represent a type.");
let type_path = type_info.type_path();
let Ok(mut entity) = world.get_entity_mut(entity) else {
panic!("error[B0003]: Could not insert a reflected component (of type {type_path}) for entity {entity}, which {}. See: https://bevyengine.org/learn/errors/b0003",
world.entities().entity_does_not_exist_error_details(entity));
};
let Some(type_registration) = type_registry.get(type_info.type_id()) else {
panic!("`{type_path}` should be registered in type registry via `App::register_type<{type_path}>`");
};
if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
reflect_component.insert(&mut entity, component.as_partial_reflect(), type_registry);
} else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
reflect_bundle.insert(&mut entity, component.as_partial_reflect(), type_registry);
} else {
panic!("`{type_path}` should have #[reflect(Component)] or #[reflect(Bundle)]");
}
}
/// Helper function to remove a reflect component or bundle from a given entity
fn remove_reflect_with_registry_ref(
world: &mut World,
entity: Entity,
type_registry: &TypeRegistry,
component_type_path: Cow<'static, str>,
) {
let Ok(mut entity) = world.get_entity_mut(entity) else {
return;
};
let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
return;
};
if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
reflect_component.remove(&mut entity);
} else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
reflect_bundle.remove(&mut entity);
}
}
#[cfg(test)]
mod tests {
use crate::{
bundle::Bundle,
component::Component,
prelude::{AppTypeRegistry, ReflectComponent},
reflect::{ReflectBundle, ReflectCommandExt},
system::{Commands, SystemState},
world::World,
};
use alloc::{borrow::ToOwned, boxed::Box};
use bevy_ecs_macros::Resource;
use bevy_reflect::{PartialReflect, Reflect, TypeRegistry};
#[derive(Resource)]
struct TypeRegistryResource {
type_registry: TypeRegistry,
}
impl AsRef<TypeRegistry> for TypeRegistryResource {
fn as_ref(&self) -> &TypeRegistry {
&self.type_registry
}
}
#[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
#[reflect(Component)]
struct ComponentA(u32);
#[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
#[reflect(Component)]
struct ComponentB(u32);
#[derive(Bundle, Reflect, Default, Debug, PartialEq)]
#[reflect(Bundle)]
struct BundleA {
a: ComponentA,
b: ComponentB,
}
#[test]
fn insert_reflected() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<ComponentA>();
registry.register_type_data::<ComponentA, ReflectComponent>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let entity2 = commands.spawn_empty().id();
let entity3 = commands.spawn_empty().id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
let boxed_reflect_component_a_clone = boxed_reflect_component_a.reflect_clone().unwrap();
let boxed_reflect_component_a_dynamic = boxed_reflect_component_a.to_dynamic();
commands
.entity(entity)
.insert_reflect(boxed_reflect_component_a);
commands
.entity(entity2)
.insert_reflect(boxed_reflect_component_a_clone.into_partial_reflect());
commands
.entity(entity3)
.insert_reflect(boxed_reflect_component_a_dynamic);
system_state.apply(&mut world);
assert_eq!(
world.entity(entity).get::<ComponentA>(),
world.entity(entity2).get::<ComponentA>(),
);
assert_eq!(
world.entity(entity).get::<ComponentA>(),
world.entity(entity3).get::<ComponentA>(),
);
}
#[test]
fn insert_reflected_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<ComponentA>();
type_registry
.type_registry
.register_type_data::<ComponentA, ReflectComponent>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
commands
.entity(entity)
.insert_reflect_with_registry::<TypeRegistryResource>(boxed_reflect_component_a);
system_state.apply(&mut world);
assert_eq!(
world.entity(entity).get::<ComponentA>(),
Some(&ComponentA(916))
);
}
#[test]
fn remove_reflected() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<ComponentA>();
registry.register_type_data::<ComponentA, ReflectComponent>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn(ComponentA(0)).id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
}
#[test]
fn remove_reflected_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<ComponentA>();
type_registry
.type_registry
.register_type_data::<ComponentA, ReflectComponent>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn(ComponentA(0)).id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect_with_registry::<TypeRegistryResource>(
boxed_reflect_component_a.reflect_type_path().to_owned(),
);
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
}
#[test]
fn insert_reflect_bundle() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<BundleA>();
registry.register_type_data::<BundleA, ReflectBundle>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let bundle = Box::new(BundleA {
a: ComponentA(31),
b: ComponentB(20),
}) as Box<dyn PartialReflect>;
commands.entity(entity).insert_reflect(bundle);
system_state.apply(&mut world);
assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
}
#[test]
fn insert_reflect_bundle_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<BundleA>();
type_registry
.type_registry
.register_type_data::<BundleA, ReflectBundle>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands.spawn_empty().id();
let bundle = Box::new(BundleA {
a: ComponentA(31),
b: ComponentB(20),
}) as Box<dyn PartialReflect>;
commands
.entity(entity)
.insert_reflect_with_registry::<TypeRegistryResource>(bundle);
system_state.apply(&mut world);
assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
}
#[test]
fn remove_reflected_bundle() {
let mut world = World::new();
let type_registry = AppTypeRegistry::default();
{
let mut registry = type_registry.write();
registry.register::<BundleA>();
registry.register_type_data::<BundleA, ReflectBundle>();
}
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands
.spawn(BundleA {
a: ComponentA(31),
b: ComponentB(20),
})
.id();
let boxed_reflect_bundle_a = Box::new(BundleA {
a: ComponentA(1),
b: ComponentB(23),
}) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect(boxed_reflect_bundle_a.reflect_type_path().to_owned());
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
assert_eq!(world.entity(entity).get::<ComponentB>(), None);
}
#[test]
fn remove_reflected_bundle_with_registry() {
let mut world = World::new();
let mut type_registry = TypeRegistryResource {
type_registry: TypeRegistry::new(),
};
type_registry.type_registry.register::<BundleA>();
type_registry
.type_registry
.register_type_data::<BundleA, ReflectBundle>();
world.insert_resource(type_registry);
let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
let mut commands = system_state.get_mut(&mut world);
let entity = commands
.spawn(BundleA {
a: ComponentA(31),
b: ComponentB(20),
})
.id();
let boxed_reflect_bundle_a = Box::new(BundleA {
a: ComponentA(1),
b: ComponentB(23),
}) as Box<dyn Reflect>;
commands
.entity(entity)
.remove_reflect_with_registry::<TypeRegistryResource>(
boxed_reflect_bundle_a.reflect_type_path().to_owned(),
);
system_state.apply(&mut world);
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
assert_eq!(world.entity(entity).get::<ComponentB>(), None);
}
}

View File

@@ -0,0 +1,87 @@
//! Definitions for [`FromWorld`] reflection.
//! This allows creating instances of types that are known only at runtime and
//! require an `&mut World` to be initialized.
//!
//! This module exports two types: [`ReflectFromWorldFns`] and [`ReflectFromWorld`].
//!
//! Same as [`super::component`], but for [`FromWorld`].
use alloc::boxed::Box;
use bevy_reflect::{FromType, Reflect};
use crate::world::{FromWorld, World};
/// A struct used to operate on the reflected [`FromWorld`] trait of a type.
///
/// A [`ReflectFromWorld`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectFromWorld(ReflectFromWorldFns);
/// The raw function pointers needed to make up a [`ReflectFromWorld`].
#[derive(Clone)]
pub struct ReflectFromWorldFns {
/// Function pointer implementing [`ReflectFromWorld::from_world()`].
pub from_world: fn(&mut World) -> Box<dyn Reflect>,
}
impl ReflectFromWorldFns {
/// Get the default set of [`ReflectFromWorldFns`] for a specific type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Reflect + FromWorld>() -> Self {
<ReflectFromWorld as FromType<T>>::from_type().0
}
}
impl ReflectFromWorld {
/// Constructs default reflected [`FromWorld`] from world using [`from_world()`](FromWorld::from_world).
pub fn from_world(&self, world: &mut World) -> Box<dyn Reflect> {
(self.0.from_world)(world)
}
/// Create a custom implementation of [`ReflectFromWorld`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(FromWorld)]` bundle
/// to generate a [`ReflectFromWorld`] implementation automatically.
///
/// See [`ReflectFromWorldFns`] for more information.
pub fn new(fns: ReflectFromWorldFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectFromWorld`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectFromWorld>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectFromWorld`] and keeping it
/// between frames, cloning a `ReflectFromWorld` is very cheap.
///
/// If you only need a subset of the methods on `ReflectFromWorld`,
/// use `fn_pointers` to get the underlying [`ReflectFromWorldFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectFromWorld>`]: bevy_reflect::TypeRegistration::data
/// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
pub fn fn_pointers(&self) -> &ReflectFromWorldFns {
&self.0
}
}
impl<B: Reflect + FromWorld> FromType<B> for ReflectFromWorld {
fn from_type() -> Self {
ReflectFromWorld(ReflectFromWorldFns {
from_world: |world| Box::new(B::from_world(world)),
})
}
}

View File

@@ -0,0 +1,38 @@
use crate::entity::{EntityMapper, MapEntities};
use bevy_reflect::{FromReflect, FromType, PartialReflect};
/// For a specific type of value, this maps any fields with values of type [`Entity`] to a new world.
///
/// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization
/// any stored IDs need to be re-allocated in the destination world.
///
/// See [`EntityMapper`] and [`MapEntities`] for more information.
///
/// [`Entity`]: crate::entity::Entity
/// [`EntityMapper`]: crate::entity::EntityMapper
#[derive(Clone)]
pub struct ReflectMapEntities {
map_entities: fn(&mut dyn PartialReflect, &mut dyn EntityMapper),
}
impl ReflectMapEntities {
/// A general method for remapping entities in a reflected value via an [`EntityMapper`].
///
/// # Panics
/// Panics if the type of the reflected value doesn't match.
pub fn map_entities(&self, reflected: &mut dyn PartialReflect, mapper: &mut dyn EntityMapper) {
(self.map_entities)(reflected, mapper);
}
}
impl<C: FromReflect + MapEntities> FromType<C> for ReflectMapEntities {
fn from_type() -> Self {
ReflectMapEntities {
map_entities: |reflected, mut mapper| {
let mut concrete = C::from_reflect(reflected).expect("reflected type should match");
concrete.map_entities(&mut mapper);
reflected.apply(&concrete);
},
}
}
}

145
vendor/bevy_ecs/src/reflect/mod.rs vendored Normal file
View File

@@ -0,0 +1,145 @@
//! Types that enable reflection support.
use core::{
any::TypeId,
ops::{Deref, DerefMut},
};
use crate::{resource::Resource, world::World};
use bevy_reflect::{
std_traits::ReflectDefault, PartialReflect, Reflect, ReflectFromReflect, TypePath,
TypeRegistry, TypeRegistryArc,
};
mod bundle;
mod component;
mod entity_commands;
mod from_world;
mod map_entities;
mod resource;
pub use bundle::{ReflectBundle, ReflectBundleFns};
pub use component::{ReflectComponent, ReflectComponentFns};
pub use entity_commands::ReflectCommandExt;
pub use from_world::{ReflectFromWorld, ReflectFromWorldFns};
pub use map_entities::ReflectMapEntities;
pub use resource::{ReflectResource, ReflectResourceFns};
/// A [`Resource`] storing [`TypeRegistry`] for
/// type registrations relevant to a whole app.
#[derive(Resource, Clone, Default)]
pub struct AppTypeRegistry(pub TypeRegistryArc);
impl Deref for AppTypeRegistry {
type Target = TypeRegistryArc;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for AppTypeRegistry {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
/// A [`Resource`] storing [`FunctionRegistry`] for
/// function registrations relevant to a whole app.
///
/// [`FunctionRegistry`]: bevy_reflect::func::FunctionRegistry
#[cfg(feature = "reflect_functions")]
#[derive(Resource, Clone, Default)]
pub struct AppFunctionRegistry(pub bevy_reflect::func::FunctionRegistryArc);
#[cfg(feature = "reflect_functions")]
impl Deref for AppFunctionRegistry {
type Target = bevy_reflect::func::FunctionRegistryArc;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "reflect_functions")]
impl DerefMut for AppFunctionRegistry {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
/// Creates a `T` from a `&dyn PartialReflect`.
///
/// This will try the following strategies, in this order:
///
/// - use the reflected `FromReflect`, if it's present and doesn't fail;
/// - use the reflected `Default`, if it's present, and then call `apply` on the result;
/// - use the reflected `FromWorld`, just like the `Default`.
///
/// The first one that is present and doesn't fail will be used.
///
/// # Panics
///
/// If any strategy produces a `Box<dyn Reflect>` that doesn't store a value of type `T`
/// this method will panic.
///
/// If none of the strategies succeed, this method will panic.
pub fn from_reflect_with_fallback<T: Reflect + TypePath>(
reflected: &dyn PartialReflect,
world: &mut World,
registry: &TypeRegistry,
) -> T {
fn different_type_error<T: TypePath>(reflected: &str) -> ! {
panic!(
"The registration for the reflected `{}` trait for the type `{}` produced \
a value of a different type",
reflected,
T::type_path(),
);
}
// First, try `FromReflect`. This is handled differently from the others because
// it doesn't need a subsequent `apply` and may fail.
if let Some(reflect_from_reflect) =
registry.get_type_data::<ReflectFromReflect>(TypeId::of::<T>())
{
// If it fails it's ok, we can continue checking `Default` and `FromWorld`.
if let Some(value) = reflect_from_reflect.from_reflect(reflected) {
return value
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("FromReflect"));
}
}
// Create an instance of `T` using either the reflected `Default` or `FromWorld`.
let mut value = if let Some(reflect_default) =
registry.get_type_data::<ReflectDefault>(TypeId::of::<T>())
{
reflect_default
.default()
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("Default"))
} else if let Some(reflect_from_world) =
registry.get_type_data::<ReflectFromWorld>(TypeId::of::<T>())
{
reflect_from_world
.from_world(world)
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("FromWorld"))
} else {
panic!(
"Couldn't create an instance of `{}` using the reflected `FromReflect`, \
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
or `#[reflect(FromWorld)]`?",
// FIXME: once we have unique reflect, use `TypePath`.
core::any::type_name::<T>(),
);
};
value.apply(reflected);
value
}

256
vendor/bevy_ecs/src/reflect/resource.rs vendored Normal file
View File

@@ -0,0 +1,256 @@
//! Definitions for [`Resource`] reflection.
//!
//! # Architecture
//!
//! See the module doc for [`crate::reflect::component`].
use crate::{
change_detection::Mut,
component::ComponentId,
resource::Resource,
world::{
error::ResourceFetchError, unsafe_world_cell::UnsafeWorldCell, FilteredResources,
FilteredResourcesMut, World,
},
};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
use super::from_reflect_with_fallback;
/// A struct used to operate on reflected [`Resource`] of a type.
///
/// A [`ReflectResource`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectResource(ReflectResourceFns);
/// The raw function pointers needed to make up a [`ReflectResource`].
///
/// This is used when creating custom implementations of [`ReflectResource`] with
/// [`ReflectResource::new()`].
///
/// > **Note:**
/// > Creating custom implementations of [`ReflectResource`] is an advanced feature that most users
/// > will not need.
/// > Usually a [`ReflectResource`] is created for a type by deriving [`Reflect`]
/// > and adding the `#[reflect(Resource)]` attribute.
/// > After adding the component to the [`TypeRegistry`],
/// > its [`ReflectResource`] can then be retrieved when needed.
///
/// Creating a custom [`ReflectResource`] may be useful if you need to create new resource types at
/// runtime, for example, for scripting implementations.
///
/// By creating a custom [`ReflectResource`] and inserting it into a type's
/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
/// you can modify the way that reflected resources of that type will be inserted into the bevy
/// world.
#[derive(Clone)]
pub struct ReflectResourceFns {
/// Function pointer implementing [`ReflectResource::insert()`].
pub insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::apply()`].
pub apply: fn(&mut World, &dyn PartialReflect),
/// Function pointer implementing [`ReflectResource::apply_or_insert()`].
pub apply_or_insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::remove()`].
pub remove: fn(&mut World),
/// Function pointer implementing [`ReflectResource::reflect()`].
pub reflect:
for<'w> fn(FilteredResources<'w, '_>) -> Result<&'w dyn Reflect, ResourceFetchError>,
/// Function pointer implementing [`ReflectResource::reflect_mut()`].
pub reflect_mut: for<'w> fn(
FilteredResourcesMut<'w, '_>,
) -> Result<Mut<'w, dyn Reflect>, ResourceFetchError>,
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
///
/// # Safety
/// The function may only be called with an [`UnsafeWorldCell`] that can be used to mutably access the relevant resource.
pub reflect_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
/// Function pointer implementing [`ReflectResource::copy()`].
pub copy: fn(&World, &mut World, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::register_resource()`].
pub register_resource: fn(&mut World) -> ComponentId,
}
impl ReflectResourceFns {
/// Get the default set of [`ReflectResourceFns`] for a specific resource type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Resource + FromReflect + TypePath>() -> Self {
<ReflectResource as FromType<T>>::from_type().0
}
}
impl ReflectResource {
/// Insert a reflected [`Resource`] into the world like [`insert()`](World::insert_resource).
pub fn insert(
&self,
world: &mut World,
resource: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(world, resource, registry);
}
/// Uses reflection to set the value of this [`Resource`] type in the world to the given value.
///
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn apply(&self, world: &mut World, resource: &dyn PartialReflect) {
(self.0.apply)(world, resource);
}
/// Uses reflection to set the value of this [`Resource`] type in the world to the given value or insert a new one if it does not exist.
pub fn apply_or_insert(
&self,
world: &mut World,
resource: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(world, resource, registry);
}
/// Removes this [`Resource`] type from the world. Does nothing if it doesn't exist.
pub fn remove(&self, world: &mut World) {
(self.0.remove)(world);
}
/// Gets the value of this [`Resource`] type from the world as a reflected reference.
///
/// Note that [`&World`](World) is a valid type for `resources`.
pub fn reflect<'w, 's>(
&self,
resources: impl Into<FilteredResources<'w, 's>>,
) -> Result<&'w dyn Reflect, ResourceFetchError> {
(self.0.reflect)(resources.into())
}
/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
///
/// Note that [`&mut World`](World) is a valid type for `resources`.
pub fn reflect_mut<'w, 's>(
&self,
resources: impl Into<FilteredResourcesMut<'w, 's>>,
) -> Result<Mut<'w, dyn Reflect>, ResourceFetchError> {
(self.0.reflect_mut)(resources.into())
}
/// # Safety
/// This method does not prevent you from having two mutable pointers to the same data,
/// violating Rust's aliasing rules. To avoid this:
/// * Only call this method with an [`UnsafeWorldCell`] which can be used to mutably access the resource.
/// * Don't call this method more than once in the same scope for a given [`Resource`].
pub unsafe fn reflect_unchecked_mut<'w>(
&self,
world: UnsafeWorldCell<'w>,
) -> Option<Mut<'w, dyn Reflect>> {
// SAFETY: caller promises to uphold uniqueness guarantees
unsafe { (self.0.reflect_unchecked_mut)(world) }
}
/// Gets the value of this [`Resource`] type from `source_world` and [applies](Self::apply()) it to the value of this [`Resource`] type in `destination_world`.
///
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn copy(
&self,
source_world: &World,
destination_world: &mut World,
registry: &TypeRegistry,
) {
(self.0.copy)(source_world, destination_world, registry);
}
/// Register the type of this [`Resource`] in [`World`], returning the [`ComponentId`]
pub fn register_resource(&self, world: &mut World) -> ComponentId {
(self.0.register_resource)(world)
}
/// Create a custom implementation of [`ReflectResource`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Resource)]` component
/// to generate a [`ReflectResource`] implementation automatically.
///
/// See [`ReflectResourceFns`] for more information.
pub fn new(&self, fns: ReflectResourceFns) -> Self {
Self(fns)
}
/// The underlying function pointers implementing methods on `ReflectResource`.
///
/// This is useful when you want to keep track locally of an individual
/// function pointer.
///
/// Calling [`TypeRegistry::get`] followed by
/// [`TypeRegistration::data::<ReflectResource>`] can be costly if done several
/// times per frame. Consider cloning [`ReflectResource`] and keeping it
/// between frames, cloning a `ReflectResource` is very cheap.
///
/// If you only need a subset of the methods on `ReflectResource`,
/// use `fn_pointers` to get the underlying [`ReflectResourceFns`]
/// and copy the subset of function pointers you care about.
///
/// [`TypeRegistration::data::<ReflectResource>`]: bevy_reflect::TypeRegistration::data
/// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
pub fn fn_pointers(&self) -> &ReflectResourceFns {
&self.0
}
}
impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
fn from_type() -> Self {
ReflectResource(ReflectResourceFns {
insert: |world, reflected_resource, registry| {
let resource = from_reflect_with_fallback::<R>(reflected_resource, world, registry);
world.insert_resource(resource);
},
apply: |world, reflected_resource| {
let mut resource = world.resource_mut::<R>();
resource.apply(reflected_resource);
},
apply_or_insert: |world, reflected_resource, registry| {
if let Some(mut resource) = world.get_resource_mut::<R>() {
resource.apply(reflected_resource);
} else {
let resource =
from_reflect_with_fallback::<R>(reflected_resource, world, registry);
world.insert_resource(resource);
}
},
remove: |world| {
world.remove_resource::<R>();
},
reflect: |world| world.get::<R>().map(|res| res.into_inner() as &dyn Reflect),
reflect_mut: |world| {
world
.into_mut::<R>()
.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
},
reflect_unchecked_mut: |world| {
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
// reference or multiple immutable ones alive at any given point
let res = unsafe { world.get_resource_mut::<R>() };
res.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
},
copy: |source_world, destination_world, registry| {
let source_resource = source_world.resource::<R>();
let destination_resource =
from_reflect_with_fallback::<R>(source_resource, destination_world, registry);
destination_world.insert_resource(destination_resource);
},
register_resource: |world: &mut World| -> ComponentId {
world.register_resource::<R>()
},
})
}
}

488
vendor/bevy_ecs/src/relationship/mod.rs vendored Normal file
View File

@@ -0,0 +1,488 @@
//! This module provides functionality to link entities to each other using specialized components called "relationships". See the [`Relationship`] trait for more info.
mod related_methods;
mod relationship_query;
mod relationship_source_collection;
use alloc::format;
pub use related_methods::*;
pub use relationship_query::*;
pub use relationship_source_collection::*;
use crate::{
component::{Component, HookContext, Mutable},
entity::{ComponentCloneCtx, Entity, SourceComponent},
error::{ignore, CommandWithEntity, HandleError},
system::entity_command::{self},
world::{DeferredWorld, EntityWorldMut},
};
use log::warn;
/// A [`Component`] on a "source" [`Entity`] that references another target [`Entity`], creating a "relationship" between them. Every [`Relationship`]
/// has a corresponding [`RelationshipTarget`] type (and vice-versa), which exists on the "target" entity of a relationship and contains the list of all
/// "source" entities that relate to the given "target"
///
/// The [`Relationship`] component is the "source of truth" and the [`RelationshipTarget`] component reflects that source of truth. When a [`Relationship`]
/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
///
/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`ChildOf`](crate::hierarchy::ChildOf)
/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
///
/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
///
/// ## Derive
///
/// [`Relationship`] and [`RelationshipTarget`] can only be derived for structs with a single unnamed field, single named field
/// or for named structs where one field is annotated with `#[relationship]`.
/// If there are additional fields, they must all implement [`Default`].
///
/// [`RelationshipTarget`] also requires that the relationship field is private to prevent direct mutation,
/// ensuring the correctness of relationships.
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::entity::Entity;
/// #[derive(Component)]
/// #[relationship(relationship_target = Children)]
/// pub struct ChildOf {
/// #[relationship]
/// pub parent: Entity,
/// internal: u8,
/// };
///
/// #[derive(Component)]
/// #[relationship_target(relationship = ChildOf)]
/// pub struct Children(Vec<Entity>);
/// ```
///
/// When deriving [`RelationshipTarget`] you can specify the `#[relationship_target(linked_spawn)]` attribute to
/// automatically despawn entities stored in an entity's [`RelationshipTarget`] when that entity is despawned:
///
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::entity::Entity;
/// #[derive(Component)]
/// #[relationship(relationship_target = Children)]
/// pub struct ChildOf(pub Entity);
///
/// #[derive(Component)]
/// #[relationship_target(relationship = ChildOf, linked_spawn)]
/// pub struct Children(Vec<Entity>);
/// ```
pub trait Relationship: Component + Sized {
/// The [`Component`] added to the "target" entities of this [`Relationship`], which contains the list of all "source"
/// entities that relate to the "target".
type RelationshipTarget: RelationshipTarget<Relationship = Self>;
/// Gets the [`Entity`] ID of the related entity.
fn get(&self) -> Entity;
/// Creates this [`Relationship`] from the given `entity`.
fn from(entity: Entity) -> Self;
/// The `on_insert` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
fn on_insert(
mut world: DeferredWorld,
HookContext {
entity,
caller,
relationship_hook_mode,
..
}: HookContext,
) {
match relationship_hook_mode {
RelationshipHookMode::Run => {}
RelationshipHookMode::Skip => return,
RelationshipHookMode::RunIfNotLinked => {
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
return;
}
}
}
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
if target_entity == entity {
warn!(
"{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
core::any::type_name::<Self>(),
core::any::type_name::<Self>()
);
world.commands().entity(entity).remove::<Self>();
return;
}
if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
if let Some(mut relationship_target) =
target_entity_mut.get_mut::<Self::RelationshipTarget>()
{
relationship_target.collection_mut_risky().add(entity);
} else {
let mut target = <Self::RelationshipTarget as RelationshipTarget>::with_capacity(1);
target.collection_mut_risky().add(entity);
world.commands().entity(target_entity).insert(target);
}
} else {
warn!(
"{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
core::any::type_name::<Self>(),
core::any::type_name::<Self>()
);
world.commands().entity(entity).remove::<Self>();
}
}
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
// note: think of this as "on_drop"
fn on_replace(
mut world: DeferredWorld,
HookContext {
entity,
relationship_hook_mode,
..
}: HookContext,
) {
match relationship_hook_mode {
RelationshipHookMode::Run => {}
RelationshipHookMode::Skip => return,
RelationshipHookMode::RunIfNotLinked => {
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
return;
}
}
}
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
if let Some(mut relationship_target) =
target_entity_mut.get_mut::<Self::RelationshipTarget>()
{
relationship_target.collection_mut_risky().remove(entity);
if relationship_target.len() == 0 {
let command = |mut entity: EntityWorldMut| {
// this "remove" operation must check emptiness because in the event that an identical
// relationship is inserted on top, this despawn would result in the removal of that identical
// relationship ... not what we want!
if entity
.get::<Self::RelationshipTarget>()
.is_some_and(RelationshipTarget::is_empty)
{
entity.remove::<Self::RelationshipTarget>();
}
};
world
.commands()
.queue(command.with_entity(target_entity).handle_error_with(ignore));
}
}
}
}
}
/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
/// as defined in the [`RelationshipSourceCollection`] trait.
pub type SourceIter<'w, R> =
<<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
/// See the [`Relationship`] documentation for more information.
pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
/// If this is true, when despawning or cloning (when [linked cloning is enabled](crate::entity::EntityClonerBuilder::linked_cloning)), the related entities targeting this entity will also be despawned or cloned.
///
/// For example, this is set to `true` for Bevy's built-in parent-child relation, defined by [`ChildOf`](crate::prelude::ChildOf) and [`Children`](crate::prelude::Children).
/// This means that when a parent is despawned, any children targeting that parent are also despawned (and the same applies to cloning).
///
/// To get around this behavior, you can first break the relationship between entities, and *then* despawn or clone.
/// This defaults to false when derived.
const LINKED_SPAWN: bool;
/// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
type Relationship: Relationship<RelationshipTarget = Self>;
/// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
///
/// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
/// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
/// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
/// or open an issue on the Bevy repository to request first-party support for your collection type.
type Collection: RelationshipSourceCollection;
/// Returns a reference to the stored [`RelationshipTarget::Collection`].
fn collection(&self) -> &Self::Collection;
/// Returns a mutable reference to the stored [`RelationshipTarget::Collection`].
///
/// # Warning
/// This should generally not be called by user code, as modifying the internal collection could invalidate the relationship.
/// The collection should not contain duplicates.
fn collection_mut_risky(&mut self) -> &mut Self::Collection;
/// Creates a new [`RelationshipTarget`] from the given [`RelationshipTarget::Collection`].
///
/// # Warning
/// This should generally not be called by user code, as constructing the internal collection could invalidate the relationship.
/// The collection should not contain duplicates.
fn from_collection_risky(collection: Self::Collection) -> Self;
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
// note: think of this as "on_drop"
fn on_replace(mut world: DeferredWorld, HookContext { entity, caller, .. }: HookContext) {
let (entities, mut commands) = world.entities_and_commands();
let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
for source_entity in relationship_target.iter() {
if entities.get(source_entity).is_ok() {
commands.queue(
entity_command::remove::<Self::Relationship>()
.with_entity(source_entity)
.handle_error_with(ignore),
);
} else {
warn!(
"{}Tried to despawn non-existent entity {}",
caller
.map(|location| format!("{location}: "))
.unwrap_or_default(),
source_entity
);
}
}
}
/// The `on_despawn` component hook that despawns entities stored in an entity's [`RelationshipTarget`] when
/// that entity is despawned.
// note: think of this as "on_drop"
fn on_despawn(mut world: DeferredWorld, HookContext { entity, caller, .. }: HookContext) {
let (entities, mut commands) = world.entities_and_commands();
let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
for source_entity in relationship_target.iter() {
if entities.get(source_entity).is_ok() {
commands.queue(
entity_command::despawn()
.with_entity(source_entity)
.handle_error_with(ignore),
);
} else {
warn!(
"{}Tried to despawn non-existent entity {}",
caller
.map(|location| format!("{location}: "))
.unwrap_or_default(),
source_entity
);
}
}
}
/// Creates this [`RelationshipTarget`] with the given pre-allocated entity capacity.
fn with_capacity(capacity: usize) -> Self {
let collection =
<Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
Self::from_collection_risky(collection)
}
/// Iterates the entities stored in this collection.
#[inline]
fn iter(&self) -> SourceIter<'_, Self> {
self.collection().iter()
}
/// Returns the number of entities in this collection.
#[inline]
fn len(&self) -> usize {
self.collection().len()
}
/// Returns true if this entity collection is empty.
#[inline]
fn is_empty(&self) -> bool {
self.collection().is_empty()
}
}
/// The "clone behavior" for [`RelationshipTarget`]. This actually creates an empty
/// [`RelationshipTarget`] instance with space reserved for the number of targets in the
/// original instance. The [`RelationshipTarget`] will then be populated with the proper components
/// when the corresponding [`Relationship`] sources of truth are inserted. Cloning the actual entities
/// in the original [`RelationshipTarget`] would result in duplicates, so we don't do that!
///
/// This will also queue up clones of the relationship sources if the [`EntityCloner`](crate::entity::EntityCloner) is configured
/// to spawn recursively.
pub fn clone_relationship_target<T: RelationshipTarget>(
source: &SourceComponent,
context: &mut ComponentCloneCtx,
) {
if let Some(component) = source.read::<T>() {
let mut cloned = T::with_capacity(component.len());
if context.linked_cloning() && T::LINKED_SPAWN {
let collection = cloned.collection_mut_risky();
for entity in component.iter() {
collection.add(entity);
context.queue_entity_clone(entity);
}
}
context.write_target_component(cloned);
}
}
/// Configures the conditions under which the Relationship insert/replace hooks will be run.
#[derive(Copy, Clone, Debug)]
pub enum RelationshipHookMode {
/// Relationship insert/replace hooks will always run
Run,
/// Relationship insert/replace hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
RunIfNotLinked,
/// Relationship insert/replace hooks will always be skipped
Skip,
}
#[cfg(test)]
mod tests {
use crate::world::World;
use crate::{component::Component, entity::Entity};
use alloc::vec::Vec;
#[test]
fn custom_relationship() {
#[derive(Component)]
#[relationship(relationship_target = LikedBy)]
struct Likes(pub Entity);
#[derive(Component)]
#[relationship_target(relationship = Likes)]
struct LikedBy(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn(Likes(a)).id();
let c = world.spawn(Likes(a)).id();
assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
}
#[test]
fn self_relationship_fails() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(a));
assert!(!world.entity(a).contains::<Rel>());
assert!(!world.entity(a).contains::<RelTarget>());
}
#[test]
fn relationship_with_missing_target_fails() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
world.despawn(a);
let b = world.spawn(Rel(a)).id();
assert!(!world.entity(b).contains::<Rel>());
assert!(!world.entity(b).contains::<RelTarget>());
}
#[test]
fn relationship_with_multiple_non_target_fields_compiles() {
#[derive(Component)]
#[relationship(relationship_target=Target)]
#[expect(dead_code, reason = "test struct")]
struct Source {
#[relationship]
target: Entity,
foo: u8,
bar: u8,
}
#[derive(Component)]
#[relationship_target(relationship=Source)]
struct Target(Vec<Entity>);
// No assert necessary, looking to make sure compilation works with the macros
}
#[test]
fn relationship_target_with_multiple_non_target_fields_compiles() {
#[derive(Component)]
#[relationship(relationship_target=Target)]
struct Source(Entity);
#[derive(Component)]
#[relationship_target(relationship=Source)]
#[expect(dead_code, reason = "test struct")]
struct Target {
#[relationship]
target: Vec<Entity>,
foo: u8,
bar: u8,
}
// No assert necessary, looking to make sure compilation works with the macros
}
#[test]
fn parent_child_relationship_with_custom_relationship() {
use crate::prelude::ChildOf;
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Entity);
let mut world = World::new();
// Rel on Parent
// Despawn Parent
let mut commands = world.commands();
let child = commands.spawn_empty().id();
let parent = commands.spawn(Rel(child)).add_child(child).id();
commands.entity(parent).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(world.get_entity(parent).is_err());
// Rel on Parent
// Despawn Child
let mut commands = world.commands();
let child = commands.spawn_empty().id();
let parent = commands.spawn(Rel(child)).add_child(child).id();
commands.entity(child).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(!world.entity(parent).contains::<Rel>());
// Rel on Child
// Despawn Parent
let mut commands = world.commands();
let parent = commands.spawn_empty().id();
let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
commands.entity(parent).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(world.get_entity(parent).is_err());
// Rel on Child
// Despawn Child
let mut commands = world.commands();
let parent = commands.spawn_empty().id();
let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
commands.entity(child).despawn();
world.flush();
assert!(world.get_entity(child).is_err());
assert!(!world.entity(parent).contains::<RelTarget>());
}
}

View File

@@ -0,0 +1,626 @@
use crate::{
bundle::Bundle,
entity::{hash_set::EntityHashSet, Entity},
relationship::{
Relationship, RelationshipHookMode, RelationshipSourceCollection, RelationshipTarget,
},
system::{Commands, EntityCommands},
world::{EntityWorldMut, World},
};
use bevy_platform::prelude::{Box, Vec};
use core::{marker::PhantomData, mem};
use super::OrderedRelationshipSourceCollection;
impl<'w> EntityWorldMut<'w> {
/// Spawns a entity related to this entity (with the `R` relationship) by taking a bundle
pub fn with_related<R: Relationship>(&mut self, bundle: impl Bundle) -> &mut Self {
let parent = self.id();
self.world_scope(|world| {
world.spawn((bundle, R::from(parent)));
});
self
}
/// Spawns entities related to this entity (with the `R` relationship) by taking a function that operates on a [`RelatedSpawner`].
pub fn with_related_entities<R: Relationship>(
&mut self,
func: impl FnOnce(&mut RelatedSpawner<R>),
) -> &mut Self {
let parent = self.id();
self.world_scope(|world| {
func(&mut RelatedSpawner::new(world, parent));
});
self
}
/// Relates the given entities to this entity with the relation `R`.
///
/// See [`add_one_related`](Self::add_one_related) if you want relate only one entity.
pub fn add_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let id = self.id();
self.world_scope(|world| {
for related in related {
world.entity_mut(*related).insert(R::from(id));
}
});
self
}
/// Relates the given entities to this entity with the relation `R`, starting at this particular index.
///
/// If the `related` has duplicates, a related entity will take the index of its last occurrence in `related`.
/// If the indices go out of bounds, they will be clamped into bounds.
/// This will not re-order existing related entities unless they are in `related`.
///
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// let mut world = World::new();
/// let e0 = world.spawn_empty().id();
/// let e1 = world.spawn_empty().id();
/// let e2 = world.spawn_empty().id();
/// let e3 = world.spawn_empty().id();
/// let e4 = world.spawn_empty().id();
///
/// let mut main_entity = world.spawn_empty();
/// main_entity.add_related::<ChildOf>(&[e0, e1, e2, e2]);
/// main_entity.insert_related::<ChildOf>(1, &[e0, e3, e4, e4]);
/// let main_id = main_entity.id();
///
/// let relationship_source = main_entity.get::<Children>().unwrap().collection();
/// assert_eq!(relationship_source, &[e1, e0, e3, e2, e4]);
/// ```
pub fn insert_related<R: Relationship>(&mut self, index: usize, related: &[Entity]) -> &mut Self
where
<R::RelationshipTarget as RelationshipTarget>::Collection:
OrderedRelationshipSourceCollection,
{
let id = self.id();
self.world_scope(|world| {
for (offset, related) in related.iter().enumerate() {
let index = index.saturating_add(offset);
if world
.get::<R>(*related)
.is_some_and(|relationship| relationship.get() == id)
{
world
.get_mut::<R::RelationshipTarget>(id)
.expect("hooks should have added relationship target")
.collection_mut_risky()
.place(*related, index);
} else {
world.entity_mut(*related).insert(R::from(id));
world
.get_mut::<R::RelationshipTarget>(id)
.expect("hooks should have added relationship target")
.collection_mut_risky()
.place_most_recent(index);
}
}
});
self
}
/// Removes the relation `R` between this entity and the given entities.
pub fn remove_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let id = self.id();
self.world_scope(|world| {
for related in related {
if world
.get::<R>(*related)
.is_some_and(|relationship| relationship.get() == id)
{
world.entity_mut(*related).remove::<R>();
}
}
});
self
}
/// Replaces all the related entities with a new set of entities.
pub fn replace_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
type Collection<R> =
<<R as Relationship>::RelationshipTarget as RelationshipTarget>::Collection;
if related.is_empty() {
self.remove::<R::RelationshipTarget>();
return self;
}
let Some(mut existing_relations) = self.get_mut::<R::RelationshipTarget>() else {
return self.add_related::<R>(related);
};
// We take the collection here so we can modify it without taking the component itself (this would create archetype move).
// SAFETY: We eventually return the correctly initialized collection into the target.
let mut existing_relations = mem::replace(
existing_relations.collection_mut_risky(),
Collection::<R>::with_capacity(0),
);
let mut potential_relations = EntityHashSet::from_iter(related.iter().copied());
let id = self.id();
self.world_scope(|world| {
for related in existing_relations.iter() {
if !potential_relations.remove(related) {
world.entity_mut(related).remove::<R>();
}
}
for related in potential_relations {
// SAFETY: We'll manually be adjusting the contents of the parent to fit the final state.
world
.entity_mut(related)
.insert_with_relationship_hook_mode(R::from(id), RelationshipHookMode::Skip);
}
});
// SAFETY: The entities we're inserting will be the entities that were either already there or entities that we've just inserted.
existing_relations.clear();
existing_relations.extend_from_iter(related.iter().copied());
self.insert(R::RelationshipTarget::from_collection_risky(
existing_relations,
));
self
}
/// Replaces all the related entities with a new set of entities.
///
/// This is a more efficient of [`Self::replace_related`] which doesn't allocate.
/// The passed in arguments must adhere to these invariants:
/// - `entities_to_unrelate`: A slice of entities to remove from the relationship source.
/// Entities need not be related to this entity, but must not appear in `entities_to_relate`
/// - `entities_to_relate`: A slice of entities to relate to this entity.
/// This must contain all entities that will remain related (i.e. not those in `entities_to_unrelate`) plus the newly related entities.
/// - `newly_related_entities`: A subset of `entities_to_relate` containing only entities not already related to this entity.
/// - Slices **must not** contain any duplicates
///
/// # Warning
///
/// Violating these invariants may lead to panics, crashes or unpredictable engine behavior.
///
/// # Panics
///
/// Panics when debug assertions are enabled and any invariants are broken.
///
// TODO: Consider making these iterators so users aren't required to allocate a separate buffers for the different slices.
pub fn replace_related_with_difference<R: Relationship>(
&mut self,
entities_to_unrelate: &[Entity],
entities_to_relate: &[Entity],
newly_related_entities: &[Entity],
) -> &mut Self {
#[cfg(debug_assertions)]
{
let entities_to_relate = EntityHashSet::from_iter(entities_to_relate.iter().copied());
let entities_to_unrelate =
EntityHashSet::from_iter(entities_to_unrelate.iter().copied());
let mut newly_related_entities =
EntityHashSet::from_iter(newly_related_entities.iter().copied());
assert!(
entities_to_relate.is_disjoint(&entities_to_unrelate),
"`entities_to_relate` ({entities_to_relate:?}) shared entities with `entities_to_unrelate` ({entities_to_unrelate:?})"
);
assert!(
newly_related_entities.is_disjoint(&entities_to_unrelate),
"`newly_related_entities` ({newly_related_entities:?}) shared entities with `entities_to_unrelate ({entities_to_unrelate:?})`"
);
assert!(
newly_related_entities.is_subset(&entities_to_relate),
"`newly_related_entities` ({newly_related_entities:?}) wasn't a subset of `entities_to_relate` ({entities_to_relate:?})"
);
if let Some(target) = self.get::<R::RelationshipTarget>() {
let existing_relationships: EntityHashSet = target.collection().iter().collect();
assert!(
existing_relationships.is_disjoint(&newly_related_entities),
"`newly_related_entities` contains an entity that wouldn't be newly related"
);
newly_related_entities.extend(existing_relationships);
newly_related_entities -= &entities_to_unrelate;
}
assert_eq!(newly_related_entities, entities_to_relate, "`entities_to_relate` ({entities_to_relate:?}) didn't contain all entities that would end up related");
};
if !self.contains::<R::RelationshipTarget>() {
self.add_related::<R>(entities_to_relate);
return self;
};
let this = self.id();
self.world_scope(|world| {
for unrelate in entities_to_unrelate {
world.entity_mut(*unrelate).remove::<R>();
}
for new_relation in newly_related_entities {
// We're changing the target collection manually so don't run the insert hook
world
.entity_mut(*new_relation)
.insert_with_relationship_hook_mode(R::from(this), RelationshipHookMode::Skip);
}
});
if !entities_to_relate.is_empty() {
if let Some(mut target) = self.get_mut::<R::RelationshipTarget>() {
// SAFETY: The invariants expected by this function mean we'll only be inserting entities that are already related.
let collection = target.collection_mut_risky();
collection.clear();
collection.extend_from_iter(entities_to_relate.iter().copied());
} else {
let mut empty =
<R::RelationshipTarget as RelationshipTarget>::Collection::with_capacity(
entities_to_relate.len(),
);
empty.extend_from_iter(entities_to_relate.iter().copied());
// SAFETY: We've just initialized this collection and we know there's no `RelationshipTarget` on `self`
self.insert(R::RelationshipTarget::from_collection_risky(empty));
}
}
self
}
/// Relates the given entity to this with the relation `R`.
///
/// See [`add_related`](Self::add_related) if you want to relate more than one entity.
pub fn add_one_related<R: Relationship>(&mut self, entity: Entity) -> &mut Self {
self.add_related::<R>(&[entity])
}
/// Despawns entities that relate to this one via the given [`RelationshipTarget`].
/// This entity will not be despawned.
pub fn despawn_related<S: RelationshipTarget>(&mut self) -> &mut Self {
if let Some(sources) = self.take::<S>() {
self.world_scope(|world| {
for entity in sources.iter() {
if let Ok(entity_mut) = world.get_entity_mut(entity) {
entity_mut.despawn();
}
}
});
}
self
}
/// Inserts a component or bundle of components into the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
// We could keep track of a list of visited entities and track cycles,
// but this is not a very well-defined operation (or hard to write) for arbitrary relationships.
pub fn insert_recursive<S: RelationshipTarget>(
&mut self,
bundle: impl Bundle + Clone,
) -> &mut Self {
self.insert(bundle.clone());
if let Some(relationship_target) = self.get::<S>() {
let related_vec: Vec<Entity> = relationship_target.iter().collect();
for related in related_vec {
self.world_scope(|world| {
world
.entity_mut(related)
.insert_recursive::<S>(bundle.clone());
});
}
}
self
}
/// Removes a component or bundle of components of type `B` from the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
self.remove::<B>();
if let Some(relationship_target) = self.get::<S>() {
let related_vec: Vec<Entity> = relationship_target.iter().collect();
for related in related_vec {
self.world_scope(|world| {
world.entity_mut(related).remove_recursive::<S, B>();
});
}
}
self
}
}
impl<'a> EntityCommands<'a> {
/// Spawns a entity related to this entity (with the `R` relationship) by taking a bundle
pub fn with_related<R: Relationship>(&mut self, bundle: impl Bundle) -> &mut Self {
let parent = self.id();
self.commands.spawn((bundle, R::from(parent)));
self
}
/// Spawns entities related to this entity (with the `R` relationship) by taking a function that operates on a [`RelatedSpawner`].
pub fn with_related_entities<R: Relationship>(
&mut self,
func: impl FnOnce(&mut RelatedSpawnerCommands<R>),
) -> &mut Self {
let id = self.id();
func(&mut RelatedSpawnerCommands::new(self.commands(), id));
self
}
/// Relates the given entities to this entity with the relation `R`.
///
/// See [`add_one_related`](Self::add_one_related) if you want relate only one entity.
pub fn add_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.add_related::<R>(&related);
})
}
/// Relates the given entities to this entity with the relation `R`, starting at this particular index.
///
/// If the `related` has duplicates, a related entity will take the index of its last occurrence in `related`.
/// If the indices go out of bounds, they will be clamped into bounds.
/// This will not re-order existing related entities unless they are in `related`.
pub fn insert_related<R: Relationship>(&mut self, index: usize, related: &[Entity]) -> &mut Self
where
<R::RelationshipTarget as RelationshipTarget>::Collection:
OrderedRelationshipSourceCollection,
{
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_related::<R>(index, &related);
})
}
/// Relates the given entity to this with the relation `R`.
///
/// See [`add_related`](Self::add_related) if you want to relate more than one entity.
pub fn add_one_related<R: Relationship>(&mut self, entity: Entity) -> &mut Self {
self.add_related::<R>(&[entity])
}
/// Removes the relation `R` between this entity and the given entities.
pub fn remove_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_related::<R>(&related);
})
}
/// Replaces all the related entities with the given set of new related entities.
pub fn replace_related<R: Relationship>(&mut self, related: &[Entity]) -> &mut Self {
let related: Box<[Entity]> = related.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.replace_related::<R>(&related);
})
}
/// Replaces all the related entities with a new set of entities.
///
/// # Warning
///
/// Failing to maintain the functions invariants may lead to erratic engine behavior including random crashes.
/// Refer to [`EntityWorldMut::replace_related_with_difference`] for a list of these invariants.
///
/// # Panics
///
/// Panics when debug assertions are enable, an invariant is are broken and the command is executed.
pub fn replace_related_with_difference<R: Relationship>(
&mut self,
entities_to_unrelate: &[Entity],
entities_to_relate: &[Entity],
newly_related_entities: &[Entity],
) -> &mut Self {
let entities_to_unrelate: Box<[Entity]> = entities_to_unrelate.into();
let entities_to_relate: Box<[Entity]> = entities_to_relate.into();
let newly_related_entities: Box<[Entity]> = newly_related_entities.into();
self.queue(move |mut entity: EntityWorldMut| {
entity.replace_related_with_difference::<R>(
&entities_to_unrelate,
&entities_to_relate,
&newly_related_entities,
);
})
}
/// Despawns entities that relate to this one via the given [`RelationshipTarget`].
/// This entity will not be despawned.
pub fn despawn_related<S: RelationshipTarget>(&mut self) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.despawn_related::<S>();
})
}
/// Inserts a component or bundle of components into the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
pub fn insert_recursive<S: RelationshipTarget>(
&mut self,
bundle: impl Bundle + Clone,
) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.insert_recursive::<S>(bundle);
})
}
/// Removes a component or bundle of components of type `B` from the entity and all related entities,
/// traversing the relationship tracked in `S` in a breadth-first manner.
///
/// # Warning
///
/// This method should only be called on relationships that form a tree-like structure.
/// Any cycles will cause this method to loop infinitely.
pub fn remove_recursive<S: RelationshipTarget, B: Bundle>(&mut self) -> &mut Self {
self.queue(move |mut entity: EntityWorldMut| {
entity.remove_recursive::<S, B>();
})
}
}
/// Directly spawns related "source" entities with the given [`Relationship`], targeting
/// a specific entity.
pub struct RelatedSpawner<'w, R: Relationship> {
target: Entity,
world: &'w mut World,
_marker: PhantomData<R>,
}
impl<'w, R: Relationship> RelatedSpawner<'w, R> {
/// Creates a new instance that will spawn entities targeting the `target` entity.
pub fn new(world: &'w mut World, target: Entity) -> Self {
Self {
world,
target,
_marker: PhantomData,
}
}
/// Spawns an entity with the given `bundle` and an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn(&mut self, bundle: impl Bundle) -> EntityWorldMut<'_> {
self.world.spawn((R::from(self.target), bundle))
}
/// Spawns an entity with an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn_empty(&mut self) -> EntityWorldMut<'_> {
self.world.spawn(R::from(self.target))
}
/// Returns the "target entity" used when spawning entities with an `R` [`Relationship`].
pub fn target_entity(&self) -> Entity {
self.target
}
/// Returns a reference to the underlying [`World`].
pub fn world(&self) -> &World {
self.world
}
/// Returns a mutable reference to the underlying [`World`].
pub fn world_mut(&mut self) -> &mut World {
self.world
}
}
/// Uses commands to spawn related "source" entities with the given [`Relationship`], targeting
/// a specific entity.
pub struct RelatedSpawnerCommands<'w, R: Relationship> {
target: Entity,
commands: Commands<'w, 'w>,
_marker: PhantomData<R>,
}
impl<'w, R: Relationship> RelatedSpawnerCommands<'w, R> {
/// Creates a new instance that will spawn entities targeting the `target` entity.
pub fn new(commands: Commands<'w, 'w>, target: Entity) -> Self {
Self {
commands,
target,
_marker: PhantomData,
}
}
/// Spawns an entity with the given `bundle` and an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands<'_> {
self.commands.spawn((R::from(self.target), bundle))
}
/// Spawns an entity with an `R` relationship targeting the `target`
/// entity this spawner was initialized with.
pub fn spawn_empty(&mut self) -> EntityCommands<'_> {
self.commands.spawn(R::from(self.target))
}
/// Returns the "target entity" used when spawning entities with an `R` [`Relationship`].
pub fn target_entity(&self) -> Entity {
self.target
}
/// Returns the underlying [`Commands`].
pub fn commands(&mut self) -> Commands {
self.commands.reborrow()
}
/// Returns a mutable reference to the underlying [`Commands`].
pub fn commands_mut(&mut self) -> &mut Commands<'w, 'w> {
&mut self.commands
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::{ChildOf, Children, Component};
#[derive(Component, Clone, Copy)]
struct TestComponent;
#[test]
fn insert_and_remove_recursive() {
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn(ChildOf(a)).id();
let c = world.spawn(ChildOf(a)).id();
let d = world.spawn(ChildOf(b)).id();
world
.entity_mut(a)
.insert_recursive::<Children>(TestComponent);
for entity in [a, b, c, d] {
assert!(world.entity(entity).contains::<TestComponent>());
}
world
.entity_mut(b)
.remove_recursive::<Children, TestComponent>();
// Parent
assert!(world.entity(a).contains::<TestComponent>());
// Target
assert!(!world.entity(b).contains::<TestComponent>());
// Sibling
assert!(world.entity(c).contains::<TestComponent>());
// Child
assert!(!world.entity(d).contains::<TestComponent>());
world
.entity_mut(a)
.remove_recursive::<Children, TestComponent>();
for entity in [a, b, c, d] {
assert!(!world.entity(entity).contains::<TestComponent>());
}
}
}

View File

@@ -0,0 +1,272 @@
use crate::{
entity::Entity,
query::{QueryData, QueryFilter},
relationship::{Relationship, RelationshipTarget},
system::Query,
};
use alloc::collections::VecDeque;
use smallvec::SmallVec;
use super::SourceIter;
impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// If the given `entity` contains the `R` [`Relationship`] component, returns the
/// target entity of that relationship.
pub fn related<R: Relationship>(&'w self, entity: Entity) -> Option<Entity>
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
{
self.get(entity).map(R::get).ok()
}
/// If the given `entity` contains the `S` [`RelationshipTarget`] component, returns the
/// source entities stored on that component.
pub fn relationship_sources<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
{
self.get(entity)
.into_iter()
.flat_map(RelationshipTarget::iter)
}
/// Recursively walks up the tree defined by the given `R` [`Relationship`] until
/// there are no more related entities, returning the "root entity" of the relationship hierarchy.
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn root_ancestor<R: Relationship>(&'w self, entity: Entity) -> Entity
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
{
// Recursively search up the tree until we're out of parents
match self.get(entity) {
Ok(parent) => self.root_ancestor(parent.get()),
Err(_) => entity,
}
}
/// Iterates all "leaf entities" as defined by the [`RelationshipTarget`] hierarchy.
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_leaves<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
self.iter_descendants_depth_first(entity).filter(|entity| {
self.get(*entity)
// These are leaf nodes if they have the `Children` component but it's empty
.map(|children| children.len() == 0)
// Or if they don't have the `Children` component at all
.unwrap_or(true)
})
}
/// Iterates all sibling entities that also have the `R` [`Relationship`] with the same target entity.
pub fn iter_siblings<R: Relationship>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
D::ReadOnly: QueryData<Item<'w> = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>,
{
self.get(entity)
.ok()
.and_then(|(maybe_parent, _)| maybe_parent.map(R::get))
.and_then(|parent| self.get(parent).ok())
.and_then(|(_, maybe_children)| maybe_children)
.into_iter()
.flat_map(move |children| children.iter().filter(move |child| *child != entity))
}
/// Iterates all descendant entities as defined by the given `entity`'s [`RelationshipTarget`] and their recursive
/// [`RelationshipTarget`].
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_descendants<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
DescendantIter::new(self, entity)
}
/// Iterates all descendant entities as defined by the given `entity`'s [`RelationshipTarget`] and their recursive
/// [`RelationshipTarget`] in depth-first order.
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_descendants_depth_first<S: RelationshipTarget>(
&'w self,
entity: Entity,
) -> DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
DescendantDepthFirstIter::new(self, entity)
}
/// Iterates all ancestors of the given `entity` as defined by the `R` [`Relationship`].
///
/// # Warning
///
/// For relationship graphs that contain loops, this could loop infinitely.
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn iter_ancestors<R: Relationship>(
&'w self,
entity: Entity,
) -> AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
AncestorIter::new(self, entity)
}
}
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
///
/// Traverses the hierarchy breadth-first.
pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
children_query: &'w Query<'w, 's, D, F>,
vecdeque: VecDeque<Entity>,
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
/// Returns a new [`DescendantIter`].
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
DescendantIter {
children_query,
vecdeque: children_query
.get(entity)
.into_iter()
.flat_map(RelationshipTarget::iter)
.collect(),
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
for DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
let entity = self.vecdeque.pop_front()?;
if let Ok(children) = self.children_query.get(entity) {
self.vecdeque.extend(children.iter());
}
Some(entity)
}
}
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
///
/// Traverses the hierarchy depth-first.
pub struct DescendantDepthFirstIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
children_query: &'w Query<'w, 's, D, F>,
stack: SmallVec<[Entity; 8]>,
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
/// Returns a new [`DescendantDepthFirstIter`].
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
DescendantDepthFirstIter {
children_query,
stack: children_query
.get(entity)
.map_or(SmallVec::new(), |children| children.iter().rev().collect()),
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
for DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
let entity = self.stack.pop()?;
if let Ok(children) = self.children_query.get(entity) {
self.stack.extend(children.iter().rev());
}
Some(entity)
}
}
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, R: Relationship>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
parent_query: &'w Query<'w, 's, D, F>,
next: Option<Entity>,
}
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
/// Returns a new [`AncestorIter`].
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
AncestorIter {
parent_query,
next: Some(entity),
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> Iterator
for AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.next = self.parent_query.get(self.next?).ok().map(R::get);
self.next
}
}

View File

@@ -0,0 +1,586 @@
use crate::entity::{hash_set::EntityHashSet, Entity};
use alloc::vec::Vec;
use smallvec::SmallVec;
/// The internal [`Entity`] collection used by a [`RelationshipTarget`](crate::relationship::RelationshipTarget) component.
/// This is not intended to be modified directly by users, as it could invalidate the correctness of relationships.
pub trait RelationshipSourceCollection {
/// The type of iterator returned by the `iter` method.
///
/// This is an associated type (rather than using a method that returns an opaque return-position impl trait)
/// to ensure that all methods and traits (like [`DoubleEndedIterator`]) of the underlying collection's iterator
/// are available to the user when implemented without unduly restricting the possible collections.
///
/// The [`SourceIter`](super::SourceIter) type alias can be helpful to reduce confusion when working with this associated type.
type SourceIter<'a>: Iterator<Item = Entity>
where
Self: 'a;
/// Creates a new empty instance.
fn new() -> Self;
/// Returns an instance with the given pre-allocated entity `capacity`.
///
/// Some collections will ignore the provided `capacity` and return a default instance.
fn with_capacity(capacity: usize) -> Self;
/// Reserves capacity for at least `additional` more entities to be inserted.
///
/// Not all collections support this operation, in which case it is a no-op.
fn reserve(&mut self, additional: usize);
/// Adds the given `entity` to the collection.
///
/// Returns whether the entity was added to the collection.
/// Mainly useful when dealing with collections that don't allow
/// multiple instances of the same entity ([`EntityHashSet`]).
fn add(&mut self, entity: Entity) -> bool;
/// Removes the given `entity` from the collection.
///
/// Returns whether the collection actually contained
/// the entity.
fn remove(&mut self, entity: Entity) -> bool;
/// Iterates all entities in the collection.
fn iter(&self) -> Self::SourceIter<'_>;
/// Returns the current length of the collection.
fn len(&self) -> usize;
/// Clears the collection.
fn clear(&mut self);
/// Attempts to save memory by shrinking the capacity to fit the current length.
///
/// This operation is a no-op for collections that do not support it.
fn shrink_to_fit(&mut self);
/// Returns true if the collection contains no entities.
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Add multiple entities to collection at once.
///
/// May be faster than repeatedly calling [`Self::add`].
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
// The method name shouldn't conflict with `Extend::extend` as it's in the rust prelude and
// would always conflict with it.
for entity in entities {
self.add(entity);
}
}
}
/// This trait signals that a [`RelationshipSourceCollection`] is ordered.
pub trait OrderedRelationshipSourceCollection: RelationshipSourceCollection {
/// Inserts the entity at a specific index.
/// If the index is too large, the entity will be added to the end of the collection.
fn insert(&mut self, index: usize, entity: Entity);
/// Removes the entity at the specified idnex if it exists.
fn remove_at(&mut self, index: usize) -> Option<Entity>;
/// Inserts the entity at a specific index.
/// This will never reorder other entities.
/// If the index is too large, the entity will be added to the end of the collection.
fn insert_stable(&mut self, index: usize, entity: Entity);
/// Removes the entity at the specified idnex if it exists.
/// This will never reorder other entities.
fn remove_at_stable(&mut self, index: usize) -> Option<Entity>;
/// Sorts the source collection.
fn sort(&mut self);
/// Inserts the entity at the proper place to maintain sorting.
fn insert_sorted(&mut self, entity: Entity);
/// This places the most recently added entity at the particular index.
fn place_most_recent(&mut self, index: usize);
/// This places the given entity at the particular index.
/// This will do nothing if the entity is not in the collection.
/// If the index is out of bounds, this will put the entity at the end.
fn place(&mut self, entity: Entity, index: usize);
/// Adds the entity at index 0.
fn push_front(&mut self, entity: Entity) {
self.insert(0, entity);
}
/// Adds the entity to the back of the collection.
fn push_back(&mut self, entity: Entity) {
self.insert(usize::MAX, entity);
}
/// Removes the first entity.
fn pop_front(&mut self) -> Option<Entity> {
self.remove_at(0)
}
/// Removes the last entity.
fn pop_back(&mut self) -> Option<Entity> {
if self.is_empty() {
None
} else {
self.remove_at(self.len() - 1)
}
}
}
impl RelationshipSourceCollection for Vec<Entity> {
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
fn new() -> Self {
Vec::new()
}
fn reserve(&mut self, additional: usize) {
Vec::reserve(self, additional);
}
fn with_capacity(capacity: usize) -> Self {
Vec::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
Vec::push(self, entity);
true
}
fn remove(&mut self, entity: Entity) -> bool {
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
Vec::remove(self, index);
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
<[Entity]>::iter(self).copied()
}
fn len(&self) -> usize {
Vec::len(self)
}
fn clear(&mut self) {
self.clear();
}
fn shrink_to_fit(&mut self) {
Vec::shrink_to_fit(self);
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl OrderedRelationshipSourceCollection for Vec<Entity> {
fn insert(&mut self, index: usize, entity: Entity) {
self.push(entity);
let len = self.len();
if index < len {
self.swap(index, len - 1);
}
}
fn remove_at(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.swap_remove(index))
}
fn insert_stable(&mut self, index: usize, entity: Entity) {
if index < self.len() {
Vec::insert(self, index, entity);
} else {
self.push(entity);
}
}
fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.remove(index))
}
fn sort(&mut self) {
self.sort_unstable();
}
fn insert_sorted(&mut self, entity: Entity) {
let index = self.partition_point(|e| e <= &entity);
self.insert_stable(index, entity);
}
fn place_most_recent(&mut self, index: usize) {
if let Some(entity) = self.pop() {
let index = index.min(self.len());
self.insert(index, entity);
}
}
fn place(&mut self, entity: Entity, index: usize) {
if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {
let index = index.min(self.len());
Vec::remove(self, current);
self.insert(index, entity);
};
}
}
impl RelationshipSourceCollection for EntityHashSet {
type SourceIter<'a> = core::iter::Copied<crate::entity::hash_set::Iter<'a>>;
fn new() -> Self {
EntityHashSet::new()
}
fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
fn with_capacity(capacity: usize) -> Self {
EntityHashSet::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
self.insert(entity)
}
fn remove(&mut self, entity: Entity) -> bool {
// We need to call the remove method on the underlying hash set,
// which takes its argument by reference
self.0.remove(&entity)
}
fn iter(&self) -> Self::SourceIter<'_> {
self.iter().copied()
}
fn len(&self) -> usize {
self.len()
}
fn clear(&mut self) {
self.0.clear();
}
fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl<const N: usize> RelationshipSourceCollection for SmallVec<[Entity; N]> {
type SourceIter<'a> = core::iter::Copied<core::slice::Iter<'a, Entity>>;
fn new() -> Self {
SmallVec::new()
}
fn reserve(&mut self, additional: usize) {
SmallVec::reserve(self, additional);
}
fn with_capacity(capacity: usize) -> Self {
SmallVec::with_capacity(capacity)
}
fn add(&mut self, entity: Entity) -> bool {
SmallVec::push(self, entity);
true
}
fn remove(&mut self, entity: Entity) -> bool {
if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) {
SmallVec::remove(self, index);
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
<[Entity]>::iter(self).copied()
}
fn len(&self) -> usize {
SmallVec::len(self)
}
fn clear(&mut self) {
self.clear();
}
fn shrink_to_fit(&mut self) {
SmallVec::shrink_to_fit(self);
}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
self.extend(entities);
}
}
impl RelationshipSourceCollection for Entity {
type SourceIter<'a> = core::option::IntoIter<Entity>;
fn new() -> Self {
Entity::PLACEHOLDER
}
fn reserve(&mut self, _: usize) {}
fn with_capacity(_capacity: usize) -> Self {
Self::new()
}
fn add(&mut self, entity: Entity) -> bool {
assert_eq!(
*self,
Entity::PLACEHOLDER,
"Entity {entity} attempted to target an entity with a one-to-one relationship, but it is already targeted by {}. You must remove the original relationship first.",
*self
);
*self = entity;
true
}
fn remove(&mut self, entity: Entity) -> bool {
if *self == entity {
*self = Entity::PLACEHOLDER;
return true;
}
false
}
fn iter(&self) -> Self::SourceIter<'_> {
if *self == Entity::PLACEHOLDER {
None.into_iter()
} else {
Some(*self).into_iter()
}
}
fn len(&self) -> usize {
if *self == Entity::PLACEHOLDER {
return 0;
}
1
}
fn clear(&mut self) {
*self = Entity::PLACEHOLDER;
}
fn shrink_to_fit(&mut self) {}
fn extend_from_iter(&mut self, entities: impl IntoIterator<Item = Entity>) {
for entity in entities {
assert_eq!(
*self,
Entity::PLACEHOLDER,
"Entity {entity} attempted to target an entity with a one-to-one relationship, but it is already targeted by {}. You must remove the original relationship first.",
*self
);
*self = entity;
}
}
}
impl<const N: usize> OrderedRelationshipSourceCollection for SmallVec<[Entity; N]> {
fn insert(&mut self, index: usize, entity: Entity) {
self.push(entity);
let len = self.len();
if index < len {
self.swap(index, len - 1);
}
}
fn remove_at(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.swap_remove(index))
}
fn insert_stable(&mut self, index: usize, entity: Entity) {
if index < self.len() {
SmallVec::<[Entity; N]>::insert(self, index, entity);
} else {
self.push(entity);
}
}
fn remove_at_stable(&mut self, index: usize) -> Option<Entity> {
(index < self.len()).then(|| self.remove(index))
}
fn sort(&mut self) {
self.sort_unstable();
}
fn insert_sorted(&mut self, entity: Entity) {
let index = self.partition_point(|e| e <= &entity);
self.insert_stable(index, entity);
}
fn place_most_recent(&mut self, index: usize) {
if let Some(entity) = self.pop() {
let index = index.min(self.len() - 1);
self.insert(index, entity);
}
}
fn place(&mut self, entity: Entity, index: usize) {
if let Some(current) = <[Entity]>::iter(self).position(|e| *e == entity) {
// The len is at least 1, so the subtraction is safe.
let index = index.min(self.len() - 1);
SmallVec::<[Entity; N]>::remove(self, current);
self.insert(index, entity);
};
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::{Component, World};
use crate::relationship::RelationshipTarget;
#[test]
fn vec_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel, linked_spawn)]
struct RelTarget(Vec<Entity>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &alloc::vec!(a));
}
#[test]
fn smallvec_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel, linked_spawn)]
struct RelTarget(SmallVec<[Entity; 4]>);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &SmallVec::from_buf([a]));
}
#[test]
fn entity_relationship_source_collection() {
#[derive(Component)]
#[relationship(relationship_target = RelTarget)]
struct Rel(Entity);
#[derive(Component)]
#[relationship_target(relationship = Rel)]
struct RelTarget(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Rel(b));
let rel_target = world.get::<RelTarget>(b).unwrap();
let collection = rel_target.collection();
assert_eq!(collection, &a);
}
#[test]
fn one_to_one_relationships() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Above(b));
assert_eq!(a, world.get::<Below>(b).unwrap().0);
// Verify removing target removes relationship
world.entity_mut(b).remove::<Below>();
assert!(world.get::<Above>(a).is_none());
// Verify removing relationship removes target
world.entity_mut(a).insert(Above(b));
world.entity_mut(a).remove::<Above>();
assert!(world.get::<Below>(b).is_none());
// Actually - a is above c now! Verify relationship was updated correctly
let c = world.spawn_empty().id();
world.entity_mut(a).insert(Above(c));
assert!(world.get::<Below>(b).is_none());
assert_eq!(a, world.get::<Below>(c).unwrap().0);
}
#[test]
#[should_panic]
fn one_to_one_relationship_shared_target() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
let c = world.spawn_empty().id();
world.entity_mut(a).insert(Above(c));
world.entity_mut(b).insert(Above(c));
}
#[test]
fn one_to_one_relationship_reinsert() {
#[derive(Component)]
#[relationship(relationship_target = Below)]
struct Above(Entity);
#[derive(Component)]
#[relationship_target(relationship = Above)]
struct Below(Entity);
let mut world = World::new();
let a = world.spawn_empty().id();
let b = world.spawn_empty().id();
world.entity_mut(a).insert(Above(b));
world.entity_mut(a).insert(Above(b));
}
}

268
vendor/bevy_ecs/src/removal_detection.rs vendored Normal file
View File

@@ -0,0 +1,268 @@
//! Alerting events when a component is removed from an entity.
use crate::{
component::{Component, ComponentId, ComponentIdFor, Tick},
entity::Entity,
event::{Event, EventCursor, EventId, EventIterator, EventIteratorWithId, Events},
prelude::Local,
storage::SparseSet,
system::{ReadOnlySystemParam, SystemMeta, SystemParam},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use derive_more::derive::Into;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::{
fmt::Debug,
iter,
marker::PhantomData,
ops::{Deref, DerefMut},
option,
};
/// Wrapper around [`Entity`] for [`RemovedComponents`].
/// Internally, `RemovedComponents` uses these as an `Events<RemovedComponentEntity>`.
#[derive(Event, Debug, Clone, Into)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Clone))]
pub struct RemovedComponentEntity(Entity);
/// Wrapper around a [`EventCursor<RemovedComponentEntity>`] so that we
/// can differentiate events between components.
#[derive(Debug)]
pub struct RemovedComponentReader<T>
where
T: Component,
{
reader: EventCursor<RemovedComponentEntity>,
marker: PhantomData<T>,
}
impl<T: Component> Default for RemovedComponentReader<T> {
fn default() -> Self {
Self {
reader: Default::default(),
marker: PhantomData,
}
}
}
impl<T: Component> Deref for RemovedComponentReader<T> {
type Target = EventCursor<RemovedComponentEntity>;
fn deref(&self) -> &Self::Target {
&self.reader
}
}
impl<T: Component> DerefMut for RemovedComponentReader<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.reader
}
}
/// Stores the [`RemovedComponents`] event buffers for all types of component in a given [`World`].
#[derive(Default, Debug)]
pub struct RemovedComponentEvents {
event_sets: SparseSet<ComponentId, Events<RemovedComponentEntity>>,
}
impl RemovedComponentEvents {
/// Creates an empty storage buffer for component removal events.
pub fn new() -> Self {
Self::default()
}
/// For each type of component, swaps the event buffers and clears the oldest event buffer.
/// In general, this should be called once per frame/update.
pub fn update(&mut self) {
for (_component_id, events) in self.event_sets.iter_mut() {
events.update();
}
}
/// Returns an iterator over components and their entity events.
pub fn iter(&self) -> impl Iterator<Item = (&ComponentId, &Events<RemovedComponentEntity>)> {
self.event_sets.iter()
}
/// Gets the event storage for a given component.
pub fn get(
&self,
component_id: impl Into<ComponentId>,
) -> Option<&Events<RemovedComponentEntity>> {
self.event_sets.get(component_id.into())
}
/// Sends a removal event for the specified component.
pub fn send(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
self.event_sets
.get_or_insert_with(component_id.into(), Default::default)
.send(RemovedComponentEntity(entity));
}
}
/// A [`SystemParam`] that yields entities that had their `T` [`Component`]
/// removed or have been despawned with it.
///
/// This acts effectively the same as an [`EventReader`](crate::event::EventReader).
///
/// Note that this does not allow you to see which data existed before removal.
/// If you need this, you will need to track the component data value on your own,
/// using a regularly scheduled system that requests `Query<(Entity, &T), Changed<T>>`
/// and stores the data somewhere safe to later cross-reference.
///
/// If you are using `bevy_ecs` as a standalone crate,
/// note that the `RemovedComponents` list will not be automatically cleared for you,
/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).
///
/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is
/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.
/// For the main world, this is delayed until after all `SubApp`s have run.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::system::IntoSystem;
/// # use bevy_ecs::removal_detection::RemovedComponents;
/// #
/// # #[derive(Component)]
/// # struct MyComponent;
/// fn react_on_removal(mut removed: RemovedComponents<MyComponent>) {
/// removed.read().for_each(|removed_entity| println!("{}", removed_entity));
/// }
/// # bevy_ecs::system::assert_is_system(react_on_removal);
/// ```
#[derive(SystemParam)]
pub struct RemovedComponents<'w, 's, T: Component> {
component_id: ComponentIdFor<'s, T>,
reader: Local<'s, RemovedComponentReader<T>>,
event_sets: &'w RemovedComponentEvents,
}
/// Iterator over entities that had a specific component removed.
///
/// See [`RemovedComponents`].
pub type RemovedIter<'a> = iter::Map<
iter::Flatten<option::IntoIter<iter::Cloned<EventIterator<'a, RemovedComponentEntity>>>>,
fn(RemovedComponentEntity) -> Entity,
>;
/// Iterator over entities that had a specific component removed.
///
/// See [`RemovedComponents`].
pub type RemovedIterWithId<'a> = iter::Map<
iter::Flatten<option::IntoIter<EventIteratorWithId<'a, RemovedComponentEntity>>>,
fn(
(&RemovedComponentEntity, EventId<RemovedComponentEntity>),
) -> (Entity, EventId<RemovedComponentEntity>),
>;
fn map_id_events(
(entity, id): (&RemovedComponentEntity, EventId<RemovedComponentEntity>),
) -> (Entity, EventId<RemovedComponentEntity>) {
(entity.clone().into(), id)
}
// For all practical purposes, the api surface of `RemovedComponents<T>`
// should be similar to `EventReader<T>` to reduce confusion.
impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> {
/// Fetch underlying [`EventCursor`].
pub fn reader(&self) -> &EventCursor<RemovedComponentEntity> {
&self.reader
}
/// Fetch underlying [`EventCursor`] mutably.
pub fn reader_mut(&mut self) -> &mut EventCursor<RemovedComponentEntity> {
&mut self.reader
}
/// Fetch underlying [`Events`].
pub fn events(&self) -> Option<&Events<RemovedComponentEntity>> {
self.event_sets.get(self.component_id.get())
}
/// Destructures to get a mutable reference to the `EventCursor`
/// and a reference to `Events`.
///
/// This is necessary since Rust can't detect destructuring through methods and most
/// usecases of the reader uses the `Events` as well.
pub fn reader_mut_with_events(
&mut self,
) -> Option<(
&mut RemovedComponentReader<T>,
&Events<RemovedComponentEntity>,
)> {
self.event_sets
.get(self.component_id.get())
.map(|events| (&mut *self.reader, events))
}
/// Iterates over the events this [`RemovedComponents`] has not seen yet. This updates the
/// [`RemovedComponents`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> RemovedIter<'_> {
self.reader_mut_with_events()
.map(|(reader, events)| reader.read(events).cloned())
.into_iter()
.flatten()
.map(RemovedComponentEntity::into)
}
/// Like [`read`](Self::read), except also returning the [`EventId`] of the events.
pub fn read_with_id(&mut self) -> RemovedIterWithId<'_> {
self.reader_mut_with_events()
.map(|(reader, events)| reader.read_with_id(events))
.into_iter()
.flatten()
.map(map_id_events)
}
/// Determines the number of removal events available to be read from this [`RemovedComponents`] without consuming any.
pub fn len(&self) -> usize {
self.events()
.map(|events| self.reader.len(events))
.unwrap_or(0)
}
/// Returns `true` if there are no events available to read.
pub fn is_empty(&self) -> bool {
self.events()
.is_none_or(|events| self.reader.is_empty(events))
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`RemovedComponents::read()`] or
/// [`RemovedComponents::read_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`.
pub fn clear(&mut self) {
if let Some((reader, events)) = self.reader_mut_with_events() {
reader.clear(events);
}
}
}
// SAFETY: Only reads World removed component events
unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentEvents {}
// SAFETY: no component value access.
unsafe impl<'a> SystemParam for &'a RemovedComponentEvents {
type State = ();
type Item<'w, 's> = &'w RemovedComponentEvents;
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.removed_components()
}
}

75
vendor/bevy_ecs/src/resource.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
//! Resources are unique, singleton-like data types that can be accessed from systems and stored in the [`World`](crate::world::World).
// The derive macro for the `Resource` trait
pub use bevy_ecs_macros::Resource;
/// A type that can be inserted into a [`World`] as a singleton.
///
/// You can access resource data in systems using the [`Res`] and [`ResMut`] system parameters
///
/// Only one resource of each type can be stored in a [`World`] at any given time.
///
/// # Examples
///
/// ```
/// # let mut world = World::default();
/// # let mut schedule = Schedule::default();
/// # use bevy_ecs::prelude::*;
/// #[derive(Resource)]
/// struct MyResource { value: u32 }
///
/// world.insert_resource(MyResource { value: 42 });
///
/// fn read_resource_system(resource: Res<MyResource>) {
/// assert_eq!(resource.value, 42);
/// }
///
/// fn write_resource_system(mut resource: ResMut<MyResource>) {
/// assert_eq!(resource.value, 42);
/// resource.value = 0;
/// assert_eq!(resource.value, 0);
/// }
/// # schedule.add_systems((read_resource_system, write_resource_system).chain());
/// # schedule.run(&mut world);
/// ```
///
/// # `!Sync` Resources
/// A `!Sync` type cannot implement `Resource`. However, it is possible to wrap a `Send` but not `Sync`
/// type in [`SyncCell`] or the currently unstable [`Exclusive`] to make it `Sync`. This forces only
/// having mutable access (`&mut T` only, never `&T`), but makes it safe to reference across multiple
/// threads.
///
/// This will fail to compile since `RefCell` is `!Sync`.
/// ```compile_fail
/// # use std::cell::RefCell;
/// # use bevy_ecs::resource::Resource;
///
/// #[derive(Resource)]
/// struct NotSync {
/// counter: RefCell<usize>,
/// }
/// ```
///
/// This will compile since the `RefCell` is wrapped with `SyncCell`.
/// ```
/// # use std::cell::RefCell;
/// # use bevy_ecs::resource::Resource;
/// use bevy_utils::synccell::SyncCell;
///
/// #[derive(Resource)]
/// struct ActuallySync {
/// counter: SyncCell<RefCell<usize>>,
/// }
/// ```
///
/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html
/// [`World`]: crate::world::World
/// [`Res`]: crate::system::Res
/// [`ResMut`]: crate::system::ResMut
/// [`SyncCell`]: bevy_utils::synccell::SyncCell
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a `Resource`",
label = "invalid `Resource`",
note = "consider annotating `{Self}` with `#[derive(Resource)]`"
)]
pub trait Resource: Send + Sync + 'static {}

View File

@@ -0,0 +1,252 @@
use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
use bevy_platform::collections::HashMap;
use crate::system::IntoSystem;
use crate::world::World;
use super::{
is_apply_deferred, ApplyDeferred, DiGraph, Direction, NodeId, ReportCycles, ScheduleBuildError,
ScheduleBuildPass, ScheduleGraph, SystemNode,
};
/// A [`ScheduleBuildPass`] that inserts [`ApplyDeferred`] systems into the schedule graph
/// when there are [`Deferred`](crate::prelude::Deferred)
/// in one system and there are ordering dependencies on that system. [`Commands`](crate::system::Commands) is one
/// such deferred buffer.
///
/// This pass is typically automatically added to the schedule. You can disable this by setting
/// [`ScheduleBuildSettings::auto_insert_apply_deferred`](crate::schedule::ScheduleBuildSettings::auto_insert_apply_deferred)
/// to `false`. You may want to disable this if you only want to sync deferred params at the end of the schedule,
/// or want to manually insert all your sync points.
#[derive(Debug, Default)]
pub struct AutoInsertApplyDeferredPass {
/// Dependency edges that will **not** automatically insert an instance of `ApplyDeferred` on the edge.
no_sync_edges: BTreeSet<(NodeId, NodeId)>,
auto_sync_node_ids: HashMap<u32, NodeId>,
}
/// If added to a dependency edge, the edge will not be considered for auto sync point insertions.
pub struct IgnoreDeferred;
impl AutoInsertApplyDeferredPass {
/// Returns the `NodeId` of the cached auto sync point. Will create
/// a new one if needed.
fn get_sync_point(&mut self, graph: &mut ScheduleGraph, distance: u32) -> NodeId {
self.auto_sync_node_ids
.get(&distance)
.copied()
.or_else(|| {
let node_id = self.add_auto_sync(graph);
self.auto_sync_node_ids.insert(distance, node_id);
Some(node_id)
})
.unwrap()
}
/// add an [`ApplyDeferred`] system with no config
fn add_auto_sync(&mut self, graph: &mut ScheduleGraph) -> NodeId {
let id = NodeId::System(graph.systems.len());
graph
.systems
.push(SystemNode::new(Box::new(IntoSystem::into_system(
ApplyDeferred,
))));
graph.system_conditions.push(Vec::new());
// ignore ambiguities with auto sync points
// They aren't under user control, so no one should know or care.
graph.ambiguous_with_all.insert(id);
id
}
}
impl ScheduleBuildPass for AutoInsertApplyDeferredPass {
type EdgeOptions = IgnoreDeferred;
fn add_dependency(&mut self, from: NodeId, to: NodeId, options: Option<&Self::EdgeOptions>) {
if options.is_some() {
self.no_sync_edges.insert((from, to));
}
}
fn build(
&mut self,
_world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError> {
let mut sync_point_graph = dependency_flattened.clone();
let topo = graph.topsort_graph(dependency_flattened, ReportCycles::Dependency)?;
fn set_has_conditions(graph: &ScheduleGraph, node: NodeId) -> bool {
!graph.set_conditions_at(node).is_empty()
|| graph
.hierarchy()
.graph()
.edges_directed(node, Direction::Incoming)
.any(|(parent, _)| set_has_conditions(graph, parent))
}
fn system_has_conditions(graph: &ScheduleGraph, node: NodeId) -> bool {
assert!(node.is_system());
!graph.system_conditions[node.index()].is_empty()
|| graph
.hierarchy()
.graph()
.edges_directed(node, Direction::Incoming)
.any(|(parent, _)| set_has_conditions(graph, parent))
}
let mut system_has_conditions_cache = HashMap::<usize, bool>::default();
let mut is_valid_explicit_sync_point = |system: NodeId| {
let index = system.index();
is_apply_deferred(graph.systems[index].get().unwrap())
&& !*system_has_conditions_cache
.entry(index)
.or_insert_with(|| system_has_conditions(graph, system))
};
// Calculate the distance for each node.
// The "distance" is the number of sync points between a node and the beginning of the graph.
// Also store if a preceding edge would have added a sync point but was ignored to add it at
// a later edge that is not ignored.
let mut distances_and_pending_sync: HashMap<usize, (u32, bool)> =
HashMap::with_capacity_and_hasher(topo.len(), Default::default());
// Keep track of any explicit sync nodes for a specific distance.
let mut distance_to_explicit_sync_node: HashMap<u32, NodeId> = HashMap::default();
// Determine the distance for every node and collect the explicit sync points.
for node in &topo {
let (node_distance, mut node_needs_sync) = distances_and_pending_sync
.get(&node.index())
.copied()
.unwrap_or_default();
if is_valid_explicit_sync_point(*node) {
// The distance of this sync point does not change anymore as the iteration order
// makes sure that this node is no unvisited target of another node.
// Because of this, the sync point can be stored for this distance to be reused as
// automatically added sync points later.
distance_to_explicit_sync_node.insert(node_distance, *node);
// This node just did a sync, so the only reason to do another sync is if one was
// explicitly scheduled afterwards.
node_needs_sync = false;
} else if !node_needs_sync {
// No previous node has postponed sync points to add so check if the system itself
// has deferred params that require a sync point to apply them.
node_needs_sync = graph.systems[node.index()].get().unwrap().has_deferred();
}
for target in dependency_flattened.neighbors_directed(*node, Direction::Outgoing) {
let (target_distance, target_pending_sync) = distances_and_pending_sync
.entry(target.index())
.or_default();
let mut edge_needs_sync = node_needs_sync;
if node_needs_sync
&& !graph.systems[target.index()].get().unwrap().is_exclusive()
&& self.no_sync_edges.contains(&(*node, target))
{
// The node has deferred params to apply, but this edge is ignoring sync points.
// Mark the target as 'delaying' those commands to a future edge and the current
// edge as not needing a sync point.
*target_pending_sync = true;
edge_needs_sync = false;
}
let mut weight = 0;
if edge_needs_sync || is_valid_explicit_sync_point(target) {
// The target distance grows if a sync point is added between it and the node.
// Also raise the distance if the target is a sync point itself so it then again
// raises the distance of following nodes as that is what the distance is about.
weight = 1;
}
// The target cannot have fewer sync points in front of it than the preceding node.
*target_distance = (node_distance + weight).max(*target_distance);
}
}
// Find any edges which have a different number of sync points between them and make sure
// there is a sync point between them.
for node in &topo {
let (node_distance, _) = distances_and_pending_sync
.get(&node.index())
.copied()
.unwrap_or_default();
for target in dependency_flattened.neighbors_directed(*node, Direction::Outgoing) {
let (target_distance, _) = distances_and_pending_sync
.get(&target.index())
.copied()
.unwrap_or_default();
if node_distance == target_distance {
// These nodes are the same distance, so they don't need an edge between them.
continue;
}
if is_apply_deferred(graph.systems[target.index()].get().unwrap()) {
// We don't need to insert a sync point since ApplyDeferred is a sync point
// already!
continue;
}
let sync_point = distance_to_explicit_sync_node
.get(&target_distance)
.copied()
.unwrap_or_else(|| self.get_sync_point(graph, target_distance));
sync_point_graph.add_edge(*node, sync_point);
sync_point_graph.add_edge(sync_point, target);
// The edge without the sync point is now redundant.
sync_point_graph.remove_edge(*node, target);
}
}
*dependency_flattened = sync_point_graph;
Ok(())
}
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
) -> impl Iterator<Item = (NodeId, NodeId)> {
if systems.is_empty() {
// collapse dependencies for empty sets
for a in dependency_flattened.neighbors_directed(set, Direction::Incoming) {
for b in dependency_flattened.neighbors_directed(set, Direction::Outgoing) {
if self.no_sync_edges.contains(&(a, set))
&& self.no_sync_edges.contains(&(set, b))
{
self.no_sync_edges.insert((a, b));
}
}
}
} else {
for a in dependency_flattened.neighbors_directed(set, Direction::Incoming) {
for &sys in systems {
if self.no_sync_edges.contains(&(a, set)) {
self.no_sync_edges.insert((a, sys));
}
}
}
for b in dependency_flattened.neighbors_directed(set, Direction::Outgoing) {
for &sys in systems {
if self.no_sync_edges.contains(&(set, b)) {
self.no_sync_edges.insert((sys, b));
}
}
}
}
core::iter::empty()
}
}

1411
vendor/bevy_ecs/src/schedule/condition.rs vendored Normal file

File diff suppressed because it is too large Load Diff

647
vendor/bevy_ecs/src/schedule/config.rs vendored Normal file
View File

@@ -0,0 +1,647 @@
use alloc::{boxed::Box, vec, vec::Vec};
use variadics_please::all_tuples;
use crate::{
error::Result,
never::Never,
schedule::{
auto_insert_apply_deferred::IgnoreDeferred,
condition::{BoxedCondition, Condition},
graph::{Ambiguity, Dependency, DependencyKind, GraphInfo},
set::{InternedSystemSet, IntoSystemSet, SystemSet},
Chain,
},
system::{BoxedSystem, InfallibleSystemWrapper, IntoSystem, ScheduleSystem, System},
};
fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
let condition_system = IntoSystem::into_system(condition);
assert!(
condition_system.is_send(),
"Condition `{}` accesses `NonSend` resources. This is not currently supported.",
condition_system.name()
);
Box::new(condition_system)
}
fn ambiguous_with(graph_info: &mut GraphInfo, set: InternedSystemSet) {
match &mut graph_info.ambiguous_with {
detection @ Ambiguity::Check => {
*detection = Ambiguity::IgnoreWithSet(vec![set]);
}
Ambiguity::IgnoreWithSet(ambiguous_with) => {
ambiguous_with.push(set);
}
Ambiguity::IgnoreAll => (),
}
}
/// Stores data to differentiate different schedulable structs.
pub trait Schedulable {
/// Additional data used to configure independent scheduling. Stored in [`ScheduleConfig`].
type Metadata;
/// Additional data used to configure a schedulable group. Stored in [`ScheduleConfigs`].
type GroupMetadata;
/// Initializes a configuration from this node.
fn into_config(self) -> ScheduleConfig<Self>
where
Self: Sized;
}
impl Schedulable for ScheduleSystem {
type Metadata = GraphInfo;
type GroupMetadata = Chain;
fn into_config(self) -> ScheduleConfig<Self> {
let sets = self.default_system_sets().clone();
ScheduleConfig {
node: self,
metadata: GraphInfo {
hierarchy: sets,
..Default::default()
},
conditions: Vec::new(),
}
}
}
impl Schedulable for InternedSystemSet {
type Metadata = GraphInfo;
type GroupMetadata = Chain;
fn into_config(self) -> ScheduleConfig<Self> {
assert!(
self.system_type().is_none(),
"configuring system type sets is not allowed"
);
ScheduleConfig {
node: self,
metadata: GraphInfo::default(),
conditions: Vec::new(),
}
}
}
/// Stores configuration for a single generic node (a system or a system set)
///
/// The configuration includes the node itself, scheduling metadata
/// (hierarchy: in which sets is the node contained,
/// dependencies: before/after which other nodes should this node run)
/// and the run conditions associated with this node.
pub struct ScheduleConfig<T: Schedulable> {
pub(crate) node: T,
pub(crate) metadata: T::Metadata,
pub(crate) conditions: Vec<BoxedCondition>,
}
/// Single or nested configurations for [`Schedulable`]s.
pub enum ScheduleConfigs<T: Schedulable> {
/// Configuration for a single [`Schedulable`].
ScheduleConfig(ScheduleConfig<T>),
/// Configuration for a tuple of nested `Configs` instances.
Configs {
/// Configuration for each element of the tuple.
configs: Vec<ScheduleConfigs<T>>,
/// Run conditions applied to everything in the tuple.
collective_conditions: Vec<BoxedCondition>,
/// Metadata to be applied to all elements in the tuple.
metadata: T::GroupMetadata,
},
}
impl<T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>> ScheduleConfigs<T> {
/// Adds a new boxed system set to the systems.
pub fn in_set_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config.metadata.hierarchy.push(set);
}
Self::Configs { configs, .. } => {
for config in configs {
config.in_set_inner(set);
}
}
}
}
fn before_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::Before, set));
}
Self::Configs { configs, .. } => {
for config in configs {
config.before_inner(set);
}
}
}
}
fn after_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::After, set));
}
Self::Configs { configs, .. } => {
for config in configs {
config.after_inner(set);
}
}
}
}
fn before_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::Before, set).add_config(IgnoreDeferred));
}
Self::Configs { configs, .. } => {
for config in configs {
config.before_ignore_deferred_inner(set.intern());
}
}
}
}
fn after_ignore_deferred_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
config
.metadata
.dependencies
.push(Dependency::new(DependencyKind::After, set).add_config(IgnoreDeferred));
}
Self::Configs { configs, .. } => {
for config in configs {
config.after_ignore_deferred_inner(set.intern());
}
}
}
}
fn distributive_run_if_inner<M>(&mut self, condition: impl Condition<M> + Clone) {
match self {
Self::ScheduleConfig(config) => {
config.conditions.push(new_condition(condition));
}
Self::Configs { configs, .. } => {
for config in configs {
config.distributive_run_if_inner(condition.clone());
}
}
}
}
fn ambiguous_with_inner(&mut self, set: InternedSystemSet) {
match self {
Self::ScheduleConfig(config) => {
ambiguous_with(&mut config.metadata, set);
}
Self::Configs { configs, .. } => {
for config in configs {
config.ambiguous_with_inner(set);
}
}
}
}
fn ambiguous_with_all_inner(&mut self) {
match self {
Self::ScheduleConfig(config) => {
config.metadata.ambiguous_with = Ambiguity::IgnoreAll;
}
Self::Configs { configs, .. } => {
for config in configs {
config.ambiguous_with_all_inner();
}
}
}
}
/// Adds a new boxed run condition to the systems.
///
/// This is useful if you have a run condition whose concrete type is unknown.
/// Prefer `run_if` for run conditions whose type is known at compile time.
pub fn run_if_dyn(&mut self, condition: BoxedCondition) {
match self {
Self::ScheduleConfig(config) => {
config.conditions.push(condition);
}
Self::Configs {
collective_conditions,
..
} => {
collective_conditions.push(condition);
}
}
}
fn chain_inner(mut self) -> Self {
match &mut self {
Self::ScheduleConfig(_) => { /* no op */ }
Self::Configs { metadata, .. } => {
metadata.set_chained();
}
};
self
}
fn chain_ignore_deferred_inner(mut self) -> Self {
match &mut self {
Self::ScheduleConfig(_) => { /* no op */ }
Self::Configs { metadata, .. } => {
metadata.set_chained_with_config(IgnoreDeferred);
}
}
self
}
}
/// Types that can convert into a [`ScheduleConfigs`].
///
/// This trait is implemented for "systems" (functions whose arguments all implement
/// [`SystemParam`](crate::system::SystemParam)), or tuples thereof.
/// It is a common entry point for system configurations.
///
/// # Usage notes
///
/// This trait should only be used as a bound for trait implementations or as an
/// argument to a function. If system configs need to be returned from a
/// function or stored somewhere, use [`ScheduleConfigs`] instead of this trait.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::{schedule::IntoScheduleConfigs, system::ScheduleSystem};
/// # struct AppMock;
/// # struct Update;
/// # impl AppMock {
/// # pub fn add_systems<M>(
/// # &mut self,
/// # schedule: Update,
/// # systems: impl IntoScheduleConfigs<ScheduleSystem, M>,
/// # ) -> &mut Self { self }
/// # }
/// # let mut app = AppMock;
///
/// fn handle_input() {}
///
/// fn update_camera() {}
/// fn update_character() {}
///
/// app.add_systems(
/// Update,
/// (
/// handle_input,
/// (update_camera, update_character).after(handle_input)
/// )
/// );
/// ```
#[diagnostic::on_unimplemented(
message = "`{Self}` does not describe a valid system configuration",
label = "invalid system configuration"
)]
pub trait IntoScheduleConfigs<T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>, Marker>:
Sized
{
/// Convert into a [`ScheduleConfigs`].
fn into_configs(self) -> ScheduleConfigs<T>;
/// Add these systems to the provided `set`.
#[track_caller]
fn in_set(self, set: impl SystemSet) -> ScheduleConfigs<T> {
self.into_configs().in_set(set)
}
/// Runs before all systems in `set`. If `self` has any systems that produce [`Commands`](crate::system::Commands)
/// or other [`Deferred`](crate::system::Deferred) operations, all systems in `set` will see their effect.
///
/// If automatically inserting [`ApplyDeferred`](crate::schedule::ApplyDeferred) like
/// this isn't desired, use [`before_ignore_deferred`](Self::before_ignore_deferred) instead.
///
/// Calling [`.chain`](Self::chain) is often more convenient and ensures that all systems are added to the schedule.
/// Please check the [caveats section of `.after`](Self::after) for details.
fn before<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().before(set)
}
/// Run after all systems in `set`. If `set` has any systems that produce [`Commands`](crate::system::Commands)
/// or other [`Deferred`](crate::system::Deferred) operations, all systems in `self` will see their effect.
///
/// If automatically inserting [`ApplyDeferred`](crate::schedule::ApplyDeferred) like
/// this isn't desired, use [`after_ignore_deferred`](Self::after_ignore_deferred) instead.
///
/// Calling [`.chain`](Self::chain) is often more convenient and ensures that all systems are added to the schedule.
///
/// # Caveats
///
/// If you configure two [`System`]s like `(GameSystem::A).after(GameSystem::B)` or `(GameSystem::A).before(GameSystem::B)`, the `GameSystem::B` will not be automatically scheduled.
///
/// This means that the system `GameSystem::A` and the system or systems in `GameSystem::B` will run independently of each other if `GameSystem::B` was never explicitly scheduled with [`configure_sets`]
/// If that is the case, `.after`/`.before` will not provide the desired behavior
/// and the systems can run in parallel or in any order determined by the scheduler.
/// Only use `after(GameSystem::B)` and `before(GameSystem::B)` when you know that `B` has already been scheduled for you,
/// e.g. when it was provided by Bevy or a third-party dependency,
/// or you manually scheduled it somewhere else in your app.
///
/// Another caveat is that if `GameSystem::B` is placed in a different schedule than `GameSystem::A`,
/// any ordering calls between them—whether using `.before`, `.after`, or `.chain`—will be silently ignored.
///
/// [`configure_sets`]: https://docs.rs/bevy/latest/bevy/app/struct.App.html#method.configure_sets
fn after<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().after(set)
}
/// Run before all systems in `set`.
///
/// Unlike [`before`](Self::before), this will not cause the systems in
/// `set` to wait for the deferred effects of `self` to be applied.
fn before_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().before_ignore_deferred(set)
}
/// Run after all systems in `set`.
///
/// Unlike [`after`](Self::after), this will not wait for the deferred
/// effects of systems in `set` to be applied.
fn after_ignore_deferred<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().after_ignore_deferred(set)
}
/// Add a run condition to each contained system.
///
/// Each system will receive its own clone of the [`Condition`] and will only run
/// if the `Condition` is true.
///
/// Each individual condition will be evaluated at most once (per schedule run),
/// right before the corresponding system prepares to run.
///
/// This is equivalent to calling [`run_if`](IntoScheduleConfigs::run_if) on each individual
/// system, as shown below:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut schedule = Schedule::default();
/// # fn a() {}
/// # fn b() {}
/// # fn condition() -> bool { true }
/// schedule.add_systems((a, b).distributive_run_if(condition));
/// schedule.add_systems((a.run_if(condition), b.run_if(condition)));
/// ```
///
/// # Note
///
/// Because the conditions are evaluated separately for each system, there is no guarantee
/// that all evaluations in a single schedule run will yield the same result. If another
/// system is run inbetween two evaluations it could cause the result of the condition to change.
///
/// Use [`run_if`](ScheduleConfigs::run_if) on a [`SystemSet`] if you want to make sure
/// that either all or none of the systems are run, or you don't want to evaluate the run
/// condition for each contained system separately.
fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> ScheduleConfigs<T> {
self.into_configs().distributive_run_if(condition)
}
/// Run the systems only if the [`Condition`] is `true`.
///
/// The `Condition` will be evaluated at most once (per schedule run),
/// the first time a system in this set prepares to run.
///
/// If this set contains more than one system, calling `run_if` is equivalent to adding each
/// system to a common set and configuring the run condition on that set, as shown below:
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let mut schedule = Schedule::default();
/// # fn a() {}
/// # fn b() {}
/// # fn condition() -> bool { true }
/// # #[derive(SystemSet, Debug, Eq, PartialEq, Hash, Clone, Copy)]
/// # struct C;
/// schedule.add_systems((a, b).run_if(condition));
/// schedule.add_systems((a, b).in_set(C)).configure_sets(C.run_if(condition));
/// ```
///
/// # Note
///
/// Because the condition will only be evaluated once, there is no guarantee that the condition
/// is upheld after the first system has run. You need to make sure that no other systems that
/// could invalidate the condition are scheduled inbetween the first and last run system.
///
/// Use [`distributive_run_if`](IntoScheduleConfigs::distributive_run_if) if you want the
/// condition to be evaluated for each individual system, right before one is run.
fn run_if<M>(self, condition: impl Condition<M>) -> ScheduleConfigs<T> {
self.into_configs().run_if(condition)
}
/// Suppress warnings and errors that would result from these systems having ambiguities
/// (conflicting access but indeterminate order) with systems in `set`.
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> ScheduleConfigs<T> {
self.into_configs().ambiguous_with(set)
}
/// Suppress warnings and errors that would result from these systems having ambiguities
/// (conflicting access but indeterminate order) with any other system.
fn ambiguous_with_all(self) -> ScheduleConfigs<T> {
self.into_configs().ambiguous_with_all()
}
/// Treat this collection as a sequence of systems.
///
/// Ordering constraints will be applied between the successive elements.
///
/// If the preceding node on an edge has deferred parameters, an [`ApplyDeferred`](crate::schedule::ApplyDeferred)
/// will be inserted on the edge. If this behavior is not desired consider using
/// [`chain_ignore_deferred`](Self::chain_ignore_deferred) instead.
fn chain(self) -> ScheduleConfigs<T> {
self.into_configs().chain()
}
/// Treat this collection as a sequence of systems.
///
/// Ordering constraints will be applied between the successive elements.
///
/// Unlike [`chain`](Self::chain) this will **not** add [`ApplyDeferred`](crate::schedule::ApplyDeferred) on the edges.
fn chain_ignore_deferred(self) -> ScheduleConfigs<T> {
self.into_configs().chain_ignore_deferred()
}
}
impl<T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>> IntoScheduleConfigs<T, ()>
for ScheduleConfigs<T>
{
fn into_configs(self) -> Self {
self
}
#[track_caller]
fn in_set(mut self, set: impl SystemSet) -> Self {
assert!(
set.system_type().is_none(),
"adding arbitrary systems to a system type set is not allowed"
);
self.in_set_inner(set.intern());
self
}
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.before_inner(set.intern());
self
}
fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.after_inner(set.intern());
self
}
fn before_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.before_ignore_deferred_inner(set.intern());
self
}
fn after_ignore_deferred<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.after_ignore_deferred_inner(set.intern());
self
}
fn distributive_run_if<M>(
mut self,
condition: impl Condition<M> + Clone,
) -> ScheduleConfigs<T> {
self.distributive_run_if_inner(condition);
self
}
fn run_if<M>(mut self, condition: impl Condition<M>) -> ScheduleConfigs<T> {
self.run_if_dyn(new_condition(condition));
self
}
fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
let set = set.into_system_set();
self.ambiguous_with_inner(set.intern());
self
}
fn ambiguous_with_all(mut self) -> Self {
self.ambiguous_with_all_inner();
self
}
fn chain(self) -> Self {
self.chain_inner()
}
fn chain_ignore_deferred(self) -> Self {
self.chain_ignore_deferred_inner()
}
}
/// Marker component to allow for conflicting implementations of [`IntoScheduleConfigs`]
#[doc(hidden)]
pub struct Infallible;
impl<F, Marker> IntoScheduleConfigs<ScheduleSystem, (Infallible, Marker)> for F
where
F: IntoSystem<(), (), Marker>,
{
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
let wrapper = InfallibleSystemWrapper::new(IntoSystem::into_system(self));
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(Box::new(wrapper)))
}
}
impl<F, Marker> IntoScheduleConfigs<ScheduleSystem, (Never, Marker)> for F
where
F: IntoSystem<(), Never, Marker>,
{
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
let wrapper = InfallibleSystemWrapper::new(IntoSystem::into_system(self));
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(Box::new(wrapper)))
}
}
/// Marker component to allow for conflicting implementations of [`IntoScheduleConfigs`]
#[doc(hidden)]
pub struct Fallible;
impl<F, Marker> IntoScheduleConfigs<ScheduleSystem, (Fallible, Marker)> for F
where
F: IntoSystem<(), Result, Marker>,
{
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
let boxed_system = Box::new(IntoSystem::into_system(self));
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(boxed_system))
}
}
impl IntoScheduleConfigs<ScheduleSystem, ()> for BoxedSystem<(), Result> {
fn into_configs(self) -> ScheduleConfigs<ScheduleSystem> {
ScheduleConfigs::ScheduleConfig(ScheduleSystem::into_config(self))
}
}
impl<S: SystemSet> IntoScheduleConfigs<InternedSystemSet, ()> for S {
fn into_configs(self) -> ScheduleConfigs<InternedSystemSet> {
ScheduleConfigs::ScheduleConfig(InternedSystemSet::into_config(self.intern()))
}
}
#[doc(hidden)]
pub struct ScheduleConfigTupleMarker;
macro_rules! impl_node_type_collection {
($(#[$meta:meta])* $(($param: ident, $sys: ident)),*) => {
$(#[$meta])*
impl<$($param, $sys),*, T: Schedulable<Metadata = GraphInfo, GroupMetadata = Chain>> IntoScheduleConfigs<T, (ScheduleConfigTupleMarker, $($param,)*)> for ($($sys,)*)
where
$($sys: IntoScheduleConfigs<T, $param>),*
{
#[expect(
clippy::allow_attributes,
reason = "We are inside a macro, and as such, `non_snake_case` is not guaranteed to apply."
)]
#[allow(
non_snake_case,
reason = "Variable names are provided by the macro caller, not by us."
)]
fn into_configs(self) -> ScheduleConfigs<T> {
let ($($sys,)*) = self;
ScheduleConfigs::Configs {
metadata: Default::default(),
configs: vec![$($sys.into_configs(),)*],
collective_conditions: Vec::new(),
}
}
}
}
}
all_tuples!(
#[doc(fake_variadic)]
impl_node_type_collection,
1,
20,
P,
S
);

View File

@@ -0,0 +1,572 @@
#[cfg(feature = "std")]
mod multi_threaded;
mod simple;
mod single_threaded;
use alloc::{borrow::Cow, vec, vec::Vec};
use core::any::TypeId;
pub use self::{simple::SimpleExecutor, single_threaded::SingleThreadedExecutor};
#[cfg(feature = "std")]
pub use self::multi_threaded::{MainThreadExecutor, MultiThreadedExecutor};
use fixedbitset::FixedBitSet;
use crate::{
archetype::ArchetypeComponentId,
component::{ComponentId, Tick},
error::{BevyError, ErrorContext, Result},
prelude::{IntoSystemSet, SystemSet},
query::Access,
schedule::{BoxedCondition, InternedSystemSet, NodeId, SystemTypeSet},
system::{ScheduleSystem, System, SystemIn, SystemParamValidationError},
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
};
/// Types that can run a [`SystemSchedule`] on a [`World`].
pub(super) trait SystemExecutor: Send + Sync {
fn kind(&self) -> ExecutorKind;
fn init(&mut self, schedule: &SystemSchedule);
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
);
fn set_apply_final_deferred(&mut self, value: bool);
}
/// Specifies how a [`Schedule`](super::Schedule) will be run.
///
/// The default depends on the target platform:
/// - [`SingleThreaded`](ExecutorKind::SingleThreaded) on Wasm.
/// - [`MultiThreaded`](ExecutorKind::MultiThreaded) everywhere else.
#[derive(PartialEq, Eq, Default, Debug, Copy, Clone)]
pub enum ExecutorKind {
/// Runs the schedule using a single thread.
///
/// Useful if you're dealing with a single-threaded environment, saving your threads for
/// other things, or just trying minimize overhead.
#[cfg_attr(any(target_arch = "wasm32", not(feature = "multi_threaded")), default)]
SingleThreaded,
/// Like [`SingleThreaded`](ExecutorKind::SingleThreaded) but calls [`apply_deferred`](crate::system::System::apply_deferred)
/// immediately after running each system.
Simple,
/// Runs the schedule using a thread pool. Non-conflicting systems can run in parallel.
#[cfg(feature = "std")]
#[cfg_attr(all(not(target_arch = "wasm32"), feature = "multi_threaded"), default)]
MultiThreaded,
}
/// Holds systems and conditions of a [`Schedule`](super::Schedule) sorted in topological order
/// (along with dependency information for `multi_threaded` execution).
///
/// Since the arrays are sorted in the same order, elements are referenced by their index.
/// [`FixedBitSet`] is used as a smaller, more efficient substitute of `HashSet<usize>`.
#[derive(Default)]
pub struct SystemSchedule {
/// List of system node ids.
pub(super) system_ids: Vec<NodeId>,
/// Indexed by system node id.
pub(super) systems: Vec<ScheduleSystem>,
/// Indexed by system node id.
pub(super) system_conditions: Vec<Vec<BoxedCondition>>,
/// Indexed by system node id.
/// Number of systems that the system immediately depends on.
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
pub(super) system_dependencies: Vec<usize>,
/// Indexed by system node id.
/// List of systems that immediately depend on the system.
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
pub(super) system_dependents: Vec<Vec<usize>>,
/// Indexed by system node id.
/// List of sets containing the system that have conditions
pub(super) sets_with_conditions_of_systems: Vec<FixedBitSet>,
/// List of system set node ids.
pub(super) set_ids: Vec<NodeId>,
/// Indexed by system set node id.
pub(super) set_conditions: Vec<Vec<BoxedCondition>>,
/// Indexed by system set node id.
/// List of systems that are in sets that have conditions.
///
/// If a set doesn't run because of its conditions, this is used to skip all systems in it.
pub(super) systems_in_sets_with_conditions: Vec<FixedBitSet>,
}
impl SystemSchedule {
/// Creates an empty [`SystemSchedule`].
pub const fn new() -> Self {
Self {
systems: Vec::new(),
system_conditions: Vec::new(),
set_conditions: Vec::new(),
system_ids: Vec::new(),
set_ids: Vec::new(),
system_dependencies: Vec::new(),
system_dependents: Vec::new(),
sets_with_conditions_of_systems: Vec::new(),
systems_in_sets_with_conditions: Vec::new(),
}
}
}
/// See [`ApplyDeferred`].
#[deprecated(
since = "0.16.0",
note = "Use `ApplyDeferred` instead. This was previously a function but is now a marker struct System."
)]
#[expect(
non_upper_case_globals,
reason = "This item is deprecated; as such, its previous name needs to stay."
)]
pub const apply_deferred: ApplyDeferred = ApplyDeferred;
/// A special [`System`] that instructs the executor to call
/// [`System::apply_deferred`] on the systems that have run but not applied
/// their [`Deferred`] system parameters (like [`Commands`]) or other system buffers.
///
/// ## Scheduling
///
/// `ApplyDeferred` systems are scheduled *by default*
/// - later in the same schedule run (for example, if a system with `Commands` param
/// is scheduled in `Update`, all the changes will be visible in `PostUpdate`)
/// - between systems with dependencies if the dependency [has deferred buffers]
/// (if system `bar` directly or indirectly depends on `foo`, and `foo` uses
/// `Commands` param, changes to the world in `foo` will be visible in `bar`)
///
/// ## Notes
/// - This system (currently) does nothing if it's called manually or wrapped
/// inside a [`PipeSystem`].
/// - Modifying a [`Schedule`] may change the order buffers are applied.
///
/// [`System::apply_deferred`]: crate::system::System::apply_deferred
/// [`Deferred`]: crate::system::Deferred
/// [`Commands`]: crate::prelude::Commands
/// [has deferred buffers]: crate::system::System::has_deferred
/// [`PipeSystem`]: crate::system::PipeSystem
/// [`Schedule`]: super::Schedule
#[doc(alias = "apply_system_buffers")]
pub struct ApplyDeferred;
/// Returns `true` if the [`System`] is an instance of [`ApplyDeferred`].
pub(super) fn is_apply_deferred(system: &ScheduleSystem) -> bool {
system.type_id() == TypeId::of::<ApplyDeferred>()
}
impl System for ApplyDeferred {
type In = ();
type Out = Result<()>;
fn name(&self) -> Cow<'static, str> {
Cow::Borrowed("bevy_ecs::apply_deferred")
}
fn component_access(&self) -> &Access<ComponentId> {
// This system accesses no components.
const { &Access::new() }
}
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
// This system accesses no archetype components.
const { &Access::new() }
}
fn is_send(&self) -> bool {
// Although this system itself does nothing on its own, the system
// executor uses it to apply deferred commands. Commands must be allowed
// to access non-send resources, so this system must be non-send for
// scheduling purposes.
false
}
fn is_exclusive(&self) -> bool {
// This system is labeled exclusive because it is used by the system
// executor to find places where deferred commands should be applied,
// and commands can only be applied with exclusive access to the world.
true
}
fn has_deferred(&self) -> bool {
// This system itself doesn't have any commands to apply, but when it
// is pulled from the schedule to be ran, the executor will apply
// deferred commands from other systems.
false
}
unsafe fn run_unsafe(
&mut self,
_input: SystemIn<'_, Self>,
_world: UnsafeWorldCell,
) -> Self::Out {
// This system does nothing on its own. The executor will apply deferred
// commands from other systems instead of running this system.
Ok(())
}
fn run(&mut self, _input: SystemIn<'_, Self>, _world: &mut World) -> Self::Out {
// This system does nothing on its own. The executor will apply deferred
// commands from other systems instead of running this system.
Ok(())
}
fn apply_deferred(&mut self, _world: &mut World) {}
fn queue_deferred(&mut self, _world: DeferredWorld) {}
unsafe fn validate_param_unsafe(
&mut self,
_world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
// This system is always valid to run because it doesn't do anything,
// and only used as a marker for the executor.
Ok(())
}
fn initialize(&mut self, _world: &mut World) {}
fn update_archetype_component_access(&mut self, _world: UnsafeWorldCell) {}
fn check_change_tick(&mut self, _change_tick: Tick) {}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
vec![SystemTypeSet::<Self>::new().intern()]
}
fn get_last_run(&self) -> Tick {
// This system is never run, so it has no last run tick.
Tick::MAX
}
fn set_last_run(&mut self, _last_run: Tick) {}
}
impl IntoSystemSet<()> for ApplyDeferred {
type Set = SystemTypeSet<Self>;
fn into_system_set(self) -> Self::Set {
SystemTypeSet::<Self>::new()
}
}
/// These functions hide the bottom of the callstack from `RUST_BACKTRACE=1` (assuming the default panic handler is used).
///
/// The full callstack will still be visible with `RUST_BACKTRACE=full`.
/// They are specialized for `System::run` & co instead of being generic over closures because this avoids an
/// extra frame in the backtrace.
///
/// This is reliant on undocumented behavior in Rust's default panic handler, which checks the call stack for symbols
/// containing the string `__rust_begin_short_backtrace` in their mangled name.
mod __rust_begin_short_backtrace {
use core::hint::black_box;
use crate::{
error::Result,
system::{ReadOnlySystem, ScheduleSystem},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
/// # Safety
/// See `System::run_unsafe`.
#[inline(never)]
pub(super) unsafe fn run_unsafe(system: &mut ScheduleSystem, world: UnsafeWorldCell) -> Result {
let result = system.run_unsafe((), world);
black_box(());
result
}
/// # Safety
/// See `ReadOnlySystem::run_unsafe`.
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
#[inline(never)]
pub(super) unsafe fn readonly_run_unsafe<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: UnsafeWorldCell,
) -> O {
black_box(system.run_unsafe((), world))
}
#[inline(never)]
pub(super) fn run(system: &mut ScheduleSystem, world: &mut World) -> Result {
let result = system.run((), world);
black_box(());
result
}
#[inline(never)]
pub(super) fn readonly_run<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: &mut World,
) -> O {
black_box(system.run((), world))
}
}
#[cfg(test)]
mod tests {
use crate::{
prelude::{Component, In, IntoSystem, Resource, Schedule},
schedule::ExecutorKind,
system::{Populated, Res, ResMut, Single},
world::World,
};
#[derive(Component)]
struct TestComponent;
const EXECUTORS: [ExecutorKind; 3] = [
ExecutorKind::Simple,
ExecutorKind::SingleThreaded,
ExecutorKind::MultiThreaded,
];
#[derive(Resource, Default)]
struct TestState {
populated_ran: bool,
single_ran: bool,
}
#[derive(Resource, Default)]
struct Counter(u8);
fn set_single_state(mut _single: Single<&TestComponent>, mut state: ResMut<TestState>) {
state.single_ran = true;
}
fn set_populated_state(
mut _populated: Populated<&TestComponent>,
mut state: ResMut<TestState>,
) {
state.populated_ran = true;
}
#[test]
#[expect(clippy::print_stdout, reason = "std and println are allowed in tests")]
fn single_and_populated_skipped_and_run() {
for executor in EXECUTORS {
std::println!("Testing executor: {:?}", executor);
let mut world = World::new();
world.init_resource::<TestState>();
let mut schedule = Schedule::default();
schedule.set_executor_kind(executor);
schedule.add_systems((set_single_state, set_populated_state));
schedule.run(&mut world);
let state = world.get_resource::<TestState>().unwrap();
assert!(!state.single_ran);
assert!(!state.populated_ran);
world.spawn(TestComponent);
schedule.run(&mut world);
let state = world.get_resource::<TestState>().unwrap();
assert!(state.single_ran);
assert!(state.populated_ran);
}
}
fn look_for_missing_resource(_res: Res<TestState>) {}
#[test]
#[should_panic]
fn missing_resource_panics_simple() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::Simple);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn missing_resource_panics_single_threaded() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::SingleThreaded);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn missing_resource_panics_multi_threaded() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::MultiThreaded);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
}
#[test]
fn piped_systems_first_system_skipped() {
// This system should be skipped when run due to no matching entity
fn pipe_out(_single: Single<&TestComponent>) -> u8 {
42
}
fn pipe_in(_input: In<u8>, mut counter: ResMut<Counter>) {
counter.0 += 1;
}
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
let counter = world.resource::<Counter>();
assert_eq!(counter.0, 0);
}
#[test]
fn piped_system_second_system_skipped() {
fn pipe_out(mut counter: ResMut<Counter>) -> u8 {
counter.0 += 1;
42
}
// This system should be skipped when run due to no matching entity
fn pipe_in(_input: In<u8>, _single: Single<&TestComponent>) {}
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
let counter = world.resource::<Counter>();
assert_eq!(counter.0, 0);
}
#[test]
#[should_panic]
fn piped_system_first_system_panics() {
// This system should panic when run because the resource is missing
fn pipe_out(_res: Res<TestState>) -> u8 {
42
}
fn pipe_in(_input: In<u8>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn piped_system_second_system_panics() {
fn pipe_out() -> u8 {
42
}
// This system should panic when run because the resource is missing
fn pipe_in(_input: In<u8>, _res: Res<TestState>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
// This test runs without panicking because we've
// decided to use early-out behavior for piped systems
#[test]
fn piped_system_skip_and_panic() {
// This system should be skipped when run due to no matching entity
fn pipe_out(_single: Single<&TestComponent>) -> u8 {
42
}
// This system should panic when run because the resource is missing
fn pipe_in(_input: In<u8>, _res: Res<TestState>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn piped_system_panic_and_skip() {
// This system should panic when run because the resource is missing
fn pipe_out(_res: Res<TestState>) -> u8 {
42
}
// This system should be skipped when run due to no matching entity
fn pipe_in(_input: In<u8>, _single: Single<&TestComponent>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
#[should_panic]
fn piped_system_panic_and_panic() {
// This system should panic when run because the resource is missing
fn pipe_out(_res: Res<TestState>) -> u8 {
42
}
// This system should panic when run because the resource is missing
fn pipe_in(_input: In<u8>, _res: Res<TestState>) {}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
}
#[test]
fn piped_system_skip_and_skip() {
// This system should be skipped when run due to no matching entity
fn pipe_out(_single: Single<&TestComponent>, mut counter: ResMut<Counter>) -> u8 {
counter.0 += 1;
42
}
// This system should be skipped when run due to no matching entity
fn pipe_in(_input: In<u8>, _single: Single<&TestComponent>, mut counter: ResMut<Counter>) {
counter.0 += 1;
}
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.add_systems(pipe_out.pipe(pipe_in));
schedule.run(&mut world);
let counter = world.resource::<Counter>();
assert_eq!(counter.0, 0);
}
}

View File

@@ -0,0 +1,886 @@
use alloc::{boxed::Box, vec::Vec};
use bevy_platform::sync::Arc;
use bevy_tasks::{ComputeTaskPool, Scope, TaskPool, ThreadExecutor};
use bevy_utils::{default, syncunsafecell::SyncUnsafeCell};
use concurrent_queue::ConcurrentQueue;
use core::{any::Any, panic::AssertUnwindSafe};
use fixedbitset::FixedBitSet;
#[cfg(feature = "std")]
use std::eprintln;
use std::sync::{Mutex, MutexGuard};
#[cfg(feature = "trace")]
use tracing::{info_span, Span};
use crate::{
archetype::ArchetypeComponentId,
error::{default_error_handler, BevyError, ErrorContext, Result},
prelude::Resource,
query::Access,
schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
system::ScheduleSystem,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use super::__rust_begin_short_backtrace;
/// Borrowed data used by the [`MultiThreadedExecutor`].
struct Environment<'env, 'sys> {
executor: &'env MultiThreadedExecutor,
systems: &'sys [SyncUnsafeCell<ScheduleSystem>],
conditions: SyncUnsafeCell<Conditions<'sys>>,
world_cell: UnsafeWorldCell<'env>,
}
struct Conditions<'a> {
system_conditions: &'a mut [Vec<BoxedCondition>],
set_conditions: &'a mut [Vec<BoxedCondition>],
sets_with_conditions_of_systems: &'a [FixedBitSet],
systems_in_sets_with_conditions: &'a [FixedBitSet],
}
impl<'env, 'sys> Environment<'env, 'sys> {
fn new(
executor: &'env MultiThreadedExecutor,
schedule: &'sys mut SystemSchedule,
world: &'env mut World,
) -> Self {
Environment {
executor,
systems: SyncUnsafeCell::from_mut(schedule.systems.as_mut_slice()).as_slice_of_cells(),
conditions: SyncUnsafeCell::new(Conditions {
system_conditions: &mut schedule.system_conditions,
set_conditions: &mut schedule.set_conditions,
sets_with_conditions_of_systems: &schedule.sets_with_conditions_of_systems,
systems_in_sets_with_conditions: &schedule.systems_in_sets_with_conditions,
}),
world_cell: world.as_unsafe_world_cell(),
}
}
}
/// Per-system data used by the [`MultiThreadedExecutor`].
// Copied here because it can't be read from the system when it's running.
struct SystemTaskMetadata {
/// The [`ArchetypeComponentId`] access of the system.
archetype_component_access: Access<ArchetypeComponentId>,
/// Indices of the systems that directly depend on the system.
dependents: Vec<usize>,
/// Is `true` if the system does not access `!Send` data.
is_send: bool,
/// Is `true` if the system is exclusive.
is_exclusive: bool,
}
/// The result of running a system that is sent across a channel.
struct SystemResult {
system_index: usize,
}
/// Runs the schedule using a thread pool. Non-conflicting systems can run in parallel.
pub struct MultiThreadedExecutor {
/// The running state, protected by a mutex so that a reference to the executor can be shared across tasks.
state: Mutex<ExecutorState>,
/// Queue of system completion events.
system_completion: ConcurrentQueue<SystemResult>,
/// Setting when true applies deferred system buffers after all systems have run
apply_final_deferred: bool,
/// When set, tells the executor that a thread has panicked.
panic_payload: Mutex<Option<Box<dyn Any + Send>>>,
starting_systems: FixedBitSet,
/// Cached tracing span
#[cfg(feature = "trace")]
executor_span: Span,
}
/// The state of the executor while running.
pub struct ExecutorState {
/// Metadata for scheduling and running system tasks.
system_task_metadata: Vec<SystemTaskMetadata>,
/// Union of the accesses of all currently running systems.
active_access: Access<ArchetypeComponentId>,
/// Returns `true` if a system with non-`Send` access is running.
local_thread_running: bool,
/// Returns `true` if an exclusive system is running.
exclusive_running: bool,
/// The number of systems that are running.
num_running_systems: usize,
/// The number of dependencies each system has that have not completed.
num_dependencies_remaining: Vec<usize>,
/// System sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
/// Systems that have no remaining dependencies and are waiting to run.
ready_systems: FixedBitSet,
/// copy of `ready_systems`
ready_systems_copy: FixedBitSet,
/// Systems that are running.
running_systems: FixedBitSet,
/// Systems that got skipped.
skipped_systems: FixedBitSet,
/// Systems whose conditions have been evaluated and were run or skipped.
completed_systems: FixedBitSet,
/// Systems that have run but have not had their buffers applied.
unapplied_systems: FixedBitSet,
}
/// References to data required by the executor.
/// This is copied to each system task so that can invoke the executor when they complete.
// These all need to outlive 'scope in order to be sent to new tasks,
// and keeping them all in a struct means we can use lifetime elision.
#[derive(Copy, Clone)]
struct Context<'scope, 'env, 'sys> {
environment: &'env Environment<'env, 'sys>,
scope: &'scope Scope<'scope, 'env, ()>,
error_handler: fn(BevyError, ErrorContext),
}
impl Default for MultiThreadedExecutor {
fn default() -> Self {
Self::new()
}
}
impl SystemExecutor for MultiThreadedExecutor {
fn kind(&self) -> ExecutorKind {
ExecutorKind::MultiThreaded
}
fn init(&mut self, schedule: &SystemSchedule) {
let state = self.state.get_mut().unwrap();
// pre-allocate space
let sys_count = schedule.system_ids.len();
let set_count = schedule.set_ids.len();
self.system_completion = ConcurrentQueue::bounded(sys_count.max(1));
self.starting_systems = FixedBitSet::with_capacity(sys_count);
state.evaluated_sets = FixedBitSet::with_capacity(set_count);
state.ready_systems = FixedBitSet::with_capacity(sys_count);
state.ready_systems_copy = FixedBitSet::with_capacity(sys_count);
state.running_systems = FixedBitSet::with_capacity(sys_count);
state.completed_systems = FixedBitSet::with_capacity(sys_count);
state.skipped_systems = FixedBitSet::with_capacity(sys_count);
state.unapplied_systems = FixedBitSet::with_capacity(sys_count);
state.system_task_metadata = Vec::with_capacity(sys_count);
for index in 0..sys_count {
state.system_task_metadata.push(SystemTaskMetadata {
archetype_component_access: default(),
dependents: schedule.system_dependents[index].clone(),
is_send: schedule.systems[index].is_send(),
is_exclusive: schedule.systems[index].is_exclusive(),
});
if schedule.system_dependencies[index] == 0 {
self.starting_systems.insert(index);
}
}
state.num_dependencies_remaining = Vec::with_capacity(sys_count);
}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
) {
let state = self.state.get_mut().unwrap();
// reset counts
if schedule.systems.is_empty() {
return;
}
state.num_running_systems = 0;
state
.num_dependencies_remaining
.clone_from(&schedule.system_dependencies);
state.ready_systems.clone_from(&self.starting_systems);
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
debug_assert_eq!(skipped_systems.len(), state.completed_systems.len());
// mark skipped systems as completed
state.completed_systems |= skipped_systems;
// signal the dependencies for each of the skipped systems, as
// though they had run
for system_index in skipped_systems.ones() {
state.signal_dependents(system_index);
state.ready_systems.remove(system_index);
}
}
let thread_executor = world
.get_resource::<MainThreadExecutor>()
.map(|e| e.0.clone());
let thread_executor = thread_executor.as_deref();
let environment = &Environment::new(self, schedule, world);
ComputeTaskPool::get_or_init(TaskPool::default).scope_with_executor(
false,
thread_executor,
|scope| {
let context = Context {
environment,
scope,
error_handler,
};
// The first tick won't need to process finished systems, but we still need to run the loop in
// tick_executor() in case a system completes while the first tick still holds the mutex.
context.tick_executor();
},
);
// End the borrows of self and world in environment by copying out the reference to systems.
let systems = environment.systems;
let state = self.state.get_mut().unwrap();
if self.apply_final_deferred {
// Do one final apply buffers after all systems have completed
// Commands should be applied while on the scope's thread, not the executor's thread
let res = apply_deferred(&state.unapplied_systems, systems, world);
if let Err(payload) = res {
let panic_payload = self.panic_payload.get_mut().unwrap();
*panic_payload = Some(payload);
}
state.unapplied_systems.clear();
}
// check to see if there was a panic
let payload = self.panic_payload.get_mut().unwrap();
if let Some(payload) = payload.take() {
std::panic::resume_unwind(payload);
}
debug_assert!(state.ready_systems.is_clear());
debug_assert!(state.running_systems.is_clear());
state.active_access.clear();
state.evaluated_sets.clear();
state.skipped_systems.clear();
state.completed_systems.clear();
}
fn set_apply_final_deferred(&mut self, value: bool) {
self.apply_final_deferred = value;
}
}
impl<'scope, 'env: 'scope, 'sys> Context<'scope, 'env, 'sys> {
fn system_completed(
&self,
system_index: usize,
res: Result<(), Box<dyn Any + Send>>,
system: &ScheduleSystem,
) {
// tell the executor that the system finished
self.environment
.executor
.system_completion
.push(SystemResult { system_index })
.unwrap_or_else(|error| unreachable!("{}", error));
if let Err(payload) = res {
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
eprintln!("Encountered a panic in system `{}`!", &*system.name());
}
// set the payload to propagate the error
{
let mut panic_payload = self.environment.executor.panic_payload.lock().unwrap();
*panic_payload = Some(payload);
}
}
self.tick_executor();
}
fn try_lock<'a>(&'a self) -> Option<(&'a mut Conditions<'sys>, MutexGuard<'a, ExecutorState>)> {
let guard = self.environment.executor.state.try_lock().ok()?;
// SAFETY: This is an exclusive access as no other location fetches conditions mutably, and
// is synchronized by the lock on the executor state.
let conditions = unsafe { &mut *self.environment.conditions.get() };
Some((conditions, guard))
}
fn tick_executor(&self) {
// Ensure that the executor handles any events pushed to the system_completion queue by this thread.
// If this thread acquires the lock, the executor runs after the push() and they are processed.
// If this thread does not acquire the lock, then the is_empty() check on the other thread runs
// after the lock is released, which is after try_lock() failed, which is after the push()
// on this thread, so the is_empty() check will see the new events and loop.
loop {
let Some((conditions, mut guard)) = self.try_lock() else {
return;
};
guard.tick(self, conditions);
// Make sure we drop the guard before checking system_completion.is_empty(), or we could lose events.
drop(guard);
if self.environment.executor.system_completion.is_empty() {
return;
}
}
}
}
impl MultiThreadedExecutor {
/// Creates a new `multi_threaded` executor for use with a [`Schedule`].
///
/// [`Schedule`]: crate::schedule::Schedule
pub fn new() -> Self {
Self {
state: Mutex::new(ExecutorState::new()),
system_completion: ConcurrentQueue::unbounded(),
starting_systems: FixedBitSet::new(),
apply_final_deferred: true,
panic_payload: Mutex::new(None),
#[cfg(feature = "trace")]
executor_span: info_span!("multithreaded executor"),
}
}
}
impl ExecutorState {
fn new() -> Self {
Self {
system_task_metadata: Vec::new(),
num_running_systems: 0,
num_dependencies_remaining: Vec::new(),
active_access: default(),
local_thread_running: false,
exclusive_running: false,
evaluated_sets: FixedBitSet::new(),
ready_systems: FixedBitSet::new(),
ready_systems_copy: FixedBitSet::new(),
running_systems: FixedBitSet::new(),
skipped_systems: FixedBitSet::new(),
completed_systems: FixedBitSet::new(),
unapplied_systems: FixedBitSet::new(),
}
}
fn tick(&mut self, context: &Context, conditions: &mut Conditions) {
#[cfg(feature = "trace")]
let _span = context.environment.executor.executor_span.enter();
for result in context.environment.executor.system_completion.try_iter() {
self.finish_system_and_handle_dependents(result);
}
self.rebuild_active_access();
// SAFETY:
// - `finish_system_and_handle_dependents` has updated the currently running systems.
// - `rebuild_active_access` locks access for all currently running systems.
unsafe {
self.spawn_system_tasks(context, conditions);
}
}
/// # Safety
/// - Caller must ensure that `self.ready_systems` does not contain any systems that
/// have been mutably borrowed (such as the systems currently running).
/// - `world_cell` must have permission to access all world data (not counting
/// any world data that is claimed by systems currently running on this executor).
unsafe fn spawn_system_tasks(&mut self, context: &Context, conditions: &mut Conditions) {
if self.exclusive_running {
return;
}
// can't borrow since loop mutably borrows `self`
let mut ready_systems = core::mem::take(&mut self.ready_systems_copy);
// Skipping systems may cause their dependents to become ready immediately.
// If that happens, we need to run again immediately or we may fail to spawn those dependents.
let mut check_for_new_ready_systems = true;
while check_for_new_ready_systems {
check_for_new_ready_systems = false;
ready_systems.clone_from(&self.ready_systems);
for system_index in ready_systems.ones() {
debug_assert!(!self.running_systems.contains(system_index));
// SAFETY: Caller assured that these systems are not running.
// Therefore, no other reference to this system exists and there is no aliasing.
let system = unsafe { &mut *context.environment.systems[system_index].get() };
if !self.can_run(
system_index,
system,
conditions,
context.environment.world_cell,
) {
// NOTE: exclusive systems with ambiguities are susceptible to
// being significantly displaced here (compared to single-threaded order)
// if systems after them in topological order can run
// if that becomes an issue, `break;` if exclusive system
continue;
}
self.ready_systems.remove(system_index);
// SAFETY: `can_run` returned true, which means that:
// - It must have called `update_archetype_component_access` for each run condition.
// - There can be no systems running whose accesses would conflict with any conditions.
if unsafe {
!self.should_run(
system_index,
system,
conditions,
context.environment.world_cell,
)
} {
self.skip_system_and_signal_dependents(system_index);
// signal_dependents may have set more systems to ready.
check_for_new_ready_systems = true;
continue;
}
self.running_systems.insert(system_index);
self.num_running_systems += 1;
if self.system_task_metadata[system_index].is_exclusive {
// SAFETY: `can_run` returned true for this system,
// which means no systems are currently borrowed.
unsafe {
self.spawn_exclusive_system_task(context, system_index);
}
check_for_new_ready_systems = false;
break;
}
// SAFETY:
// - Caller ensured no other reference to this system exists.
// - `system_task_metadata[system_index].is_exclusive` is `false`,
// so `System::is_exclusive` returned `false` when we called it.
// - `can_run` has been called, which calls `update_archetype_component_access` with this system.
// - `can_run` returned true, so no systems with conflicting world access are running.
unsafe {
self.spawn_system_task(context, system_index);
}
}
}
// give back
self.ready_systems_copy = ready_systems;
}
fn can_run(
&mut self,
system_index: usize,
system: &mut ScheduleSystem,
conditions: &mut Conditions,
world: UnsafeWorldCell,
) -> bool {
let system_meta = &self.system_task_metadata[system_index];
if system_meta.is_exclusive && self.num_running_systems > 0 {
return false;
}
if !system_meta.is_send && self.local_thread_running {
return false;
}
// TODO: an earlier out if world's archetypes did not change
for set_idx in conditions.sets_with_conditions_of_systems[system_index]
.difference(&self.evaluated_sets)
{
for condition in &mut conditions.set_conditions[set_idx] {
condition.update_archetype_component_access(world);
if !condition
.archetype_component_access()
.is_compatible(&self.active_access)
{
return false;
}
}
}
for condition in &mut conditions.system_conditions[system_index] {
condition.update_archetype_component_access(world);
if !condition
.archetype_component_access()
.is_compatible(&self.active_access)
{
return false;
}
}
if !self.skipped_systems.contains(system_index) {
system.update_archetype_component_access(world);
if !system
.archetype_component_access()
.is_compatible(&self.active_access)
{
return false;
}
self.system_task_metadata[system_index]
.archetype_component_access
.clone_from(system.archetype_component_access());
}
true
}
/// # Safety
/// * `world` must have permission to read any world data required by
/// the system's conditions: this includes conditions for the system
/// itself, and conditions for any of the system's sets.
/// * `update_archetype_component` must have been called with `world`
/// for the system as well as system and system set's run conditions.
unsafe fn should_run(
&mut self,
system_index: usize,
system: &mut ScheduleSystem,
conditions: &mut Conditions,
world: UnsafeWorldCell,
) -> bool {
let mut should_run = !self.skipped_systems.contains(system_index);
let error_handler = default_error_handler();
for set_idx in conditions.sets_with_conditions_of_systems[system_index].ones() {
if self.evaluated_sets.contains(set_idx) {
continue;
}
// Evaluate the system set's conditions.
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the conditions.
// - `update_archetype_component_access` has been called for each run condition.
let set_conditions_met = unsafe {
evaluate_and_fold_conditions(&mut conditions.set_conditions[set_idx], world)
};
if !set_conditions_met {
self.skipped_systems
.union_with(&conditions.systems_in_sets_with_conditions[set_idx]);
}
should_run &= set_conditions_met;
self.evaluated_sets.insert(set_idx);
}
// Evaluate the system's conditions.
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the conditions.
// - `update_archetype_component_access` has been called for each run condition.
let system_conditions_met = unsafe {
evaluate_and_fold_conditions(&mut conditions.system_conditions[system_index], world)
};
if !system_conditions_met {
self.skipped_systems.insert(system_index);
}
should_run &= system_conditions_met;
if should_run {
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the system.
// - `update_archetype_component_access` has been called for system.
let valid_params = match unsafe { system.validate_param_unsafe(world) } {
Ok(()) => true,
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
false
}
};
if !valid_params {
self.skipped_systems.insert(system_index);
}
should_run &= valid_params;
}
should_run
}
/// # Safety
/// - Caller must not alias systems that are running.
/// - `is_exclusive` must have returned `false` for the specified system.
/// - `world` must have permission to access the world data
/// used by the specified system.
/// - `update_archetype_component_access` must have been called with `world`
/// on the system associated with `system_index`.
unsafe fn spawn_system_task(&mut self, context: &Context, system_index: usize) {
// SAFETY: this system is not running, no other reference exists
let system = unsafe { &mut *context.environment.systems[system_index].get() };
// Move the full context object into the new future.
let context = *context;
let system_meta = &self.system_task_metadata[system_index];
let task = async move {
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
// SAFETY:
// - The caller ensures that we have permission to
// access the world data used by the system.
// - `is_exclusive` returned false
// - `update_archetype_component_access` has been called.
unsafe {
if let Err(err) = __rust_begin_short_backtrace::run_unsafe(
system,
context.environment.world_cell,
) {
(context.error_handler)(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
};
}));
context.system_completed(system_index, res, system);
};
self.active_access
.extend(&system_meta.archetype_component_access);
if system_meta.is_send {
context.scope.spawn(task);
} else {
self.local_thread_running = true;
context.scope.spawn_on_external(task);
}
}
/// # Safety
/// Caller must ensure no systems are currently borrowed.
unsafe fn spawn_exclusive_system_task(&mut self, context: &Context, system_index: usize) {
// SAFETY: this system is not running, no other reference exists
let system = unsafe { &mut *context.environment.systems[system_index].get() };
// Move the full context object into the new future.
let context = *context;
if is_apply_deferred(system) {
// TODO: avoid allocation
let unapplied_systems = self.unapplied_systems.clone();
self.unapplied_systems.clear();
let task = async move {
// SAFETY: `can_run` returned true for this system, which means
// that no other systems currently have access to the world.
let world = unsafe { context.environment.world_cell.world_mut() };
let res = apply_deferred(&unapplied_systems, context.environment.systems, world);
context.system_completed(system_index, res, system);
};
context.scope.spawn_on_scope(task);
} else {
let task = async move {
// SAFETY: `can_run` returned true for this system, which means
// that no other systems currently have access to the world.
let world = unsafe { context.environment.world_cell.world_mut() };
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
if let Err(err) = __rust_begin_short_backtrace::run(system, world) {
(context.error_handler)(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
}));
context.system_completed(system_index, res, system);
};
context.scope.spawn_on_scope(task);
}
self.exclusive_running = true;
self.local_thread_running = true;
}
fn finish_system_and_handle_dependents(&mut self, result: SystemResult) {
let SystemResult { system_index, .. } = result;
if self.system_task_metadata[system_index].is_exclusive {
self.exclusive_running = false;
}
if !self.system_task_metadata[system_index].is_send {
self.local_thread_running = false;
}
debug_assert!(self.num_running_systems >= 1);
self.num_running_systems -= 1;
self.running_systems.remove(system_index);
self.completed_systems.insert(system_index);
self.unapplied_systems.insert(system_index);
self.signal_dependents(system_index);
}
fn skip_system_and_signal_dependents(&mut self, system_index: usize) {
self.completed_systems.insert(system_index);
self.signal_dependents(system_index);
}
fn signal_dependents(&mut self, system_index: usize) {
for &dep_idx in &self.system_task_metadata[system_index].dependents {
let remaining = &mut self.num_dependencies_remaining[dep_idx];
debug_assert!(*remaining >= 1);
*remaining -= 1;
if *remaining == 0 && !self.completed_systems.contains(dep_idx) {
self.ready_systems.insert(dep_idx);
}
}
}
fn rebuild_active_access(&mut self) {
self.active_access.clear();
for index in self.running_systems.ones() {
let system_meta = &self.system_task_metadata[index];
self.active_access
.extend(&system_meta.archetype_component_access);
}
}
}
fn apply_deferred(
unapplied_systems: &FixedBitSet,
systems: &[SyncUnsafeCell<ScheduleSystem>],
world: &mut World,
) -> Result<(), Box<dyn Any + Send>> {
for system_index in unapplied_systems.ones() {
// SAFETY: none of these systems are running, no other references exist
let system = unsafe { &mut *systems[system_index].get() };
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
system.apply_deferred(world);
}));
if let Err(payload) = res {
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
eprintln!(
"Encountered a panic when applying buffers for system `{}`!",
&*system.name()
);
}
return Err(payload);
}
}
Ok(())
}
/// # Safety
/// - `world` must have permission to read any world data
/// required by `conditions`.
/// - `update_archetype_component_access` must have been called
/// with `world` for each condition in `conditions`.
unsafe fn evaluate_and_fold_conditions(
conditions: &mut [BoxedCondition],
world: UnsafeWorldCell,
) -> bool {
let error_handler = default_error_handler();
#[expect(
clippy::unnecessary_fold,
reason = "Short-circuiting here would prevent conditions from mutating their own state as needed."
)]
conditions
.iter_mut()
.map(|condition| {
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the condition.
// - `update_archetype_component_access` has been called for condition.
match unsafe { condition.validate_param_unsafe(world) } {
Ok(()) => (),
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: condition.name(),
last_run: condition.get_last_run(),
},
);
}
return false;
}
}
// SAFETY:
// - The caller ensures that `world` has permission to read any data
// required by the condition.
// - `update_archetype_component_access` has been called for condition.
unsafe { __rust_begin_short_backtrace::readonly_run_unsafe(&mut **condition, world) }
})
.fold(true, |acc, res| acc && res)
}
/// New-typed [`ThreadExecutor`] [`Resource`] that is used to run systems on the main thread
#[derive(Resource, Clone)]
pub struct MainThreadExecutor(pub Arc<ThreadExecutor<'static>>);
impl Default for MainThreadExecutor {
fn default() -> Self {
Self::new()
}
}
impl MainThreadExecutor {
/// Creates a new executor that can be used to run systems on the main thread.
pub fn new() -> Self {
MainThreadExecutor(TaskPool::get_thread_executor())
}
}
#[cfg(test)]
mod tests {
use crate::{
prelude::Resource,
schedule::{ExecutorKind, IntoScheduleConfigs, Schedule},
system::Commands,
world::World,
};
#[derive(Resource)]
struct R;
#[test]
fn skipped_systems_notify_dependents() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::MultiThreaded);
schedule.add_systems(
(
(|| {}).run_if(|| false),
// This system depends on a system that is always skipped.
|mut commands: Commands| {
commands.insert_resource(R);
},
)
.chain(),
);
schedule.run(&mut world);
assert!(world.get_resource::<R>().is_some());
}
/// Regression test for a weird bug flagged by MIRI in
/// `spawn_exclusive_system_task`, related to a `&mut World` being captured
/// inside an `async` block and somehow remaining alive even after its last use.
#[test]
fn check_spawn_exclusive_system_task_miri() {
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.set_executor_kind(ExecutorKind::MultiThreaded);
schedule.add_systems(((|_: Commands| {}), |_: Commands| {}).chain());
schedule.run(&mut world);
}
}

View File

@@ -0,0 +1,210 @@
use core::panic::AssertUnwindSafe;
use fixedbitset::FixedBitSet;
#[cfg(feature = "trace")]
use tracing::info_span;
#[cfg(feature = "std")]
use std::eprintln;
use crate::{
error::{default_error_handler, BevyError, ErrorContext},
schedule::{
executor::is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule,
},
world::World,
};
use super::__rust_begin_short_backtrace;
/// A variant of [`SingleThreadedExecutor`](crate::schedule::SingleThreadedExecutor) that calls
/// [`apply_deferred`](crate::system::System::apply_deferred) immediately after running each system.
#[derive(Default)]
pub struct SimpleExecutor {
/// Systems sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
/// Systems that have run or been skipped.
completed_systems: FixedBitSet,
}
impl SystemExecutor for SimpleExecutor {
fn kind(&self) -> ExecutorKind {
ExecutorKind::Simple
}
fn init(&mut self, schedule: &SystemSchedule) {
let sys_count = schedule.system_ids.len();
let set_count = schedule.set_ids.len();
self.evaluated_sets = FixedBitSet::with_capacity(set_count);
self.completed_systems = FixedBitSet::with_capacity(sys_count);
}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
) {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
// mark skipped systems as completed
self.completed_systems |= skipped_systems;
}
for system_index in 0..schedule.systems.len() {
#[cfg(feature = "trace")]
let name = schedule.systems[system_index].name();
#[cfg(feature = "trace")]
let should_run_span = info_span!("check_conditions", name = &*name).entered();
let mut should_run = !self.completed_systems.contains(system_index);
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
if self.evaluated_sets.contains(set_idx) {
continue;
}
// evaluate system set's conditions
let set_conditions_met =
evaluate_and_fold_conditions(&mut schedule.set_conditions[set_idx], world);
if !set_conditions_met {
self.completed_systems
.union_with(&schedule.systems_in_sets_with_conditions[set_idx]);
}
should_run &= set_conditions_met;
self.evaluated_sets.insert(set_idx);
}
// evaluate system's conditions
let system_conditions_met =
evaluate_and_fold_conditions(&mut schedule.system_conditions[system_index], world);
should_run &= system_conditions_met;
let system = &mut schedule.systems[system_index];
if should_run {
let valid_params = match system.validate_param(world) {
Ok(()) => true,
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
false
}
};
should_run &= valid_params;
}
#[cfg(feature = "trace")]
should_run_span.exit();
// system has either been skipped or will run
self.completed_systems.insert(system_index);
if !should_run {
continue;
}
if is_apply_deferred(system) {
continue;
}
let f = AssertUnwindSafe(|| {
if let Err(err) = __rust_begin_short_backtrace::run(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
});
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
if let Err(payload) = std::panic::catch_unwind(f) {
eprintln!("Encountered a panic in system `{}`!", &*system.name());
std::panic::resume_unwind(payload);
}
}
#[cfg(not(feature = "std"))]
{
(f)();
}
}
self.evaluated_sets.clear();
self.completed_systems.clear();
}
fn set_apply_final_deferred(&mut self, _: bool) {
// do nothing. simple executor does not do a final sync
}
}
impl SimpleExecutor {
/// Creates a new simple executor for use in a [`Schedule`](crate::schedule::Schedule).
/// This calls each system in order and immediately calls [`System::apply_deferred`](crate::system::System).
pub const fn new() -> Self {
Self {
evaluated_sets: FixedBitSet::new(),
completed_systems: FixedBitSet::new(),
}
}
}
fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
let error_handler = default_error_handler();
#[expect(
clippy::unnecessary_fold,
reason = "Short-circuiting here would prevent conditions from mutating their own state as needed."
)]
conditions
.iter_mut()
.map(|condition| {
match condition.validate_param(world) {
Ok(()) => (),
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: condition.name(),
last_run: condition.get_last_run(),
},
);
}
return false;
}
}
__rust_begin_short_backtrace::readonly_run(&mut **condition, world)
})
.fold(true, |acc, res| acc && res)
}
#[cfg(test)]
#[test]
fn skip_automatic_sync_points() {
// Schedules automatically insert ApplyDeferred systems, but these should
// not be executed as they only serve as markers and are not initialized
use crate::prelude::*;
let mut sched = Schedule::default();
sched.set_executor_kind(ExecutorKind::Simple);
sched.add_systems((|_: Commands| (), || ()).chain());
let mut world = World::new();
sched.run(&mut world);
}

View File

@@ -0,0 +1,241 @@
use core::panic::AssertUnwindSafe;
use fixedbitset::FixedBitSet;
#[cfg(feature = "trace")]
use tracing::info_span;
#[cfg(feature = "std")]
use std::eprintln;
use crate::{
error::{default_error_handler, BevyError, ErrorContext},
schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
world::World,
};
use super::__rust_begin_short_backtrace;
/// Runs the schedule using a single thread.
///
/// Useful if you're dealing with a single-threaded environment, saving your threads for
/// other things, or just trying minimize overhead.
#[derive(Default)]
pub struct SingleThreadedExecutor {
/// System sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
/// Systems that have run or been skipped.
completed_systems: FixedBitSet,
/// Systems that have run but have not had their buffers applied.
unapplied_systems: FixedBitSet,
/// Setting when true applies deferred system buffers after all systems have run
apply_final_deferred: bool,
}
impl SystemExecutor for SingleThreadedExecutor {
fn kind(&self) -> ExecutorKind {
ExecutorKind::SingleThreaded
}
fn init(&mut self, schedule: &SystemSchedule) {
// pre-allocate space
let sys_count = schedule.system_ids.len();
let set_count = schedule.set_ids.len();
self.evaluated_sets = FixedBitSet::with_capacity(set_count);
self.completed_systems = FixedBitSet::with_capacity(sys_count);
self.unapplied_systems = FixedBitSet::with_capacity(sys_count);
}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
error_handler: fn(BevyError, ErrorContext),
) {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
// mark skipped systems as completed
self.completed_systems |= skipped_systems;
}
for system_index in 0..schedule.systems.len() {
#[cfg(feature = "trace")]
let name = schedule.systems[system_index].name();
#[cfg(feature = "trace")]
let should_run_span = info_span!("check_conditions", name = &*name).entered();
let mut should_run = !self.completed_systems.contains(system_index);
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
if self.evaluated_sets.contains(set_idx) {
continue;
}
// evaluate system set's conditions
let set_conditions_met =
evaluate_and_fold_conditions(&mut schedule.set_conditions[set_idx], world);
if !set_conditions_met {
self.completed_systems
.union_with(&schedule.systems_in_sets_with_conditions[set_idx]);
}
should_run &= set_conditions_met;
self.evaluated_sets.insert(set_idx);
}
// evaluate system's conditions
let system_conditions_met =
evaluate_and_fold_conditions(&mut schedule.system_conditions[system_index], world);
should_run &= system_conditions_met;
let system = &mut schedule.systems[system_index];
if should_run {
let valid_params = match system.validate_param(world) {
Ok(()) => true,
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
false
}
};
should_run &= valid_params;
}
#[cfg(feature = "trace")]
should_run_span.exit();
// system has either been skipped or will run
self.completed_systems.insert(system_index);
if !should_run {
continue;
}
if is_apply_deferred(system) {
self.apply_deferred(schedule, world);
continue;
}
let f = AssertUnwindSafe(|| {
if system.is_exclusive() {
if let Err(err) = __rust_begin_short_backtrace::run(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
} else {
// Use run_unsafe to avoid immediately applying deferred buffers
let world = world.as_unsafe_world_cell();
system.update_archetype_component_access(world);
// SAFETY: We have exclusive, single-threaded access to the world and
// update_archetype_component_access is being called immediately before this.
unsafe {
if let Err(err) = __rust_begin_short_backtrace::run_unsafe(system, world) {
error_handler(
err,
ErrorContext::System {
name: system.name(),
last_run: system.get_last_run(),
},
);
}
};
}
});
#[cfg(feature = "std")]
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
{
if let Err(payload) = std::panic::catch_unwind(f) {
eprintln!("Encountered a panic in system `{}`!", &*system.name());
std::panic::resume_unwind(payload);
}
}
#[cfg(not(feature = "std"))]
{
(f)();
}
self.unapplied_systems.insert(system_index);
}
if self.apply_final_deferred {
self.apply_deferred(schedule, world);
}
self.evaluated_sets.clear();
self.completed_systems.clear();
}
fn set_apply_final_deferred(&mut self, apply_final_deferred: bool) {
self.apply_final_deferred = apply_final_deferred;
}
}
impl SingleThreadedExecutor {
/// Creates a new single-threaded executor for use in a [`Schedule`].
///
/// [`Schedule`]: crate::schedule::Schedule
pub const fn new() -> Self {
Self {
evaluated_sets: FixedBitSet::new(),
completed_systems: FixedBitSet::new(),
unapplied_systems: FixedBitSet::new(),
apply_final_deferred: true,
}
}
fn apply_deferred(&mut self, schedule: &mut SystemSchedule, world: &mut World) {
for system_index in self.unapplied_systems.ones() {
let system = &mut schedule.systems[system_index];
system.apply_deferred(world);
}
self.unapplied_systems.clear();
}
}
fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
let error_handler: fn(BevyError, ErrorContext) = default_error_handler();
#[expect(
clippy::unnecessary_fold,
reason = "Short-circuiting here would prevent conditions from mutating their own state as needed."
)]
conditions
.iter_mut()
.map(|condition| {
match condition.validate_param(world) {
Ok(()) => (),
Err(e) => {
if !e.skipped {
error_handler(
e.into(),
ErrorContext::System {
name: condition.name(),
last_run: condition.get_last_run(),
},
);
}
return false;
}
}
__rust_begin_short_backtrace::readonly_run(&mut **condition, world)
})
.fold(true, |acc, res| acc && res)
}

View File

@@ -0,0 +1,474 @@
//! `Graph<DIRECTED>` is a graph datastructure where node values are mapping
//! keys.
//! Based on the `GraphMap` datastructure from [`petgraph`].
//!
//! [`petgraph`]: https://docs.rs/petgraph/0.6.5/petgraph/
use alloc::vec::Vec;
use bevy_platform::{collections::HashSet, hash::FixedHasher};
use core::{
fmt,
hash::{BuildHasher, Hash},
};
use indexmap::IndexMap;
use smallvec::SmallVec;
use super::NodeId;
use Direction::{Incoming, Outgoing};
/// A `Graph` with undirected edges.
///
/// For example, an edge between *1* and *2* is equivalent to an edge between
/// *2* and *1*.
pub type UnGraph<S = FixedHasher> = Graph<false, S>;
/// A `Graph` with directed edges.
///
/// For example, an edge from *1* to *2* is distinct from an edge from *2* to
/// *1*.
pub type DiGraph<S = FixedHasher> = Graph<true, S>;
/// `Graph<DIRECTED>` is a graph datastructure using an associative array
/// of its node weights `NodeId`.
///
/// It uses a combined adjacency list and sparse adjacency matrix
/// representation, using **O(|N| + |E|)** space, and allows testing for edge
/// existence in constant time.
///
/// `Graph` is parameterized over:
///
/// - Constant generic bool `DIRECTED` determines whether the graph edges are directed or
/// undirected.
/// - The `BuildHasher` `S`.
///
/// You can use the type aliases `UnGraph` and `DiGraph` for convenience.
///
/// `Graph` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct Graph<const DIRECTED: bool, S = FixedHasher>
where
S: BuildHasher,
{
nodes: IndexMap<NodeId, Vec<CompactNodeIdAndDirection>, S>,
edges: HashSet<CompactNodeIdPair, S>,
}
impl<const DIRECTED: bool, S: BuildHasher> fmt::Debug for Graph<DIRECTED, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.nodes.fmt(f)
}
}
impl<const DIRECTED: bool, S> Graph<DIRECTED, S>
where
S: BuildHasher,
{
/// Create a new `Graph` with estimated capacity.
pub fn with_capacity(nodes: usize, edges: usize) -> Self
where
S: Default,
{
Self {
nodes: IndexMap::with_capacity_and_hasher(nodes, S::default()),
edges: HashSet::with_capacity_and_hasher(edges, S::default()),
}
}
/// Use their natural order to map the node pair (a, b) to a canonical edge id.
#[inline]
fn edge_key(a: NodeId, b: NodeId) -> CompactNodeIdPair {
let (a, b) = if DIRECTED || a <= b { (a, b) } else { (b, a) };
CompactNodeIdPair::store(a, b)
}
/// Return the number of nodes in the graph.
pub fn node_count(&self) -> usize {
self.nodes.len()
}
/// Add node `n` to the graph.
pub fn add_node(&mut self, n: NodeId) {
self.nodes.entry(n).or_default();
}
/// Remove a node `n` from the graph.
///
/// Computes in **O(N)** time, due to the removal of edges with other nodes.
pub fn remove_node(&mut self, n: NodeId) {
let Some(links) = self.nodes.swap_remove(&n) else {
return;
};
let links = links.into_iter().map(CompactNodeIdAndDirection::load);
for (succ, dir) in links {
let edge = if dir == Outgoing {
Self::edge_key(n, succ)
} else {
Self::edge_key(succ, n)
};
// remove all successor links
self.remove_single_edge(succ, n, dir.opposite());
// Remove all edge values
self.edges.remove(&edge);
}
}
/// Return `true` if the node is contained in the graph.
pub fn contains_node(&self, n: NodeId) -> bool {
self.nodes.contains_key(&n)
}
/// Add an edge connecting `a` and `b` to the graph.
/// For a directed graph, the edge is directed from `a` to `b`.
///
/// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
pub fn add_edge(&mut self, a: NodeId, b: NodeId) {
if self.edges.insert(Self::edge_key(a, b)) {
// insert in the adjacency list if it's a new edge
self.nodes
.entry(a)
.or_insert_with(|| Vec::with_capacity(1))
.push(CompactNodeIdAndDirection::store(b, Outgoing));
if a != b {
// self loops don't have the Incoming entry
self.nodes
.entry(b)
.or_insert_with(|| Vec::with_capacity(1))
.push(CompactNodeIdAndDirection::store(a, Incoming));
}
}
}
/// Remove edge relation from a to b
///
/// Return `true` if it did exist.
fn remove_single_edge(&mut self, a: NodeId, b: NodeId, dir: Direction) -> bool {
let Some(sus) = self.nodes.get_mut(&a) else {
return false;
};
let Some(index) = sus
.iter()
.copied()
.map(CompactNodeIdAndDirection::load)
.position(|elt| (DIRECTED && elt == (b, dir)) || (!DIRECTED && elt.0 == b))
else {
return false;
};
sus.swap_remove(index);
true
}
/// Remove edge from `a` to `b` from the graph.
///
/// Return `false` if the edge didn't exist.
pub fn remove_edge(&mut self, a: NodeId, b: NodeId) -> bool {
let exist1 = self.remove_single_edge(a, b, Outgoing);
let exist2 = if a != b {
self.remove_single_edge(b, a, Incoming)
} else {
exist1
};
let weight = self.edges.remove(&Self::edge_key(a, b));
debug_assert!(exist1 == exist2 && exist1 == weight);
weight
}
/// Return `true` if the edge connecting `a` with `b` is contained in the graph.
pub fn contains_edge(&self, a: NodeId, b: NodeId) -> bool {
self.edges.contains(&Self::edge_key(a, b))
}
/// Return an iterator over the nodes of the graph.
pub fn nodes(
&self,
) -> impl DoubleEndedIterator<Item = NodeId> + ExactSizeIterator<Item = NodeId> + '_ {
self.nodes.keys().copied()
}
/// Return an iterator of all nodes with an edge starting from `a`.
pub fn neighbors(&self, a: NodeId) -> impl DoubleEndedIterator<Item = NodeId> + '_ {
let iter = match self.nodes.get(&a) {
Some(neigh) => neigh.iter(),
None => [].iter(),
};
iter.copied()
.map(CompactNodeIdAndDirection::load)
.filter_map(|(n, dir)| (!DIRECTED || dir == Outgoing).then_some(n))
}
/// Return an iterator of all neighbors that have an edge between them and
/// `a`, in the specified direction.
/// If the graph's edges are undirected, this is equivalent to *.neighbors(a)*.
pub fn neighbors_directed(
&self,
a: NodeId,
dir: Direction,
) -> impl DoubleEndedIterator<Item = NodeId> + '_ {
let iter = match self.nodes.get(&a) {
Some(neigh) => neigh.iter(),
None => [].iter(),
};
iter.copied()
.map(CompactNodeIdAndDirection::load)
.filter_map(move |(n, d)| (!DIRECTED || d == dir || n == a).then_some(n))
}
/// Return an iterator of target nodes with an edge starting from `a`,
/// paired with their respective edge weights.
pub fn edges(&self, a: NodeId) -> impl DoubleEndedIterator<Item = (NodeId, NodeId)> + '_ {
self.neighbors(a)
.map(move |b| match self.edges.get(&Self::edge_key(a, b)) {
None => unreachable!(),
Some(_) => (a, b),
})
}
/// Return an iterator of target nodes with an edge starting from `a`,
/// paired with their respective edge weights.
pub fn edges_directed(
&self,
a: NodeId,
dir: Direction,
) -> impl DoubleEndedIterator<Item = (NodeId, NodeId)> + '_ {
self.neighbors_directed(a, dir).map(move |b| {
let (a, b) = if dir == Incoming { (b, a) } else { (a, b) };
match self.edges.get(&Self::edge_key(a, b)) {
None => unreachable!(),
Some(_) => (a, b),
}
})
}
/// Return an iterator over all edges of the graph with their weight in arbitrary order.
pub fn all_edges(&self) -> impl ExactSizeIterator<Item = (NodeId, NodeId)> + '_ {
self.edges.iter().copied().map(CompactNodeIdPair::load)
}
pub(crate) fn to_index(&self, ix: NodeId) -> usize {
self.nodes.get_index_of(&ix).unwrap()
}
}
/// Create a new empty `Graph`.
impl<const DIRECTED: bool, S> Default for Graph<DIRECTED, S>
where
S: BuildHasher + Default,
{
fn default() -> Self {
Self::with_capacity(0, 0)
}
}
impl<S: BuildHasher> DiGraph<S> {
/// Iterate over all *Strongly Connected Components* in this graph.
pub(crate) fn iter_sccs(&self) -> impl Iterator<Item = SmallVec<[NodeId; 4]>> + '_ {
super::tarjan_scc::new_tarjan_scc(self)
}
}
/// Edge direction.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(u8)]
pub enum Direction {
/// An `Outgoing` edge is an outward edge *from* the current node.
Outgoing = 0,
/// An `Incoming` edge is an inbound edge *to* the current node.
Incoming = 1,
}
impl Direction {
/// Return the opposite `Direction`.
#[inline]
pub fn opposite(self) -> Self {
match self {
Self::Outgoing => Self::Incoming,
Self::Incoming => Self::Outgoing,
}
}
}
/// Compact storage of a [`NodeId`] and a [`Direction`].
#[derive(Clone, Copy)]
struct CompactNodeIdAndDirection {
index: usize,
is_system: bool,
direction: Direction,
}
impl fmt::Debug for CompactNodeIdAndDirection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.load().fmt(f)
}
}
impl CompactNodeIdAndDirection {
const fn store(node: NodeId, direction: Direction) -> Self {
let index = node.index();
let is_system = node.is_system();
Self {
index,
is_system,
direction,
}
}
const fn load(self) -> (NodeId, Direction) {
let Self {
index,
is_system,
direction,
} = self;
let node = match is_system {
true => NodeId::System(index),
false => NodeId::Set(index),
};
(node, direction)
}
}
/// Compact storage of a [`NodeId`] pair.
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
struct CompactNodeIdPair {
index_a: usize,
index_b: usize,
is_system_a: bool,
is_system_b: bool,
}
impl fmt::Debug for CompactNodeIdPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.load().fmt(f)
}
}
impl CompactNodeIdPair {
const fn store(a: NodeId, b: NodeId) -> Self {
let index_a = a.index();
let is_system_a = a.is_system();
let index_b = b.index();
let is_system_b = b.is_system();
Self {
index_a,
index_b,
is_system_a,
is_system_b,
}
}
const fn load(self) -> (NodeId, NodeId) {
let Self {
index_a,
index_b,
is_system_a,
is_system_b,
} = self;
let a = match is_system_a {
true => NodeId::System(index_a),
false => NodeId::Set(index_a),
};
let b = match is_system_b {
true => NodeId::System(index_b),
false => NodeId::Set(index_b),
};
(a, b)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
/// The `Graph` type _must_ preserve the order that nodes are inserted in if
/// no removals occur. Removals are permitted to swap the latest node into the
/// location of the removed node.
#[test]
fn node_order_preservation() {
use NodeId::System;
let mut graph = <DiGraph>::default();
graph.add_node(System(1));
graph.add_node(System(2));
graph.add_node(System(3));
graph.add_node(System(4));
assert_eq!(
graph.nodes().collect::<Vec<_>>(),
vec![System(1), System(2), System(3), System(4)]
);
graph.remove_node(System(1));
assert_eq!(
graph.nodes().collect::<Vec<_>>(),
vec![System(4), System(2), System(3)]
);
graph.remove_node(System(4));
assert_eq!(
graph.nodes().collect::<Vec<_>>(),
vec![System(3), System(2)]
);
graph.remove_node(System(2));
assert_eq!(graph.nodes().collect::<Vec<_>>(), vec![System(3)]);
graph.remove_node(System(3));
assert_eq!(graph.nodes().collect::<Vec<_>>(), vec![]);
}
/// Nodes that have bidirectional edges (or any edge in the case of undirected graphs) are
/// considered strongly connected. A strongly connected component is a collection of
/// nodes where there exists a path from any node to any other node in the collection.
#[test]
fn strongly_connected_components() {
use NodeId::System;
let mut graph = <DiGraph>::default();
graph.add_edge(System(1), System(2));
graph.add_edge(System(2), System(1));
graph.add_edge(System(2), System(3));
graph.add_edge(System(3), System(2));
graph.add_edge(System(4), System(5));
graph.add_edge(System(5), System(4));
graph.add_edge(System(6), System(2));
let sccs = graph
.iter_sccs()
.map(|scc| scc.to_vec())
.collect::<Vec<_>>();
assert_eq!(
sccs,
vec![
vec![System(3), System(2), System(1)],
vec![System(5), System(4)],
vec![System(6)]
]
);
}
}

View File

@@ -0,0 +1,331 @@
use alloc::{boxed::Box, vec, vec::Vec};
use core::{
any::{Any, TypeId},
fmt::Debug,
};
use smallvec::SmallVec;
use bevy_platform::collections::{HashMap, HashSet};
use bevy_utils::TypeIdMap;
use fixedbitset::FixedBitSet;
use crate::schedule::set::*;
mod graph_map;
mod node;
mod tarjan_scc;
pub use graph_map::{DiGraph, Direction, UnGraph};
pub use node::NodeId;
/// Specifies what kind of edge should be added to the dependency graph.
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub(crate) enum DependencyKind {
/// A node that should be preceded.
Before,
/// A node that should be succeeded.
After,
}
/// An edge to be added to the dependency graph.
pub(crate) struct Dependency {
pub(crate) kind: DependencyKind,
pub(crate) set: InternedSystemSet,
pub(crate) options: TypeIdMap<Box<dyn Any>>,
}
impl Dependency {
pub fn new(kind: DependencyKind, set: InternedSystemSet) -> Self {
Self {
kind,
set,
options: Default::default(),
}
}
pub fn add_config<T: 'static>(mut self, option: T) -> Self {
self.options.insert(TypeId::of::<T>(), Box::new(option));
self
}
}
/// Configures ambiguity detection for a single system.
#[derive(Clone, Debug, Default)]
pub(crate) enum Ambiguity {
#[default]
Check,
/// Ignore warnings with systems in any of these system sets. May contain duplicates.
IgnoreWithSet(Vec<InternedSystemSet>),
/// Ignore all warnings.
IgnoreAll,
}
/// Metadata about how the node fits in the schedule graph
#[derive(Default)]
pub struct GraphInfo {
/// the sets that the node belongs to (hierarchy)
pub(crate) hierarchy: Vec<InternedSystemSet>,
/// the sets that the node depends on (must run before or after)
pub(crate) dependencies: Vec<Dependency>,
pub(crate) ambiguous_with: Ambiguity,
}
/// Converts 2D row-major pair of indices into a 1D array index.
pub(crate) fn index(row: usize, col: usize, num_cols: usize) -> usize {
debug_assert!(col < num_cols);
(row * num_cols) + col
}
/// Converts a 1D array index into a 2D row-major pair of indices.
pub(crate) fn row_col(index: usize, num_cols: usize) -> (usize, usize) {
(index / num_cols, index % num_cols)
}
/// Stores the results of the graph analysis.
pub(crate) struct CheckGraphResults {
/// Boolean reachability matrix for the graph.
pub(crate) reachable: FixedBitSet,
/// Pairs of nodes that have a path connecting them.
pub(crate) connected: HashSet<(NodeId, NodeId)>,
/// Pairs of nodes that don't have a path connecting them.
pub(crate) disconnected: Vec<(NodeId, NodeId)>,
/// Edges that are redundant because a longer path exists.
pub(crate) transitive_edges: Vec<(NodeId, NodeId)>,
/// Variant of the graph with no transitive edges.
pub(crate) transitive_reduction: DiGraph,
/// Variant of the graph with all possible transitive edges.
// TODO: this will very likely be used by "if-needed" ordering
#[expect(dead_code, reason = "See the TODO above this attribute.")]
pub(crate) transitive_closure: DiGraph,
}
impl Default for CheckGraphResults {
fn default() -> Self {
Self {
reachable: FixedBitSet::new(),
connected: HashSet::default(),
disconnected: Vec::new(),
transitive_edges: Vec::new(),
transitive_reduction: DiGraph::default(),
transitive_closure: DiGraph::default(),
}
}
}
/// Processes a DAG and computes its:
/// - transitive reduction (along with the set of removed edges)
/// - transitive closure
/// - reachability matrix (as a bitset)
/// - pairs of nodes connected by a path
/// - pairs of nodes not connected by a path
///
/// The algorithm implemented comes from
/// ["On the calculation of transitive reduction-closure of orders"][1] by Habib, Morvan and Rampon.
///
/// [1]: https://doi.org/10.1016/0012-365X(93)90164-O
pub(crate) fn check_graph(graph: &DiGraph, topological_order: &[NodeId]) -> CheckGraphResults {
if graph.node_count() == 0 {
return CheckGraphResults::default();
}
let n = graph.node_count();
// build a copy of the graph where the nodes and edges appear in topsorted order
let mut map = <HashMap<_, _>>::with_capacity_and_hasher(n, Default::default());
let mut topsorted = <DiGraph>::default();
// iterate nodes in topological order
for (i, &node) in topological_order.iter().enumerate() {
map.insert(node, i);
topsorted.add_node(node);
// insert nodes as successors to their predecessors
for pred in graph.neighbors_directed(node, Direction::Incoming) {
topsorted.add_edge(pred, node);
}
}
let mut reachable = FixedBitSet::with_capacity(n * n);
let mut connected = <HashSet<_>>::default();
let mut disconnected = Vec::new();
let mut transitive_edges = Vec::new();
let mut transitive_reduction = DiGraph::default();
let mut transitive_closure = DiGraph::default();
let mut visited = FixedBitSet::with_capacity(n);
// iterate nodes in topological order
for node in topsorted.nodes() {
transitive_reduction.add_node(node);
transitive_closure.add_node(node);
}
// iterate nodes in reverse topological order
for a in topsorted.nodes().rev() {
let index_a = *map.get(&a).unwrap();
// iterate their successors in topological order
for b in topsorted.neighbors_directed(a, Direction::Outgoing) {
let index_b = *map.get(&b).unwrap();
debug_assert!(index_a < index_b);
if !visited[index_b] {
// edge <a, b> is not redundant
transitive_reduction.add_edge(a, b);
transitive_closure.add_edge(a, b);
reachable.insert(index(index_a, index_b, n));
let successors = transitive_closure
.neighbors_directed(b, Direction::Outgoing)
.collect::<Vec<_>>();
for c in successors {
let index_c = *map.get(&c).unwrap();
debug_assert!(index_b < index_c);
if !visited[index_c] {
visited.insert(index_c);
transitive_closure.add_edge(a, c);
reachable.insert(index(index_a, index_c, n));
}
}
} else {
// edge <a, b> is redundant
transitive_edges.push((a, b));
}
}
visited.clear();
}
// partition pairs of nodes into "connected by path" and "not connected by path"
for i in 0..(n - 1) {
// reachable is upper triangular because the nodes were topsorted
for index in index(i, i + 1, n)..=index(i, n - 1, n) {
let (a, b) = row_col(index, n);
let pair = (topological_order[a], topological_order[b]);
if reachable[index] {
connected.insert(pair);
} else {
disconnected.push(pair);
}
}
}
// fill diagonal (nodes reach themselves)
// for i in 0..n {
// reachable.set(index(i, i, n), true);
// }
CheckGraphResults {
reachable,
connected,
disconnected,
transitive_edges,
transitive_reduction,
transitive_closure,
}
}
/// Returns the simple cycles in a strongly-connected component of a directed graph.
///
/// The algorithm implemented comes from
/// ["Finding all the elementary circuits of a directed graph"][1] by D. B. Johnson.
///
/// [1]: https://doi.org/10.1137/0204007
pub fn simple_cycles_in_component(graph: &DiGraph, scc: &[NodeId]) -> Vec<Vec<NodeId>> {
let mut cycles = vec![];
let mut sccs = vec![SmallVec::from_slice(scc)];
while let Some(mut scc) = sccs.pop() {
// only look at nodes and edges in this strongly-connected component
let mut subgraph = <DiGraph>::default();
for &node in &scc {
subgraph.add_node(node);
}
for &node in &scc {
for successor in graph.neighbors(node) {
if subgraph.contains_node(successor) {
subgraph.add_edge(node, successor);
}
}
}
// path of nodes that may form a cycle
let mut path = Vec::with_capacity(subgraph.node_count());
// we mark nodes as "blocked" to avoid finding permutations of the same cycles
let mut blocked: HashSet<_> =
HashSet::with_capacity_and_hasher(subgraph.node_count(), Default::default());
// connects nodes along path segments that can't be part of a cycle (given current root)
// those nodes can be unblocked at the same time
let mut unblock_together: HashMap<NodeId, HashSet<NodeId>> =
HashMap::with_capacity_and_hasher(subgraph.node_count(), Default::default());
// stack for unblocking nodes
let mut unblock_stack = Vec::with_capacity(subgraph.node_count());
// nodes can be involved in multiple cycles
let mut maybe_in_more_cycles: HashSet<NodeId> =
HashSet::with_capacity_and_hasher(subgraph.node_count(), Default::default());
// stack for DFS
let mut stack = Vec::with_capacity(subgraph.node_count());
// we're going to look for all cycles that begin and end at this node
let root = scc.pop().unwrap();
// start a path at the root
path.clear();
path.push(root);
// mark this node as blocked
blocked.insert(root);
// DFS
stack.clear();
stack.push((root, subgraph.neighbors(root)));
while !stack.is_empty() {
let &mut (ref node, ref mut successors) = stack.last_mut().unwrap();
if let Some(next) = successors.next() {
if next == root {
// found a cycle
maybe_in_more_cycles.extend(path.iter());
cycles.push(path.clone());
} else if !blocked.contains(&next) {
// first time seeing `next` on this path
maybe_in_more_cycles.remove(&next);
path.push(next);
blocked.insert(next);
stack.push((next, subgraph.neighbors(next)));
continue;
} else {
// not first time seeing `next` on this path
}
}
if successors.peekable().peek().is_none() {
if maybe_in_more_cycles.contains(node) {
unblock_stack.push(*node);
// unblock this node's ancestors
while let Some(n) = unblock_stack.pop() {
if blocked.remove(&n) {
let unblock_predecessors = unblock_together.entry(n).or_default();
unblock_stack.extend(unblock_predecessors.iter());
unblock_predecessors.clear();
}
}
} else {
// if its descendants can be unblocked later, this node will be too
for successor in subgraph.neighbors(*node) {
unblock_together.entry(successor).or_default().insert(*node);
}
}
// remove node from path and DFS stack
path.pop();
stack.pop();
}
}
drop(stack);
// remove node from subgraph
subgraph.remove_node(root);
// divide remainder into smaller SCCs
sccs.extend(subgraph.iter_sccs().filter(|scc| scc.len() > 1));
}
cycles
}

View File

@@ -0,0 +1,47 @@
use core::fmt::Debug;
/// Unique identifier for a system or system set stored in a [`ScheduleGraph`].
///
/// [`ScheduleGraph`]: crate::schedule::ScheduleGraph
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NodeId {
/// Identifier for a system.
System(usize),
/// Identifier for a system set.
Set(usize),
}
impl NodeId {
/// Returns the internal integer value.
pub const fn index(&self) -> usize {
match self {
NodeId::System(index) | NodeId::Set(index) => *index,
}
}
/// Returns `true` if the identified node is a system.
pub const fn is_system(&self) -> bool {
matches!(self, NodeId::System(_))
}
/// Returns `true` if the identified node is a system set.
pub const fn is_set(&self) -> bool {
matches!(self, NodeId::Set(_))
}
/// Compare this [`NodeId`] with another.
pub const fn cmp(&self, other: &Self) -> core::cmp::Ordering {
use core::cmp::Ordering::{Equal, Greater, Less};
use NodeId::{Set, System};
match (self, other) {
(System(a), System(b)) | (Set(a), Set(b)) => match a.checked_sub(*b) {
None => Less,
Some(0) => Equal,
Some(_) => Greater,
},
(System(_), Set(_)) => Less,
(Set(_), System(_)) => Greater,
}
}
}

View File

@@ -0,0 +1,223 @@
use super::DiGraph;
use super::NodeId;
use alloc::vec::Vec;
use core::hash::BuildHasher;
use core::num::NonZeroUsize;
use smallvec::SmallVec;
/// Create an iterator over *strongly connected components* using Algorithm 3 in
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
/// which is a memory-efficient variation of [Tarjan's algorithm][2].
///
///
/// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
/// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
///
/// Returns each strongly strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
pub(crate) fn new_tarjan_scc<S: BuildHasher>(
graph: &DiGraph<S>,
) -> impl Iterator<Item = SmallVec<[NodeId; 4]>> + '_ {
// Create a list of all nodes we need to visit.
let unchecked_nodes = graph.nodes();
// For each node we need to visit, we also need to visit its neighbors.
// Storing the iterator for each set of neighbors allows this list to be computed without
// an additional allocation.
let nodes = graph
.nodes()
.map(|node| NodeData {
root_index: None,
neighbors: graph.neighbors(node),
})
.collect::<Vec<_>>();
TarjanScc {
graph,
unchecked_nodes,
index: 1, // Invariant: index < component_count at all times.
component_count: usize::MAX, // Will hold if component_count is initialized to number of nodes - 1 or higher.
nodes,
stack: Vec::new(),
visitation_stack: Vec::new(),
start: None,
index_adjustment: None,
}
}
struct NodeData<N: Iterator<Item = NodeId>> {
root_index: Option<NonZeroUsize>,
neighbors: N,
}
/// A state for computing the *strongly connected components* using [Tarjan's algorithm][1].
///
/// This is based on [`TarjanScc`] from [`petgraph`].
///
/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
/// [`petgraph`]: https://docs.rs/petgraph/0.6.5/petgraph/
/// [`TarjanScc`]: https://docs.rs/petgraph/0.6.5/petgraph/algo/struct.TarjanScc.html
struct TarjanScc<'graph, Hasher, AllNodes, Neighbors>
where
Hasher: BuildHasher,
AllNodes: Iterator<Item = NodeId>,
Neighbors: Iterator<Item = NodeId>,
{
/// Source of truth [`DiGraph`]
graph: &'graph DiGraph<Hasher>,
/// An [`Iterator`] of [`NodeId`]s from the `graph` which may not have been visited yet.
unchecked_nodes: AllNodes,
/// The index of the next SCC
index: usize,
/// A count of potentially remaining SCCs
component_count: usize,
/// Information about each [`NodeId`], including a possible SCC index and an
/// [`Iterator`] of possibly unvisited neighbors.
nodes: Vec<NodeData<Neighbors>>,
/// A stack of [`NodeId`]s where a SCC will be found starting at the top of the stack.
stack: Vec<NodeId>,
/// A stack of [`NodeId`]s which need to be visited to determine which SCC they belong to.
visitation_stack: Vec<(NodeId, bool)>,
/// An index into the `stack` indicating the starting point of a SCC.
start: Option<usize>,
/// An adjustment to the `index` which will be applied once the current SCC is found.
index_adjustment: Option<usize>,
}
impl<'graph, S: BuildHasher, A: Iterator<Item = NodeId>, N: Iterator<Item = NodeId>>
TarjanScc<'graph, S, A, N>
{
/// Compute the next *strongly connected component* using Algorithm 3 in
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
/// which is a memory-efficient variation of [Tarjan's algorithm][2].
///
///
/// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
/// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
///
/// Returns `Some` for each strongly strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
fn next_scc(&mut self) -> Option<&[NodeId]> {
// Cleanup from possible previous iteration
if let (Some(start), Some(index_adjustment)) =
(self.start.take(), self.index_adjustment.take())
{
self.stack.truncate(start);
self.index -= index_adjustment; // Backtrack index back to where it was before we ever encountered the component.
self.component_count -= 1;
}
loop {
// If there are items on the visitation stack, then we haven't finished visiting
// the node at the bottom of the stack yet.
// Must visit all nodes in the stack from top to bottom before visiting the next node.
while let Some((v, v_is_local_root)) = self.visitation_stack.pop() {
// If this visitation finds a complete SCC, return it immediately.
if let Some(start) = self.visit_once(v, v_is_local_root) {
return Some(&self.stack[start..]);
};
}
// Get the next node to check, otherwise we're done and can return None.
let Some(node) = self.unchecked_nodes.next() else {
break None;
};
let visited = self.nodes[self.graph.to_index(node)].root_index.is_some();
// If this node hasn't already been visited (e.g., it was the neighbor of a previously checked node)
// add it to the visitation stack.
if !visited {
self.visitation_stack.push((node, true));
}
}
}
/// Attempt to find the starting point on the stack for a new SCC without visiting neighbors.
/// If a visitation is required, this will return `None` and mark the required neighbor and the
/// current node as in need of visitation again.
/// If no SCC can be found in the current visitation stack, returns `None`.
fn visit_once(&mut self, v: NodeId, mut v_is_local_root: bool) -> Option<usize> {
let node_v = &mut self.nodes[self.graph.to_index(v)];
if node_v.root_index.is_none() {
let v_index = self.index;
node_v.root_index = NonZeroUsize::new(v_index);
self.index += 1;
}
while let Some(w) = self.nodes[self.graph.to_index(v)].neighbors.next() {
// If a neighbor hasn't been visited yet...
if self.nodes[self.graph.to_index(w)].root_index.is_none() {
// Push the current node and the neighbor back onto the visitation stack.
// On the next execution of `visit_once`, the neighbor will be visited.
self.visitation_stack.push((v, v_is_local_root));
self.visitation_stack.push((w, true));
return None;
}
if self.nodes[self.graph.to_index(w)].root_index
< self.nodes[self.graph.to_index(v)].root_index
{
self.nodes[self.graph.to_index(v)].root_index =
self.nodes[self.graph.to_index(w)].root_index;
v_is_local_root = false;
}
}
if !v_is_local_root {
self.stack.push(v); // Stack is filled up when backtracking, unlike in Tarjans original algorithm.
return None;
}
// Pop the stack and generate an SCC.
let mut index_adjustment = 1;
let c = NonZeroUsize::new(self.component_count);
let nodes = &mut self.nodes;
let start = self
.stack
.iter()
.rposition(|&w| {
if nodes[self.graph.to_index(v)].root_index
> nodes[self.graph.to_index(w)].root_index
{
true
} else {
nodes[self.graph.to_index(w)].root_index = c;
index_adjustment += 1;
false
}
})
.map(|x| x + 1)
.unwrap_or_default();
nodes[self.graph.to_index(v)].root_index = c;
self.stack.push(v); // Pushing the component root to the back right before getting rid of it is somewhat ugly, but it lets it be included in f.
self.start = Some(start);
self.index_adjustment = Some(index_adjustment);
Some(start)
}
}
impl<'graph, S: BuildHasher, A: Iterator<Item = NodeId>, N: Iterator<Item = NodeId>> Iterator
for TarjanScc<'graph, S, A, N>
{
// It is expected that the `DiGraph` is sparse, and as such wont have many large SCCs.
// Returning a `SmallVec` allows this iterator to skip allocation in cases where that
// assumption holds.
type Item = SmallVec<[NodeId; 4]>;
fn next(&mut self) -> Option<Self::Item> {
let next = SmallVec::from_slice(self.next_scc()?);
Some(next)
}
fn size_hint(&self) -> (usize, Option<usize>) {
// There can be no more than the number of nodes in a graph worth of SCCs
(0, Some(self.nodes.len()))
}
}

1256
vendor/bevy_ecs/src/schedule/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

79
vendor/bevy_ecs/src/schedule/pass.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
use alloc::{boxed::Box, vec::Vec};
use core::any::{Any, TypeId};
use super::{DiGraph, NodeId, ScheduleBuildError, ScheduleGraph};
use crate::world::World;
use bevy_utils::TypeIdMap;
use core::fmt::Debug;
/// A pass for modular modification of the dependency graph.
pub trait ScheduleBuildPass: Send + Sync + Debug + 'static {
/// Custom options for dependencies between sets or systems.
type EdgeOptions: 'static;
/// Called when a dependency between sets or systems was explicitly added to the graph.
fn add_dependency(&mut self, from: NodeId, to: NodeId, options: Option<&Self::EdgeOptions>);
/// Called while flattening the dependency graph. For each `set`, this method is called
/// with the `systems` associated with the set as well as an immutable reference to the current graph.
/// Instead of modifying the graph directly, this method should return an iterator of edges to add to the graph.
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
) -> impl Iterator<Item = (NodeId, NodeId)>;
/// The implementation will be able to modify the `ScheduleGraph` here.
fn build(
&mut self,
world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError>;
}
/// Object safe version of [`ScheduleBuildPass`].
pub(super) trait ScheduleBuildPassObj: Send + Sync + Debug {
fn build(
&mut self,
world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError>;
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
dependencies_to_add: &mut Vec<(NodeId, NodeId)>,
);
fn add_dependency(&mut self, from: NodeId, to: NodeId, all_options: &TypeIdMap<Box<dyn Any>>);
}
impl<T: ScheduleBuildPass> ScheduleBuildPassObj for T {
fn build(
&mut self,
world: &mut World,
graph: &mut ScheduleGraph,
dependency_flattened: &mut DiGraph,
) -> Result<(), ScheduleBuildError> {
self.build(world, graph, dependency_flattened)
}
fn collapse_set(
&mut self,
set: NodeId,
systems: &[NodeId],
dependency_flattened: &DiGraph,
dependencies_to_add: &mut Vec<(NodeId, NodeId)>,
) {
let iter = self.collapse_set(set, systems, dependency_flattened);
dependencies_to_add.extend(iter);
}
fn add_dependency(&mut self, from: NodeId, to: NodeId, all_options: &TypeIdMap<Box<dyn Any>>) {
let option = all_options
.get(&TypeId::of::<T::EdgeOptions>())
.and_then(|x| x.downcast_ref::<T::EdgeOptions>());
self.add_dependency(from, to, option);
}
}

2864
vendor/bevy_ecs/src/schedule/schedule.rs vendored Normal file

File diff suppressed because it is too large Load Diff

448
vendor/bevy_ecs/src/schedule/set.rs vendored Normal file
View File

@@ -0,0 +1,448 @@
use alloc::boxed::Box;
use core::{
any::TypeId,
fmt::Debug,
hash::{Hash, Hasher},
marker::PhantomData,
};
pub use crate::label::DynEq;
pub use bevy_ecs_macros::{ScheduleLabel, SystemSet};
use crate::{
define_label,
intern::Interned,
system::{
ExclusiveFunctionSystem, ExclusiveSystemParamFunction, FunctionSystem,
IsExclusiveFunctionSystem, IsFunctionSystem, SystemParamFunction,
},
};
define_label!(
/// A strongly-typed class of labels used to identify a [`Schedule`](crate::schedule::Schedule).
#[diagnostic::on_unimplemented(
note = "consider annotating `{Self}` with `#[derive(ScheduleLabel)]`"
)]
ScheduleLabel,
SCHEDULE_LABEL_INTERNER
);
define_label!(
/// Types that identify logical groups of systems.
#[diagnostic::on_unimplemented(
note = "consider annotating `{Self}` with `#[derive(SystemSet)]`"
)]
SystemSet,
SYSTEM_SET_INTERNER,
extra_methods: {
/// Returns `Some` if this system set is a [`SystemTypeSet`].
fn system_type(&self) -> Option<TypeId> {
None
}
/// Returns `true` if this system set is an [`AnonymousSet`].
fn is_anonymous(&self) -> bool {
false
}
},
extra_methods_impl: {
fn system_type(&self) -> Option<TypeId> {
(**self).system_type()
}
fn is_anonymous(&self) -> bool {
(**self).is_anonymous()
}
}
);
/// A shorthand for `Interned<dyn SystemSet>`.
pub type InternedSystemSet = Interned<dyn SystemSet>;
/// A shorthand for `Interned<dyn ScheduleLabel>`.
pub type InternedScheduleLabel = Interned<dyn ScheduleLabel>;
/// A [`SystemSet`] grouping instances of the same function.
///
/// This kind of set is automatically populated and thus has some special rules:
/// - You cannot manually add members.
/// - You cannot configure them.
/// - You cannot order something relative to one if it has more than one member.
pub struct SystemTypeSet<T: 'static>(PhantomData<fn() -> T>);
impl<T: 'static> SystemTypeSet<T> {
pub(crate) fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Debug for SystemTypeSet<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("SystemTypeSet")
.field(&format_args!("fn {}()", &core::any::type_name::<T>()))
.finish()
}
}
impl<T> Hash for SystemTypeSet<T> {
fn hash<H: Hasher>(&self, _state: &mut H) {
// all systems of a given type are the same
}
}
impl<T> Clone for SystemTypeSet<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SystemTypeSet<T> {}
impl<T> PartialEq for SystemTypeSet<T> {
#[inline]
fn eq(&self, _other: &Self) -> bool {
// all systems of a given type are the same
true
}
}
impl<T> Eq for SystemTypeSet<T> {}
impl<T> SystemSet for SystemTypeSet<T> {
fn system_type(&self) -> Option<TypeId> {
Some(TypeId::of::<T>())
}
fn dyn_clone(&self) -> Box<dyn SystemSet> {
Box::new(*self)
}
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
TypeId::of::<Self>().hash(&mut state);
self.hash(&mut state);
}
}
/// A [`SystemSet`] implicitly created when using
/// [`Schedule::add_systems`](super::Schedule::add_systems) or
/// [`Schedule::configure_sets`](super::Schedule::configure_sets).
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct AnonymousSet(usize);
impl AnonymousSet {
pub(crate) fn new(id: usize) -> Self {
Self(id)
}
}
impl SystemSet for AnonymousSet {
fn is_anonymous(&self) -> bool {
true
}
fn dyn_clone(&self) -> Box<dyn SystemSet> {
Box::new(*self)
}
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
TypeId::of::<Self>().hash(&mut state);
self.hash(&mut state);
}
}
/// Types that can be converted into a [`SystemSet`].
///
/// # Usage notes
///
/// This trait should only be used as a bound for trait implementations or as an
/// argument to a function. If a system set needs to be returned from a function
/// or stored somewhere, use [`SystemSet`] instead of this trait.
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a system set",
label = "invalid system set"
)]
pub trait IntoSystemSet<Marker>: Sized {
/// The type of [`SystemSet`] this instance converts into.
type Set: SystemSet;
/// Converts this instance to its associated [`SystemSet`] type.
fn into_system_set(self) -> Self::Set;
}
// systems sets
impl<S: SystemSet> IntoSystemSet<()> for S {
type Set = Self;
#[inline]
fn into_system_set(self) -> Self::Set {
self
}
}
// systems
impl<Marker, F> IntoSystemSet<(IsFunctionSystem, Marker)> for F
where
Marker: 'static,
F: SystemParamFunction<Marker>,
{
type Set = SystemTypeSet<FunctionSystem<Marker, F>>;
#[inline]
fn into_system_set(self) -> Self::Set {
SystemTypeSet::<FunctionSystem<Marker, F>>::new()
}
}
// exclusive systems
impl<Marker, F> IntoSystemSet<(IsExclusiveFunctionSystem, Marker)> for F
where
Marker: 'static,
F: ExclusiveSystemParamFunction<Marker>,
{
type Set = SystemTypeSet<ExclusiveFunctionSystem<Marker, F>>;
#[inline]
fn into_system_set(self) -> Self::Set {
SystemTypeSet::<ExclusiveFunctionSystem<Marker, F>>::new()
}
}
#[cfg(test)]
mod tests {
use crate::{
resource::Resource,
schedule::{tests::ResMut, Schedule},
};
use super::*;
#[test]
fn test_schedule_label() {
use crate::world::World;
#[derive(Resource)]
struct Flag(bool);
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct A;
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct B;
let mut world = World::new();
let mut schedule = Schedule::new(A);
schedule.add_systems(|mut flag: ResMut<Flag>| flag.0 = true);
world.add_schedule(schedule);
let interned = A.intern();
world.insert_resource(Flag(false));
world.run_schedule(interned);
assert!(world.resource::<Flag>().0);
world.insert_resource(Flag(false));
world.run_schedule(interned);
assert!(world.resource::<Flag>().0);
assert_ne!(A.intern(), B.intern());
}
#[test]
fn test_derive_schedule_label() {
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct UnitLabel;
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct TupleLabel(u32, u32);
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct StructLabel {
a: u32,
b: u32,
}
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyTupleLabel();
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyStructLabel {}
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
enum EnumLabel {
#[default]
Unit,
Tuple(u32, u32),
Struct {
a: u32,
b: u32,
},
}
#[derive(ScheduleLabel, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct GenericLabel<T>(PhantomData<T>);
assert_eq!(UnitLabel.intern(), UnitLabel.intern());
assert_eq!(EnumLabel::Unit.intern(), EnumLabel::Unit.intern());
assert_ne!(UnitLabel.intern(), EnumLabel::Unit.intern());
assert_ne!(UnitLabel.intern(), TupleLabel(0, 0).intern());
assert_ne!(EnumLabel::Unit.intern(), EnumLabel::Tuple(0, 0).intern());
assert_eq!(TupleLabel(0, 0).intern(), TupleLabel(0, 0).intern());
assert_eq!(
EnumLabel::Tuple(0, 0).intern(),
EnumLabel::Tuple(0, 0).intern()
);
assert_ne!(TupleLabel(0, 0).intern(), TupleLabel(0, 1).intern());
assert_ne!(
EnumLabel::Tuple(0, 0).intern(),
EnumLabel::Tuple(0, 1).intern()
);
assert_ne!(TupleLabel(0, 0).intern(), EnumLabel::Tuple(0, 0).intern());
assert_ne!(
TupleLabel(0, 0).intern(),
StructLabel { a: 0, b: 0 }.intern()
);
assert_ne!(
EnumLabel::Tuple(0, 0).intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_eq!(
StructLabel { a: 0, b: 0 }.intern(),
StructLabel { a: 0, b: 0 }.intern()
);
assert_eq!(
EnumLabel::Struct { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructLabel { a: 0, b: 0 }.intern(),
StructLabel { a: 0, b: 1 }.intern()
);
assert_ne!(
EnumLabel::Struct { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 1 }.intern()
);
assert_ne!(
StructLabel { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructLabel { a: 0, b: 0 }.intern(),
EnumLabel::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(StructLabel { a: 0, b: 0 }.intern(), UnitLabel.intern(),);
assert_ne!(
EnumLabel::Struct { a: 0, b: 0 }.intern(),
EnumLabel::Unit.intern()
);
assert_eq!(
GenericLabel::<u32>(PhantomData).intern(),
GenericLabel::<u32>(PhantomData).intern()
);
assert_ne!(
GenericLabel::<u32>(PhantomData).intern(),
GenericLabel::<u64>(PhantomData).intern()
);
}
#[test]
fn test_derive_system_set() {
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct UnitSet;
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct TupleSet(u32, u32);
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct StructSet {
a: u32,
b: u32,
}
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyTupleSet();
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct EmptyStructSet {}
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
enum EnumSet {
#[default]
Unit,
Tuple(u32, u32),
Struct {
a: u32,
b: u32,
},
}
#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
struct GenericSet<T>(PhantomData<T>);
assert_eq!(UnitSet.intern(), UnitSet.intern());
assert_eq!(EnumSet::Unit.intern(), EnumSet::Unit.intern());
assert_ne!(UnitSet.intern(), EnumSet::Unit.intern());
assert_ne!(UnitSet.intern(), TupleSet(0, 0).intern());
assert_ne!(EnumSet::Unit.intern(), EnumSet::Tuple(0, 0).intern());
assert_eq!(TupleSet(0, 0).intern(), TupleSet(0, 0).intern());
assert_eq!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
assert_ne!(TupleSet(0, 0).intern(), TupleSet(0, 1).intern());
assert_ne!(EnumSet::Tuple(0, 0).intern(), EnumSet::Tuple(0, 1).intern());
assert_ne!(TupleSet(0, 0).intern(), EnumSet::Tuple(0, 0).intern());
assert_ne!(TupleSet(0, 0).intern(), StructSet { a: 0, b: 0 }.intern());
assert_ne!(
EnumSet::Tuple(0, 0).intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_eq!(
StructSet { a: 0, b: 0 }.intern(),
StructSet { a: 0, b: 0 }.intern()
);
assert_eq!(
EnumSet::Struct { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructSet { a: 0, b: 0 }.intern(),
StructSet { a: 0, b: 1 }.intern()
);
assert_ne!(
EnumSet::Struct { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 1 }.intern()
);
assert_ne!(
StructSet { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(
StructSet { a: 0, b: 0 }.intern(),
EnumSet::Struct { a: 0, b: 0 }.intern()
);
assert_ne!(StructSet { a: 0, b: 0 }.intern(), UnitSet.intern(),);
assert_ne!(
EnumSet::Struct { a: 0, b: 0 }.intern(),
EnumSet::Unit.intern()
);
assert_eq!(
GenericSet::<u32>(PhantomData).intern(),
GenericSet::<u32>(PhantomData).intern()
);
assert_ne!(
GenericSet::<u32>(PhantomData).intern(),
GenericSet::<u64>(PhantomData).intern()
);
}
}

1560
vendor/bevy_ecs/src/schedule/stepping.rs vendored Normal file

File diff suppressed because it is too large Load Diff

361
vendor/bevy_ecs/src/spawn.rs vendored Normal file
View File

@@ -0,0 +1,361 @@
//! Entity spawning abstractions, largely focused on spawning related hierarchies of entities. See [`related`](crate::related) and [`SpawnRelated`]
//! for the best entry points into these APIs and examples of how to use them.
use crate::{
bundle::{Bundle, BundleEffect, DynamicBundle, NoBundleEffect},
entity::Entity,
relationship::{RelatedSpawner, Relationship, RelationshipTarget},
world::{EntityWorldMut, World},
};
use alloc::vec::Vec;
use core::marker::PhantomData;
use variadics_please::all_tuples;
/// A wrapper over a [`Bundle`] indicating that an entity should be spawned with that [`Bundle`].
/// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
///
/// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn((
/// Spawn(Name::new("Child1")),
/// Spawn((
/// Name::new("Child2"),
/// Children::spawn(Spawn(Name::new("Grandchild"))),
/// ))
/// )),
/// ));
/// ```
pub struct Spawn<B: Bundle>(pub B);
/// A spawn-able list of changes to a given [`World`] and relative to a given [`Entity`]. This is generally used
/// for spawning "related" entities, such as children.
pub trait SpawnableList<R> {
/// Spawn this list of changes in a given [`World`] and relative to a given [`Entity`]. This is generally used
/// for spawning "related" entities, such as children.
fn spawn(self, world: &mut World, entity: Entity);
/// Returns a size hint, which is used to reserve space for this list in a [`RelationshipTarget`]. This should be
/// less than or equal to the actual size of the list. When in doubt, just use 0.
fn size_hint(&self) -> usize;
}
impl<R: Relationship, B: Bundle<Effect: NoBundleEffect>> SpawnableList<R> for Vec<B> {
fn spawn(self, world: &mut World, entity: Entity) {
let mapped_bundles = self.into_iter().map(|b| (R::from(entity), b));
world.spawn_batch(mapped_bundles);
}
fn size_hint(&self) -> usize {
self.len()
}
}
impl<R: Relationship, B: Bundle> SpawnableList<R> for Spawn<B> {
fn spawn(self, world: &mut World, entity: Entity) {
world.spawn((R::from(entity), self.0));
}
fn size_hint(&self) -> usize {
1
}
}
/// A [`SpawnableList`] that spawns entities using an iterator of a given [`Bundle`]:
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::spawn::{Spawn, SpawnIter, SpawnRelated};
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn((
/// Spawn(Name::new("Child1")),
/// SpawnIter(["Child2", "Child3"].into_iter().map(Name::new)),
/// )),
/// ));
/// ```
pub struct SpawnIter<I>(pub I);
impl<R: Relationship, I: Iterator<Item = B> + Send + Sync + 'static, B: Bundle> SpawnableList<R>
for SpawnIter<I>
{
fn spawn(self, world: &mut World, entity: Entity) {
for bundle in self.0 {
world.spawn((R::from(entity), bundle));
}
}
fn size_hint(&self) -> usize {
self.0.size_hint().0
}
}
/// A [`SpawnableList`] that spawns entities using a [`FnOnce`] with a [`RelatedSpawner`] as an argument:
///
/// ```
/// # use bevy_ecs::hierarchy::{Children, ChildOf};
/// # use bevy_ecs::spawn::{Spawn, SpawnWith, SpawnRelated};
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::relationship::RelatedSpawner;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn((
/// Spawn(Name::new("Child1")),
/// SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
/// parent.spawn(Name::new("Child2"));
/// parent.spawn(Name::new("Child3"));
/// }),
/// )),
/// ));
/// ```
pub struct SpawnWith<F>(pub F);
impl<R: Relationship, F: FnOnce(&mut RelatedSpawner<R>) + Send + Sync + 'static> SpawnableList<R>
for SpawnWith<F>
{
fn spawn(self, world: &mut World, entity: Entity) {
world.entity_mut(entity).with_related_entities(self.0);
}
fn size_hint(&self) -> usize {
1
}
}
macro_rules! spawnable_list_impl {
($($list: ident),*) => {
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
)]
impl<R: Relationship, $($list: SpawnableList<R>),*> SpawnableList<R> for ($($list,)*) {
fn spawn(self, _world: &mut World, _entity: Entity) {
#[allow(
non_snake_case,
reason = "The names of these variables are provided by the caller, not by us."
)]
let ($($list,)*) = self;
$($list.spawn(_world, _entity);)*
}
fn size_hint(&self) -> usize {
#[allow(
non_snake_case,
reason = "The names of these variables are provided by the caller, not by us."
)]
let ($($list,)*) = self;
0 $(+ $list.size_hint())*
}
}
}
}
all_tuples!(spawnable_list_impl, 0, 12, P);
/// A [`Bundle`] that:
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for the [`SpawnableList`].
/// 2. Spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
///
/// This is intended to be created using [`SpawnRelated`].
pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
list: L,
marker: PhantomData<R>,
}
impl<R: Relationship, L: SpawnableList<R>> BundleEffect for SpawnRelatedBundle<R, L> {
fn apply(self, entity: &mut EntityWorldMut) {
let id = entity.id();
entity.world_scope(|world: &mut World| {
self.list.spawn(world, id);
});
}
}
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
for SpawnRelatedBundle<R, L>
{
fn component_ids(
components: &mut crate::component::ComponentsRegistrator,
ids: &mut impl FnMut(crate::component::ComponentId),
) {
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
}
fn get_component_ids(
components: &crate::component::Components,
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
) {
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
}
fn register_required_components(
components: &mut crate::component::ComponentsRegistrator,
required_components: &mut crate::component::RequiredComponents,
) {
<R::RelationshipTarget as Bundle>::register_required_components(
components,
required_components,
);
}
}
impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
type Effect = Self;
fn get_components(
self,
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
) -> Self::Effect {
<R::RelationshipTarget as RelationshipTarget>::with_capacity(self.list.size_hint())
.get_components(func);
self
}
}
/// A [`Bundle`] that:
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
///
/// This is intended to be created using [`SpawnRelated`].
pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
bundle: B,
marker: PhantomData<R>,
}
impl<R: Relationship, B: Bundle> BundleEffect for SpawnOneRelated<R, B> {
fn apply(self, entity: &mut EntityWorldMut) {
entity.with_related::<R>(self.bundle);
}
}
impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
type Effect = Self;
fn get_components(
self,
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
) -> Self::Effect {
<R::RelationshipTarget as RelationshipTarget>::with_capacity(1).get_components(func);
self
}
}
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
fn component_ids(
components: &mut crate::component::ComponentsRegistrator,
ids: &mut impl FnMut(crate::component::ComponentId),
) {
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
}
fn get_component_ids(
components: &crate::component::Components,
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
) {
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
}
fn register_required_components(
components: &mut crate::component::ComponentsRegistrator,
required_components: &mut crate::component::RequiredComponents,
) {
<R::RelationshipTarget as Bundle>::register_required_components(
components,
required_components,
);
}
}
/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
///
/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
pub trait SpawnRelated: RelationshipTarget {
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
///
/// See [`Spawn`], [`SpawnIter`], and [`SpawnWith`] for usage examples.
fn spawn<L: SpawnableList<Self::Relationship>>(
list: L,
) -> SpawnRelatedBundle<Self::Relationship, L>;
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
/// via [`RelationshipTarget::Relationship`].
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::spawn::SpawnRelated;
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// Children::spawn_one(Name::new("Child")),
/// ));
/// ```
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B>;
}
impl<T: RelationshipTarget> SpawnRelated for T {
fn spawn<L: SpawnableList<Self::Relationship>>(
list: L,
) -> SpawnRelatedBundle<Self::Relationship, L> {
SpawnRelatedBundle {
list,
marker: PhantomData,
}
}
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B> {
SpawnOneRelated {
bundle,
marker: PhantomData,
}
}
}
/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
///
/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
///
/// Also see [`children`](crate::children) for a [`Children`](crate::hierarchy::Children)-specific equivalent.
///
/// ```
/// # use bevy_ecs::hierarchy::Children;
/// # use bevy_ecs::name::Name;
/// # use bevy_ecs::world::World;
/// # use bevy_ecs::related;
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
/// let mut world = World::new();
/// world.spawn((
/// Name::new("Root"),
/// related!(Children[
/// Name::new("Child1"),
/// (
/// Name::new("Child2"),
/// related!(Children[
/// Name::new("Grandchild"),
/// ])
/// )
/// ])
/// ));
/// ```
#[macro_export]
macro_rules! related {
($relationship_target:ty [$($child:expr),*$(,)?]) => {
<$relationship_target>::spawn(($($crate::spawn::Spawn($child)),*))
};
}

View File

@@ -0,0 +1,500 @@
use super::blob_vec::array_layout;
use crate::storage::blob_vec::array_layout_unchecked;
use alloc::alloc::handle_alloc_error;
use bevy_ptr::{OwningPtr, Ptr, PtrMut};
use bevy_utils::OnDrop;
use core::{alloc::Layout, cell::UnsafeCell, num::NonZeroUsize, ptr::NonNull};
/// A flat, type-erased data storage type similar to a [`BlobVec`](super::blob_vec::BlobVec), but with the length and capacity cut out
/// for performance reasons. This type is reliant on its owning type to store the capacity and length information.
///
/// Used to densely store homogeneous ECS data. A blob is usually just an arbitrary block of contiguous memory without any identity, and
/// could be used to represent any arbitrary data (i.e. string, arrays, etc). This type only stores meta-data about the Blob that it stores,
/// and a pointer to the location of the start of the array, similar to a C array.
pub(super) struct BlobArray {
item_layout: Layout,
// the `data` ptr's layout is always `array_layout(item_layout, capacity)`
data: NonNull<u8>,
// None if the underlying type doesn't need to be dropped
pub drop: Option<unsafe fn(OwningPtr<'_>)>,
#[cfg(debug_assertions)]
capacity: usize,
}
impl BlobArray {
/// Create a new [`BlobArray`] with a specified `capacity`.
/// If `capacity` is 0, no allocations will be made.
///
/// `drop` is an optional function pointer that is meant to be invoked when any element in the [`BlobArray`]
/// should be dropped. For all Rust-based types, this should match 1:1 with the implementation of [`Drop`]
/// if present, and should be `None` if `T: !Drop`. For non-Rust based types, this should match any cleanup
/// processes typically associated with the stored element.
///
/// # Safety
/// `drop` should be safe to call with an [`OwningPtr`] pointing to any item that's been placed into this [`BlobArray`].
/// If `drop` is `None`, the items will be leaked. This should generally be set as None based on [`needs_drop`].
///
/// [`needs_drop`]: std::mem::needs_drop
pub unsafe fn with_capacity(
item_layout: Layout,
drop_fn: Option<unsafe fn(OwningPtr<'_>)>,
capacity: usize,
) -> Self {
if capacity == 0 {
let align = NonZeroUsize::new(item_layout.align()).expect("alignment must be > 0");
let data = bevy_ptr::dangling_with_align(align);
Self {
item_layout,
drop: drop_fn,
data,
#[cfg(debug_assertions)]
capacity,
}
} else {
let mut arr = Self::with_capacity(item_layout, drop_fn, 0);
// SAFETY: `capacity` > 0
unsafe { arr.alloc(NonZeroUsize::new_unchecked(capacity)) }
arr
}
}
/// Returns the [`Layout`] of the element type stored in the vector.
#[inline]
pub fn layout(&self) -> Layout {
self.item_layout
}
/// Return `true` if this [`BlobArray`] stores `ZSTs`.
pub fn is_zst(&self) -> bool {
self.item_layout.size() == 0
}
/// Returns a reference to the element at `index`, without doing bounds checking.
///
/// *`len` refers to the length of the array, the number of elements that have been initialized, and are safe to read.
/// Just like [`Vec::len`], or [`BlobVec::len`](super::blob_vec::BlobVec::len).*
///
/// # Safety
/// - The element at index `index` is safe to access.
/// (If the safety requirements of every method that has been used on `Self` have been fulfilled, the caller just needs to ensure that `index` < `len`)
///
/// [`Vec::len`]: alloc::vec::Vec::len
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> Ptr<'_> {
#[cfg(debug_assertions)]
debug_assert!(index < self.capacity);
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this array,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
unsafe { self.get_ptr().byte_add(index * size) }
}
/// Returns a mutable reference to the element at `index`, without doing bounds checking.
///
/// *`len` refers to the length of the array, the number of elements that have been initialized, and are safe to read.
/// Just like [`Vec::len`], or [`BlobVec::len`](super::blob_vec::BlobVec::len).*
///
/// # Safety
/// - The element with at index `index` is safe to access.
/// (If the safety requirements of every method that has been used on `Self` have been fulfilled, the caller just needs to ensure that `index` < `len`)
///
/// [`Vec::len`]: alloc::vec::Vec::len
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> PtrMut<'_> {
#[cfg(debug_assertions)]
debug_assert!(index < self.capacity);
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this vector,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
unsafe { self.get_ptr_mut().byte_add(index * size) }
}
/// Gets a [`Ptr`] to the start of the array
#[inline]
pub fn get_ptr(&self) -> Ptr<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { Ptr::new(self.data) }
}
/// Gets a [`PtrMut`] to the start of the array
#[inline]
pub fn get_ptr_mut(&mut self) -> PtrMut<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { PtrMut::new(self.data) }
}
/// Get a slice of the first `slice_len` elements in [`BlobArray`] as if it were an array with elements of type `T`
/// To get a slice to the entire array, the caller must plug `len` in `slice_len`.
///
/// *`len` refers to the length of the array, the number of elements that have been initialized, and are safe to read.
/// Just like [`Vec::len`], or [`BlobVec::len`](super::blob_vec::BlobVec::len).*
///
/// # Safety
/// - The type `T` must be the type of the items in this [`BlobArray`].
/// - `slice_len` <= `len`
///
/// [`Vec::len`]: alloc::vec::Vec::len
pub unsafe fn get_sub_slice<T>(&self, slice_len: usize) -> &[UnsafeCell<T>] {
#[cfg(debug_assertions)]
debug_assert!(slice_len <= self.capacity);
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe {
core::slice::from_raw_parts(self.data.as_ptr() as *const UnsafeCell<T>, slice_len)
}
}
/// Clears the array, i.e. removing (and dropping) all of the elements.
/// Note that this method has no effect on the allocated capacity of the vector.
///
/// Note that this method will behave exactly the same as [`Vec::clear`].
///
/// # Safety
/// - For every element with index `i`, if `i` < `len`: It must be safe to call [`Self::get_unchecked_mut`] with `i`.
/// (If the safety requirements of every method that has been used on `Self` have been fulfilled, the caller just needs to ensure that `len` is correct.)
///
/// [`Vec::clear`]: alloc::vec::Vec::clear
pub unsafe fn clear(&mut self, len: usize) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity >= len);
if let Some(drop) = self.drop {
// We set `self.drop` to `None` before dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.drop = None;
let size = self.item_layout.size();
for i in 0..len {
// SAFETY:
// * 0 <= `i` < `len`, so `i * size` must be in bounds for the allocation.
// * `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// * The item is left unreachable so it can be safely promoted to an `OwningPtr`.
let item = unsafe { self.get_ptr_mut().byte_add(i * size).promote() };
// SAFETY: `item` was obtained from this `BlobArray`, so its underlying type must match `drop`.
unsafe { drop(item) };
}
self.drop = Some(drop);
}
}
/// Because this method needs parameters, it can't be the implementation of the `Drop` trait.
/// The owner of this [`BlobArray`] must call this method with the correct information.
///
/// # Safety
/// - `cap` and `len` are indeed the capacity and length of this [`BlobArray`]
/// - This [`BlobArray`] mustn't be used after calling this method.
pub unsafe fn drop(&mut self, cap: usize, len: usize) {
#[cfg(debug_assertions)]
debug_assert_eq!(self.capacity, cap);
if cap != 0 {
self.clear(len);
if !self.is_zst() {
let layout =
array_layout(&self.item_layout, cap).expect("array layout should be valid");
alloc::alloc::dealloc(self.data.as_ptr().cast(), layout);
}
#[cfg(debug_assertions)]
{
self.capacity = 0;
}
}
}
/// Drops the last element in this [`BlobArray`].
///
/// # Safety
// - `last_element_index` must correspond to the last element in the array.
// - After this method is called, the last element must not be used
// unless [`Self::initialize_unchecked`] is called to set the value of the last element.
pub unsafe fn drop_last_element(&mut self, last_element_index: usize) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity > last_element_index);
if let Some(drop) = self.drop {
// We set `self.drop` to `None` before dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.drop = None;
// SAFETY:
let item = self.get_unchecked_mut(last_element_index).promote();
// SAFETY:
unsafe { drop(item) };
self.drop = Some(drop);
}
}
/// Allocate a block of memory for the array. This should be used to initialize the array, do not use this
/// method if there are already elements stored in the array - use [`Self::realloc`] instead.
pub(super) fn alloc(&mut self, capacity: NonZeroUsize) {
#[cfg(debug_assertions)]
debug_assert_eq!(self.capacity, 0);
if !self.is_zst() {
let new_layout = array_layout(&self.item_layout, capacity.get())
.expect("array layout should be valid");
// SAFETY: layout has non-zero size because capacity > 0, and the blob isn't ZST (`self.is_zst` == false)
let new_data = unsafe { alloc::alloc::alloc(new_layout) };
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
}
#[cfg(debug_assertions)]
{
self.capacity = capacity.into();
}
}
/// Reallocate memory for this array.
/// For example, if the length (number of stored elements) reached the capacity (number of elements the current allocation can store),
/// you might want to use this method to increase the allocation, so more data can be stored in the array.
///
/// # Safety
/// - `current_capacity` is indeed the current capacity of this array.
/// - After calling this method, the caller must update their saved capacity to reflect the change.
pub(super) unsafe fn realloc(
&mut self,
current_capacity: NonZeroUsize,
new_capacity: NonZeroUsize,
) {
#[cfg(debug_assertions)]
debug_assert_eq!(self.capacity, current_capacity.get());
if !self.is_zst() {
// SAFETY: `new_capacity` can't overflow usize
let new_layout =
unsafe { array_layout_unchecked(&self.item_layout, new_capacity.get()) };
// SAFETY:
// - ptr was be allocated via this allocator
// - the layout used to previously allocate this array is equivalent to `array_layout(&self.item_layout, current_capacity.get())`
// - `item_layout.size() > 0` (`self.is_zst`==false) and `new_capacity > 0`, so the layout size is non-zero
// - "new_size, when rounded up to the nearest multiple of layout.align(), must not overflow (i.e., the rounded value must be less than usize::MAX)",
// since the item size is always a multiple of its align, the rounding cannot happen
// here and the overflow is handled in `array_layout`
let new_data = unsafe {
alloc::alloc::realloc(
self.get_ptr_mut().as_ptr(),
// SAFETY: This is the Layout of the current array, it must be valid, if it hadn't have been, there would have been a panic on a previous allocation
array_layout_unchecked(&self.item_layout, current_capacity.get()),
new_layout.size(),
)
};
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
}
#[cfg(debug_assertions)]
{
self.capacity = new_capacity.into();
}
}
/// Initializes the value at `index` to `value`. This function does not do any bounds checking.
///
/// # Safety
/// - `index` must be in bounds (`index` < capacity)
/// - The [`Layout`] of the value must match the layout of the blobs stored in this array,
/// and it must be safe to use the `drop` function of this [`BlobArray`] to drop `value`.
/// - `value` must not point to the same value that is being initialized.
#[inline]
pub unsafe fn initialize_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity > index);
let size = self.item_layout.size();
let dst = self.get_unchecked_mut(index);
core::ptr::copy::<u8>(value.as_ptr(), dst.as_ptr(), size);
}
/// Replaces the value at `index` with `value`. This function does not do any bounds checking.
///
/// # Safety
/// - Index must be in-bounds (`index` < `len`)
/// - `value`'s [`Layout`] must match this [`BlobArray`]'s `item_layout`,
/// and it must be safe to use the `drop` function of this [`BlobArray`] to drop `value`.
/// - `value` must not point to the same value that is being replaced.
pub unsafe fn replace_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
#[cfg(debug_assertions)]
debug_assert!(self.capacity > index);
// Pointer to the value in the vector that will get replaced.
// SAFETY: The caller ensures that `index` fits in this vector.
let destination = NonNull::from(unsafe { self.get_unchecked_mut(index) });
let source = value.as_ptr();
if let Some(drop) = self.drop {
// We set `self.drop` to `None` before dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.drop = None;
// Transfer ownership of the old value out of the vector, so it can be dropped.
// SAFETY:
// - `destination` was obtained from a `PtrMut` in this vector, which ensures it is non-null,
// well-aligned for the underlying type, and has proper provenance.
// - The storage location will get overwritten with `value` later, which ensures
// that the element will not get observed or double dropped later.
// - If a panic occurs, `self.len` will remain `0`, which ensures a double-drop
// does not occur. Instead, all elements will be forgotten.
let old_value = unsafe { OwningPtr::new(destination) };
// This closure will run in case `drop()` panics,
// which ensures that `value` does not get forgotten.
let on_unwind = OnDrop::new(|| drop(value));
drop(old_value);
// If the above code does not panic, make sure that `value` doesn't get dropped.
core::mem::forget(on_unwind);
self.drop = Some(drop);
}
// Copy the new value into the vector, overwriting the previous value.
// SAFETY:
// - `source` and `destination` were obtained from `OwningPtr`s, which ensures they are
// valid for both reads and writes.
// - The value behind `source` will only be dropped if the above branch panics,
// so it must still be initialized and it is safe to transfer ownership into the vector.
// - `source` and `destination` were obtained from different memory locations,
// both of which we have exclusive access to, so they are guaranteed not to overlap.
unsafe {
core::ptr::copy_nonoverlapping::<u8>(
source,
destination.as_ptr(),
self.item_layout.size(),
);
}
}
/// This method will swap two elements in the array, and return the one at `index_to_remove`.
/// It is the caller's responsibility to drop the returned pointer, if that is desirable.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
#[must_use = "The returned pointer should be used to drop the removed element"]
pub unsafe fn swap_remove_unchecked(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) -> OwningPtr<'_> {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
}
if index_to_remove != index_to_keep {
return self.swap_remove_unchecked_nonoverlapping(index_to_remove, index_to_keep);
}
// Now the element that used to be in index `index_to_remove` is now in index `index_to_keep` (after swap)
// If we are storing ZSTs than the index doesn't actually matter because the size is 0.
self.get_unchecked_mut(index_to_keep).promote()
}
/// The same as [`Self::swap_remove_unchecked`] but the two elements must non-overlapping.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_unchecked_nonoverlapping(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) -> OwningPtr<'_> {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
debug_assert_ne!(index_to_keep, index_to_remove);
}
debug_assert_ne!(index_to_keep, index_to_remove);
core::ptr::swap_nonoverlapping::<u8>(
self.get_unchecked_mut(index_to_keep).as_ptr(),
self.get_unchecked_mut(index_to_remove).as_ptr(),
self.item_layout.size(),
);
// Now the element that used to be in index `index_to_remove` is now in index `index_to_keep` (after swap)
// If we are storing ZSTs than the index doesn't actually matter because the size is 0.
self.get_unchecked_mut(index_to_keep).promote()
}
/// This method will call [`Self::swap_remove_unchecked`] and drop the result.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
}
let drop = self.drop;
let value = self.swap_remove_unchecked(index_to_remove, index_to_keep);
if let Some(drop) = drop {
drop(value);
}
}
/// The same as [`Self::swap_remove_and_drop_unchecked`] but the two elements must non-overlapping.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked_nonoverlapping(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
debug_assert_ne!(index_to_keep, index_to_remove);
}
let drop = self.drop;
let value = self.swap_remove_unchecked_nonoverlapping(index_to_remove, index_to_keep);
if let Some(drop) = drop {
drop(value);
}
}
}
#[cfg(test)]
mod tests {
use bevy_ecs::prelude::*;
#[derive(Component)]
struct PanicOnDrop;
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!("PanicOnDrop is being Dropped");
}
}
#[test]
#[should_panic(expected = "PanicOnDrop is being Dropped")]
fn make_sure_zst_components_get_dropped() {
let mut world = World::new();
world.spawn(PanicOnDrop);
}
}

724
vendor/bevy_ecs/src/storage/blob_vec.rs vendored Normal file
View File

@@ -0,0 +1,724 @@
use alloc::alloc::handle_alloc_error;
use bevy_ptr::{OwningPtr, Ptr, PtrMut};
use bevy_utils::OnDrop;
use core::{alloc::Layout, cell::UnsafeCell, num::NonZero, ptr::NonNull};
/// A flat, type-erased data storage type
///
/// Used to densely store homogeneous ECS data. A blob is usually just an arbitrary block of contiguous memory without any identity, and
/// could be used to represent any arbitrary data (i.e. string, arrays, etc). This type is an extendable and re-allocatable blob, which makes
/// it a blobby Vec, a `BlobVec`.
pub(super) struct BlobVec {
item_layout: Layout,
capacity: usize,
/// Number of elements, not bytes
len: usize,
// the `data` ptr's layout is always `array_layout(item_layout, capacity)`
data: NonNull<u8>,
// None if the underlying type doesn't need to be dropped
drop: Option<unsafe fn(OwningPtr<'_>)>,
}
// We want to ignore the `drop` field in our `Debug` impl
impl core::fmt::Debug for BlobVec {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BlobVec")
.field("item_layout", &self.item_layout)
.field("capacity", &self.capacity)
.field("len", &self.len)
.field("data", &self.data)
.finish()
}
}
impl BlobVec {
/// Creates a new [`BlobVec`] with the specified `capacity`.
///
/// `drop` is an optional function pointer that is meant to be invoked when any element in the [`BlobVec`]
/// should be dropped. For all Rust-based types, this should match 1:1 with the implementation of [`Drop`]
/// if present, and should be `None` if `T: !Drop`. For non-Rust based types, this should match any cleanup
/// processes typically associated with the stored element.
///
/// # Safety
///
/// `drop` should be safe to call with an [`OwningPtr`] pointing to any item that's been pushed into this [`BlobVec`].
///
/// If `drop` is `None`, the items will be leaked. This should generally be set as None based on [`needs_drop`].
///
/// [`needs_drop`]: std::mem::needs_drop
pub unsafe fn new(
item_layout: Layout,
drop: Option<unsafe fn(OwningPtr<'_>)>,
capacity: usize,
) -> BlobVec {
let align = NonZero::<usize>::new(item_layout.align()).expect("alignment must be > 0");
let data = bevy_ptr::dangling_with_align(align);
if item_layout.size() == 0 {
BlobVec {
data,
// ZST `BlobVec` max size is `usize::MAX`, and `reserve_exact` for ZST assumes
// the capacity is always `usize::MAX` and panics if it overflows.
capacity: usize::MAX,
len: 0,
item_layout,
drop,
}
} else {
let mut blob_vec = BlobVec {
data,
capacity: 0,
len: 0,
item_layout,
drop,
};
blob_vec.reserve_exact(capacity);
blob_vec
}
}
/// Returns the number of elements in the vector.
#[inline]
pub fn len(&self) -> usize {
self.len
}
/// Returns `true` if the vector contains no elements.
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns the [`Layout`] of the element type stored in the vector.
#[inline]
pub fn layout(&self) -> Layout {
self.item_layout
}
/// Reserves the minimum capacity for at least `additional` more elements to be inserted in the given `BlobVec`.
/// After calling `reserve_exact`, capacity will be greater than or equal to `self.len() + additional`. Does nothing if
/// the capacity is already sufficient.
///
/// Note that the allocator may give the collection more space than it requests. Therefore, capacity can not be relied upon
/// to be precisely minimal.
///
/// # Panics
///
/// Panics if new capacity overflows `usize`.
pub fn reserve_exact(&mut self, additional: usize) {
let available_space = self.capacity - self.len;
if available_space < additional {
// SAFETY: `available_space < additional`, so `additional - available_space > 0`
let increment =
unsafe { NonZero::<usize>::new_unchecked(additional - available_space) };
self.grow_exact(increment);
}
}
/// Reserves the minimum capacity for at least `additional` more elements to be inserted in the given `BlobVec`.
#[inline]
pub fn reserve(&mut self, additional: usize) {
/// Similar to `reserve_exact`. This method ensures that the capacity will grow at least `self.capacity()` if there is no
/// enough space to hold `additional` more elements.
#[cold]
fn do_reserve(slf: &mut BlobVec, additional: usize) {
let increment = slf.capacity.max(additional - (slf.capacity - slf.len));
let increment = NonZero::<usize>::new(increment).unwrap();
slf.grow_exact(increment);
}
if self.capacity - self.len < additional {
do_reserve(self, additional);
}
}
/// Grows the capacity by `increment` elements.
///
/// # Panics
///
/// Panics if the new capacity overflows `usize`.
/// For ZST it panics unconditionally because ZST `BlobVec` capacity
/// is initialized to `usize::MAX` and always stays that way.
fn grow_exact(&mut self, increment: NonZero<usize>) {
let new_capacity = self
.capacity
.checked_add(increment.get())
.expect("capacity overflow");
let new_layout =
array_layout(&self.item_layout, new_capacity).expect("array layout should be valid");
let new_data = if self.capacity == 0 {
// SAFETY:
// - layout has non-zero size as per safety requirement
unsafe { alloc::alloc::alloc(new_layout) }
} else {
// SAFETY:
// - ptr was be allocated via this allocator
// - the layout of the ptr was `array_layout(self.item_layout, self.capacity)`
// - `item_layout.size() > 0` and `new_capacity > 0`, so the layout size is non-zero
// - "new_size, when rounded up to the nearest multiple of layout.align(), must not overflow (i.e., the rounded value must be less than usize::MAX)",
// since the item size is always a multiple of its alignment, the rounding cannot happen
// here and the overflow is handled in `array_layout`
unsafe {
alloc::alloc::realloc(
self.get_ptr_mut().as_ptr(),
array_layout(&self.item_layout, self.capacity)
.expect("array layout should be valid"),
new_layout.size(),
)
}
};
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
self.capacity = new_capacity;
}
/// Initializes the value at `index` to `value`. This function does not do any bounds checking.
///
/// # Safety
/// - index must be in bounds
/// - the memory in the [`BlobVec`] starting at index `index`, of a size matching this [`BlobVec`]'s
/// `item_layout`, must have been previously allocated.
#[inline]
pub unsafe fn initialize_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
debug_assert!(index < self.len());
let ptr = self.get_unchecked_mut(index);
core::ptr::copy_nonoverlapping::<u8>(value.as_ptr(), ptr.as_ptr(), self.item_layout.size());
}
/// Replaces the value at `index` with `value`. This function does not do any bounds checking.
///
/// # Safety
/// - index must be in-bounds
/// - the memory in the [`BlobVec`] starting at index `index`, of a size matching this
/// [`BlobVec`]'s `item_layout`, must have been previously initialized with an item matching
/// this [`BlobVec`]'s `item_layout`
/// - the memory at `*value` must also be previously initialized with an item matching this
/// [`BlobVec`]'s `item_layout`
pub unsafe fn replace_unchecked(&mut self, index: usize, value: OwningPtr<'_>) {
debug_assert!(index < self.len());
// Pointer to the value in the vector that will get replaced.
// SAFETY: The caller ensures that `index` fits in this vector.
let destination = NonNull::from(unsafe { self.get_unchecked_mut(index) });
let source = value.as_ptr();
if let Some(drop) = self.drop {
// Temporarily set the length to zero, so that if `drop` panics the caller
// will not be left with a `BlobVec` containing a dropped element within
// its initialized range.
let old_len = self.len;
self.len = 0;
// Transfer ownership of the old value out of the vector, so it can be dropped.
// SAFETY:
// - `destination` was obtained from a `PtrMut` in this vector, which ensures it is non-null,
// well-aligned for the underlying type, and has proper provenance.
// - The storage location will get overwritten with `value` later, which ensures
// that the element will not get observed or double dropped later.
// - If a panic occurs, `self.len` will remain `0`, which ensures a double-drop
// does not occur. Instead, all elements will be forgotten.
let old_value = unsafe { OwningPtr::new(destination) };
// This closure will run in case `drop()` panics,
// which ensures that `value` does not get forgotten.
let on_unwind = OnDrop::new(|| drop(value));
drop(old_value);
// If the above code does not panic, make sure that `value` doesn't get dropped.
core::mem::forget(on_unwind);
// Make the vector's contents observable again, since panics are no longer possible.
self.len = old_len;
}
// Copy the new value into the vector, overwriting the previous value.
// SAFETY:
// - `source` and `destination` were obtained from `OwningPtr`s, which ensures they are
// valid for both reads and writes.
// - The value behind `source` will only be dropped if the above branch panics,
// so it must still be initialized and it is safe to transfer ownership into the vector.
// - `source` and `destination` were obtained from different memory locations,
// both of which we have exclusive access to, so they are guaranteed not to overlap.
unsafe {
core::ptr::copy_nonoverlapping::<u8>(
source,
destination.as_ptr(),
self.item_layout.size(),
);
}
}
/// Appends an element to the back of the vector.
///
/// # Safety
/// The `value` must match the [`layout`](`BlobVec::layout`) of the elements in the [`BlobVec`].
#[inline]
pub unsafe fn push(&mut self, value: OwningPtr<'_>) {
self.reserve(1);
let index = self.len;
self.len += 1;
self.initialize_unchecked(index, value);
}
/// Performs a "swap remove" at the given `index`, which removes the item at `index` and moves
/// the last item in the [`BlobVec`] to `index` (if `index` is not the last item). It is the
/// caller's responsibility to drop the returned pointer, if that is desirable.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index` is less than `self.len()`.
#[must_use = "The returned pointer should be used to dropped the removed element"]
pub unsafe fn swap_remove_and_forget_unchecked(&mut self, index: usize) -> OwningPtr<'_> {
debug_assert!(index < self.len());
// Since `index` must be strictly less than `self.len` and `index` is at least zero,
// `self.len` must be at least one. Thus, this cannot underflow.
let new_len = self.len - 1;
let size = self.item_layout.size();
if index != new_len {
core::ptr::swap_nonoverlapping::<u8>(
self.get_unchecked_mut(index).as_ptr(),
self.get_unchecked_mut(new_len).as_ptr(),
size,
);
}
self.len = new_len;
// Cannot use get_unchecked here as this is technically out of bounds after changing len.
// SAFETY:
// - `new_len` is less than the old len, so it must fit in this vector's allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// - The removed element lives as long as this vector's mutable reference.
let p = unsafe { self.get_ptr_mut().byte_add(new_len * size) };
// SAFETY: The removed element is unreachable by this vector so it's safe to promote the
// `PtrMut` to an `OwningPtr`.
unsafe { p.promote() }
}
/// Removes the value at `index` and drops it.
/// Does not do any bounds checking on `index`.
/// The removed element is replaced by the last element of the `BlobVec`.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index` is `< self.len()`.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked(&mut self, index: usize) {
debug_assert!(index < self.len());
let drop = self.drop;
let value = self.swap_remove_and_forget_unchecked(index);
if let Some(drop) = drop {
drop(value);
}
}
/// Returns a reference to the element at `index`, without doing bounds checking.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index < self.len()`.
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> Ptr<'_> {
debug_assert!(index < self.len());
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this vector,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// - The element at `index` outlives this vector's reference.
unsafe { self.get_ptr().byte_add(index * size) }
}
/// Returns a mutable reference to the element at `index`, without doing bounds checking.
///
/// # Safety
/// It is the caller's responsibility to ensure that `index < self.len()`.
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> PtrMut<'_> {
debug_assert!(index < self.len());
let size = self.item_layout.size();
// SAFETY:
// - The caller ensures that `index` fits in this vector,
// so this operation will not overflow the original allocation.
// - `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// - The element at `index` outlives this vector's mutable reference.
unsafe { self.get_ptr_mut().byte_add(index * size) }
}
/// Gets a [`Ptr`] to the start of the vec
#[inline]
pub fn get_ptr(&self) -> Ptr<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { Ptr::new(self.data) }
}
/// Gets a [`PtrMut`] to the start of the vec
#[inline]
pub fn get_ptr_mut(&mut self) -> PtrMut<'_> {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { PtrMut::new(self.data) }
}
/// Get a reference to the entire [`BlobVec`] as if it were an array with elements of type `T`
///
/// # Safety
/// The type `T` must be the type of the items in this [`BlobVec`].
pub unsafe fn get_slice<T>(&self) -> &[UnsafeCell<T>] {
// SAFETY: the inner data will remain valid for as long as 'self.
unsafe { core::slice::from_raw_parts(self.data.as_ptr() as *const UnsafeCell<T>, self.len) }
}
/// Returns the drop function for values stored in the vector,
/// or `None` if they don't need to be dropped.
#[inline]
pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
self.drop
}
/// Clears the vector, removing (and dropping) all values.
///
/// Note that this method has no effect on the allocated capacity of the vector.
pub fn clear(&mut self) {
let len = self.len;
// We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't
// accidentally drop elements twice in the event of a drop impl panicking.
self.len = 0;
if let Some(drop) = self.drop {
let size = self.item_layout.size();
for i in 0..len {
// SAFETY:
// * 0 <= `i` < `len`, so `i * size` must be in bounds for the allocation.
// * `size` is a multiple of the erased type's alignment,
// so adding a multiple of `size` will preserve alignment.
// * The item lives until it's dropped.
// * The item is left unreachable so it can be safely promoted to an `OwningPtr`.
// NOTE: `self.get_unchecked_mut(i)` cannot be used here, since the `debug_assert`
// would panic due to `self.len` being set to 0.
let item = unsafe { self.get_ptr_mut().byte_add(i * size).promote() };
// SAFETY: `item` was obtained from this `BlobVec`, so its underlying type must match `drop`.
unsafe { drop(item) };
}
}
}
}
impl Drop for BlobVec {
fn drop(&mut self) {
self.clear();
let array_layout =
array_layout(&self.item_layout, self.capacity).expect("array layout should be valid");
if array_layout.size() > 0 {
// SAFETY: data ptr layout is correct, swap_scratch ptr layout is correct
unsafe {
alloc::alloc::dealloc(self.get_ptr_mut().as_ptr(), array_layout);
}
}
}
}
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
pub(super) fn array_layout(layout: &Layout, n: usize) -> Option<Layout> {
let (array_layout, offset) = repeat_layout(layout, n)?;
debug_assert_eq!(layout.size(), offset);
Some(array_layout)
}
// TODO: replace with `Layout::repeat` if/when it stabilizes
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
fn repeat_layout(layout: &Layout, n: usize) -> Option<(Layout, usize)> {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow (i.e., the rounded value must be less than
// > `usize::MAX`)
let padded_size = layout.size() + padding_needed_for(layout, layout.align());
let alloc_size = padded_size.checked_mul(n)?;
// SAFETY: self.align is already known to be valid and alloc_size has been
// padded already.
unsafe {
Some((
Layout::from_size_align_unchecked(alloc_size, layout.align()),
padded_size,
))
}
}
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
/// # Safety
/// The caller must ensure that:
/// - The resulting [`Layout`] is valid, by ensuring that `(layout.size() + padding_needed_for(layout, layout.align())) * n` doesn't overflow.
pub(super) unsafe fn array_layout_unchecked(layout: &Layout, n: usize) -> Layout {
let (array_layout, offset) = repeat_layout_unchecked(layout, n);
debug_assert_eq!(layout.size(), offset);
array_layout
}
// TODO: replace with `Layout::repeat` if/when it stabilizes
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
/// # Safety
/// The caller must ensure that:
/// - The resulting [`Layout`] is valid, by ensuring that `(layout.size() + padding_needed_for(layout, layout.align())) * n` doesn't overflow.
unsafe fn repeat_layout_unchecked(layout: &Layout, n: usize) -> (Layout, usize) {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow (i.e., the rounded value must be less than
// > `usize::MAX`)
let padded_size = layout.size() + padding_needed_for(layout, layout.align());
// This may overflow in release builds, that's why this function is unsafe.
let alloc_size = padded_size * n;
// SAFETY: self.align is already known to be valid and alloc_size has been
// padded already.
unsafe {
(
Layout::from_size_align_unchecked(alloc_size, layout.align()),
padded_size,
)
}
}
/// From <https://doc.rust-lang.org/beta/src/core/alloc/layout.rs.html>
const fn padding_needed_for(layout: &Layout, align: usize) -> usize {
let len = layout.size();
// Rounded up value is:
// len_rounded_up = (len + align - 1) & !(align - 1);
// and then we return the padding difference: `len_rounded_up - len`.
//
// We use modular arithmetic throughout:
//
// 1. align is guaranteed to be > 0, so align - 1 is always
// valid.
//
// 2. `len + align - 1` can overflow by at most `align - 1`,
// so the &-mask with `!(align - 1)` will ensure that in the
// case of overflow, `len_rounded_up` will itself be 0.
// Thus the returned padding, when added to `len`, yields 0,
// which trivially satisfies the alignment `align`.
//
// (Of course, attempts to allocate blocks of memory whose
// size and padding overflow in the above manner should cause
// the allocator to yield an error anyway.)
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len)
}
#[cfg(test)]
mod tests {
use super::BlobVec;
use crate::{component::Component, ptr::OwningPtr, world::World};
use alloc::{
rc::Rc,
string::{String, ToString},
};
use core::{alloc::Layout, cell::RefCell};
/// # Safety
///
/// The pointer `x` must point to a valid value of type `T` and it must be safe to drop this value.
unsafe fn drop_ptr<T>(x: OwningPtr<'_>) {
// SAFETY: It is guaranteed by the caller that `x` points to a
// valid value of type `T` and it is safe to drop this value.
unsafe {
x.drop_as::<T>();
}
}
/// # Safety
///
/// `blob_vec` must have a layout that matches `Layout::new::<T>()`
unsafe fn push<T>(blob_vec: &mut BlobVec, value: T) {
OwningPtr::make(value, |ptr| {
blob_vec.push(ptr);
});
}
/// # Safety
///
/// `blob_vec` must have a layout that matches `Layout::new::<T>()`
unsafe fn swap_remove<T>(blob_vec: &mut BlobVec, index: usize) -> T {
assert!(index < blob_vec.len());
let value = blob_vec.swap_remove_and_forget_unchecked(index);
value.read::<T>()
}
/// # Safety
///
/// `blob_vec` must have a layout that matches `Layout::new::<T>()`, it most store a valid `T`
/// value at the given `index`
unsafe fn get_mut<T>(blob_vec: &mut BlobVec, index: usize) -> &mut T {
assert!(index < blob_vec.len());
blob_vec.get_unchecked_mut(index).deref_mut::<T>()
}
#[test]
fn resize_test() {
let item_layout = Layout::new::<usize>();
// SAFETY: `drop` fn is `None`, usize doesn't need dropping
let mut blob_vec = unsafe { BlobVec::new(item_layout, None, 64) };
// SAFETY: `i` is a usize, i.e. the type corresponding to `item_layout`
unsafe {
for i in 0..1_000 {
push(&mut blob_vec, i as usize);
}
}
assert_eq!(blob_vec.len(), 1_000);
assert_eq!(blob_vec.capacity, 1_024);
}
#[derive(Debug, Eq, PartialEq, Clone)]
struct Foo {
a: u8,
b: String,
drop_counter: Rc<RefCell<usize>>,
}
impl Drop for Foo {
fn drop(&mut self) {
*self.drop_counter.borrow_mut() += 1;
}
}
#[test]
fn blob_vec() {
let drop_counter = Rc::new(RefCell::new(0));
{
let item_layout = Layout::new::<Foo>();
let drop = drop_ptr::<Foo>;
// SAFETY: drop is able to drop a value of its `item_layout`
let mut blob_vec = unsafe { BlobVec::new(item_layout, Some(drop), 2) };
assert_eq!(blob_vec.capacity, 2);
// SAFETY: the following code only deals with values of type `Foo`, which satisfies the safety requirement of `push`, `get_mut` and `swap_remove` that the
// values have a layout compatible to the blob vec's `item_layout`.
// Every index is in range.
unsafe {
let foo1 = Foo {
a: 42,
b: "abc".to_string(),
drop_counter: drop_counter.clone(),
};
push(&mut blob_vec, foo1.clone());
assert_eq!(blob_vec.len(), 1);
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo1);
let mut foo2 = Foo {
a: 7,
b: "xyz".to_string(),
drop_counter: drop_counter.clone(),
};
push::<Foo>(&mut blob_vec, foo2.clone());
assert_eq!(blob_vec.len(), 2);
assert_eq!(blob_vec.capacity, 2);
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo1);
assert_eq!(get_mut::<Foo>(&mut blob_vec, 1), &foo2);
get_mut::<Foo>(&mut blob_vec, 1).a += 1;
assert_eq!(get_mut::<Foo>(&mut blob_vec, 1).a, 8);
let foo3 = Foo {
a: 16,
b: "123".to_string(),
drop_counter: drop_counter.clone(),
};
push(&mut blob_vec, foo3.clone());
assert_eq!(blob_vec.len(), 3);
assert_eq!(blob_vec.capacity, 4);
let last_index = blob_vec.len() - 1;
let value = swap_remove::<Foo>(&mut blob_vec, last_index);
assert_eq!(foo3, value);
assert_eq!(blob_vec.len(), 2);
assert_eq!(blob_vec.capacity, 4);
let value = swap_remove::<Foo>(&mut blob_vec, 0);
assert_eq!(foo1, value);
assert_eq!(blob_vec.len(), 1);
assert_eq!(blob_vec.capacity, 4);
foo2.a = 8;
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo2);
}
}
assert_eq!(*drop_counter.borrow(), 6);
}
#[test]
fn blob_vec_drop_empty_capacity() {
let item_layout = Layout::new::<Foo>();
let drop = drop_ptr::<Foo>;
// SAFETY: drop is able to drop a value of its `item_layout`
let _ = unsafe { BlobVec::new(item_layout, Some(drop), 0) };
}
#[test]
#[should_panic(expected = "capacity overflow")]
fn blob_vec_zst_size_overflow() {
// SAFETY: no drop is correct drop for `()`.
let mut blob_vec = unsafe { BlobVec::new(Layout::new::<()>(), None, 0) };
assert_eq!(usize::MAX, blob_vec.capacity, "Self-check");
// SAFETY: Because `()` is a ZST trivial drop type, and because `BlobVec` capacity
// is always `usize::MAX` for ZSTs, we can arbitrarily set the length
// and still be sound.
blob_vec.len = usize::MAX;
// SAFETY: `BlobVec` was initialized for `()`, so it is safe to push `()` to it.
unsafe {
OwningPtr::make((), |ptr| {
// This should panic because len is usize::MAX, remaining capacity is 0.
blob_vec.push(ptr);
});
}
}
#[test]
#[should_panic(expected = "capacity overflow")]
fn blob_vec_capacity_overflow() {
// SAFETY: no drop is correct drop for `u32`.
let mut blob_vec = unsafe { BlobVec::new(Layout::new::<u32>(), None, 0) };
assert_eq!(0, blob_vec.capacity, "Self-check");
OwningPtr::make(17u32, |ptr| {
// SAFETY: we push the value of correct type.
unsafe {
blob_vec.push(ptr);
}
});
blob_vec.reserve_exact(usize::MAX);
}
#[test]
fn aligned_zst() {
// NOTE: This test is explicitly for uncovering potential UB with miri.
#[derive(Component)]
#[repr(align(32))]
struct Zst;
let mut world = World::default();
world.spawn(Zst);
world.spawn(Zst);
world.spawn(Zst);
world.spawn_empty();
let mut count = 0;
let mut q = world.query::<&Zst>();
for zst in q.iter(&world) {
// Ensure that the references returned are properly aligned.
assert_eq!(
core::ptr::from_ref::<Zst>(zst) as usize % align_of::<Zst>(),
0
);
count += 1;
}
assert_eq!(count, 3);
}
}

62
vendor/bevy_ecs/src/storage/mod.rs vendored Normal file
View File

@@ -0,0 +1,62 @@
//! Storage layouts for ECS data.
//!
//! This module implements the low-level collections that store data in a [`World`]. These all offer minimal and often
//! unsafe APIs, and have been made `pub` primarily for debugging and monitoring purposes.
//!
//! # Fetching Storages
//! Each of the below data stores can be fetched via [`Storages`], which can be fetched from a
//! [`World`] via [`World::storages`]. It exposes a top level container for each class of storage within
//! ECS:
//!
//! - [`Tables`] - columnar contiguous blocks of memory, optimized for fast iteration.
//! - [`SparseSets`] - sparse `HashMap`-like mappings from entities to components, optimized for random
//! lookup and regular insertion/removal of components.
//! - [`Resources`] - singleton storage for the resources in the world
//!
//! # Safety
//! To avoid trivially unsound use of the APIs in this module, it is explicitly impossible to get a mutable
//! reference to [`Storages`] from [`World`], and none of the types publicly expose a mutable interface.
//!
//! [`World`]: crate::world::World
//! [`World::storages`]: crate::world::World::storages
mod blob_array;
mod blob_vec;
mod resource;
mod sparse_set;
mod table;
mod thin_array_ptr;
pub use resource::*;
pub use sparse_set::*;
pub use table::*;
use crate::component::{ComponentInfo, StorageType};
/// The raw data stores of a [`World`](crate::world::World)
#[derive(Default)]
pub struct Storages {
/// Backing storage for [`SparseSet`] components.
/// Note that sparse sets are only present for components that have been spawned or have had a relevant bundle registered.
pub sparse_sets: SparseSets,
/// Backing storage for [`Table`] components.
pub tables: Tables,
/// Backing storage for resources.
pub resources: Resources<true>,
/// Backing storage for `!Send` resources.
pub non_send_resources: Resources<false>,
}
impl Storages {
/// ensures that the component has its necessary storage initialize.
pub fn prepare_component(&mut self, component: &ComponentInfo) {
match component.storage_type() {
StorageType::Table => {
// table needs no preparation
}
StorageType::SparseSet => {
self.sparse_sets.get_or_insert(component);
}
}
}
}

403
vendor/bevy_ecs/src/storage/resource.rs vendored Normal file
View File

@@ -0,0 +1,403 @@
use crate::{
archetype::ArchetypeComponentId,
change_detection::{MaybeLocation, MutUntyped, TicksMut},
component::{ComponentId, ComponentTicks, Components, Tick, TickCells},
storage::{blob_vec::BlobVec, SparseSet},
};
use alloc::string::String;
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
use core::{cell::UnsafeCell, mem::ManuallyDrop, panic::Location};
#[cfg(feature = "std")]
use std::thread::ThreadId;
/// The type-erased backing storage and metadata for a single resource within a [`World`].
///
/// If `SEND` is false, values of this type will panic if dropped from a different thread.
///
/// [`World`]: crate::world::World
pub struct ResourceData<const SEND: bool> {
data: ManuallyDrop<BlobVec>,
added_ticks: UnsafeCell<Tick>,
changed_ticks: UnsafeCell<Tick>,
#[cfg_attr(
not(feature = "std"),
expect(dead_code, reason = "currently only used with the std feature")
)]
type_name: String,
id: ArchetypeComponentId,
#[cfg(feature = "std")]
origin_thread_id: Option<ThreadId>,
changed_by: MaybeLocation<UnsafeCell<&'static Location<'static>>>,
}
impl<const SEND: bool> Drop for ResourceData<SEND> {
fn drop(&mut self) {
// For Non Send resources we need to validate that correct thread
// is dropping the resource. This validation is not needed in case
// of SEND resources. Or if there is no data.
if !SEND && self.is_present() {
// If this thread is already panicking, panicking again will cause
// the entire process to abort. In this case we choose to avoid
// dropping or checking this altogether and just leak the column.
#[cfg(feature = "std")]
if std::thread::panicking() {
return;
}
self.validate_access();
}
// SAFETY: Drop is only called once upon dropping the ResourceData
// and is inaccessible after this as the parent ResourceData has
// been dropped. The validate_access call above will check that the
// data is dropped on the thread it was inserted from.
unsafe {
ManuallyDrop::drop(&mut self.data);
}
}
}
impl<const SEND: bool> ResourceData<SEND> {
/// The only row in the underlying `BlobVec`.
const ROW: usize = 0;
/// Validates the access to `!Send` resources is only done on the thread they were created from.
///
/// # Panics
/// If `SEND` is false, this will panic if called from a different thread than the one it was inserted from.
#[inline]
fn validate_access(&self) {
if SEND {
return;
}
#[cfg(feature = "std")]
if self.origin_thread_id != Some(std::thread::current().id()) {
// Panic in tests, as testing for aborting is nearly impossible
panic!(
"Attempted to access or drop non-send resource {} from thread {:?} on a thread {:?}. This is not allowed. Aborting.",
self.type_name,
self.origin_thread_id,
std::thread::current().id()
);
}
// TODO: Handle no_std non-send.
// Currently, no_std is single-threaded only, so this is safe to ignore.
// To support no_std multithreading, an alternative will be required.
}
/// Returns true if the resource is populated.
#[inline]
pub fn is_present(&self) -> bool {
!self.data.is_empty()
}
/// Gets the [`ArchetypeComponentId`] for the resource.
#[inline]
pub fn id(&self) -> ArchetypeComponentId {
self.id
}
/// Returns a reference to the resource, if it exists.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
/// original thread it was inserted from.
#[inline]
pub fn get_data(&self) -> Option<Ptr<'_>> {
self.is_present().then(|| {
self.validate_access();
// SAFETY: We've already checked if a value is present, and there should only be one.
unsafe { self.data.get_unchecked(Self::ROW) }
})
}
/// Returns a reference to the resource's change ticks, if it exists.
#[inline]
pub fn get_ticks(&self) -> Option<ComponentTicks> {
// SAFETY: This is being fetched through a read-only reference to Self, so no other mutable references
// to the ticks can exist.
unsafe {
self.is_present().then(|| ComponentTicks {
added: self.added_ticks.read(),
changed: self.changed_ticks.read(),
})
}
}
/// Returns references to the resource and its change ticks, if it exists.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
/// original thread it was inserted in.
#[inline]
pub(crate) fn get_with_ticks(
&self,
) -> Option<(
Ptr<'_>,
TickCells<'_>,
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
)> {
self.is_present().then(|| {
self.validate_access();
(
// SAFETY: We've already checked if a value is present, and there should only be one.
unsafe { self.data.get_unchecked(Self::ROW) },
TickCells {
added: &self.added_ticks,
changed: &self.changed_ticks,
},
self.changed_by.as_ref(),
)
})
}
/// Returns a mutable reference to the resource, if it exists.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
/// original thread it was inserted in.
pub(crate) fn get_mut(&mut self, last_run: Tick, this_run: Tick) -> Option<MutUntyped<'_>> {
let (ptr, ticks, caller) = self.get_with_ticks()?;
Some(MutUntyped {
// SAFETY: We have exclusive access to the underlying storage.
value: unsafe { ptr.assert_unique() },
// SAFETY: We have exclusive access to the underlying storage.
ticks: unsafe { TicksMut::from_tick_cells(ticks, last_run, this_run) },
// SAFETY: We have exclusive access to the underlying storage.
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
})
}
/// Inserts a value into the resource. If a value is already present
/// it will be replaced.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not replaced from
/// the original thread it was inserted in.
///
/// # Safety
/// - `value` must be valid for the underlying type for the resource.
#[inline]
pub(crate) unsafe fn insert(
&mut self,
value: OwningPtr<'_>,
change_tick: Tick,
caller: MaybeLocation,
) {
if self.is_present() {
self.validate_access();
// SAFETY: The caller ensures that the provided value is valid for the underlying type and
// is properly initialized. We've ensured that a value is already present and previously
// initialized.
unsafe {
self.data.replace_unchecked(Self::ROW, value);
}
} else {
#[cfg(feature = "std")]
if !SEND {
self.origin_thread_id = Some(std::thread::current().id());
}
self.data.push(value);
*self.added_ticks.deref_mut() = change_tick;
}
*self.changed_ticks.deref_mut() = change_tick;
self.changed_by
.as_ref()
.map(|changed_by| changed_by.deref_mut())
.assign(caller);
}
/// Inserts a value into the resource with a pre-existing change tick. If a
/// value is already present it will be replaced.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not replaced from
/// the original thread it was inserted in.
///
/// # Safety
/// - `value` must be valid for the underlying type for the resource.
#[inline]
pub(crate) unsafe fn insert_with_ticks(
&mut self,
value: OwningPtr<'_>,
change_ticks: ComponentTicks,
caller: MaybeLocation,
) {
if self.is_present() {
self.validate_access();
// SAFETY: The caller ensures that the provided value is valid for the underlying type and
// is properly initialized. We've ensured that a value is already present and previously
// initialized.
unsafe {
self.data.replace_unchecked(Self::ROW, value);
}
} else {
#[cfg(feature = "std")]
if !SEND {
self.origin_thread_id = Some(std::thread::current().id());
}
self.data.push(value);
}
*self.added_ticks.deref_mut() = change_ticks.added;
*self.changed_ticks.deref_mut() = change_ticks.changed;
self.changed_by
.as_ref()
.map(|changed_by| changed_by.deref_mut())
.assign(caller);
}
/// Removes a value from the resource, if present.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not removed from the
/// original thread it was inserted from.
#[inline]
#[must_use = "The returned pointer to the removed component should be used or dropped"]
pub(crate) fn remove(&mut self) -> Option<(OwningPtr<'_>, ComponentTicks, MaybeLocation)> {
if !self.is_present() {
return None;
}
if !SEND {
self.validate_access();
}
// SAFETY: We've already validated that the row is present.
let res = unsafe { self.data.swap_remove_and_forget_unchecked(Self::ROW) };
let caller = self
.changed_by
.as_ref()
// SAFETY: This function is being called through an exclusive mutable reference to Self
.map(|changed_by| unsafe { *changed_by.deref_mut() });
// SAFETY: This function is being called through an exclusive mutable reference to Self, which
// makes it sound to read these ticks.
unsafe {
Some((
res,
ComponentTicks {
added: self.added_ticks.read(),
changed: self.changed_ticks.read(),
},
caller,
))
}
}
/// Removes a value from the resource, if present, and drops it.
///
/// # Panics
/// If `SEND` is false, this will panic if a value is present and is not
/// accessed from the original thread it was inserted in.
#[inline]
pub(crate) fn remove_and_drop(&mut self) {
if self.is_present() {
self.validate_access();
self.data.clear();
}
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
self.added_ticks.get_mut().check_tick(change_tick);
self.changed_ticks.get_mut().check_tick(change_tick);
}
}
/// The backing store for all [`Resource`]s stored in the [`World`].
///
/// [`Resource`]: crate::resource::Resource
/// [`World`]: crate::world::World
#[derive(Default)]
pub struct Resources<const SEND: bool> {
resources: SparseSet<ComponentId, ResourceData<SEND>>,
}
impl<const SEND: bool> Resources<SEND> {
/// The total number of resources stored in the [`World`]
///
/// [`World`]: crate::world::World
#[inline]
pub fn len(&self) -> usize {
self.resources.len()
}
/// Iterate over all resources that have been initialized, i.e. given a [`ComponentId`]
pub fn iter(&self) -> impl Iterator<Item = (ComponentId, &ResourceData<SEND>)> {
self.resources.iter().map(|(id, data)| (*id, data))
}
/// Returns true if there are no resources stored in the [`World`],
/// false otherwise.
///
/// [`World`]: crate::world::World
#[inline]
pub fn is_empty(&self) -> bool {
self.resources.is_empty()
}
/// Gets read-only access to a resource, if it exists.
#[inline]
pub fn get(&self, component_id: ComponentId) -> Option<&ResourceData<SEND>> {
self.resources.get(component_id)
}
/// Clears all resources.
#[inline]
pub fn clear(&mut self) {
self.resources.clear();
}
/// Gets mutable access to a resource, if it exists.
#[inline]
pub(crate) fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ResourceData<SEND>> {
self.resources.get_mut(component_id)
}
/// Fetches or initializes a new resource and returns back its underlying column.
///
/// # Panics
/// Will panic if `component_id` is not valid for the provided `components`
/// If `SEND` is true, this will panic if `component_id`'s `ComponentInfo` is not registered as being `Send` + `Sync`.
pub(crate) fn initialize_with(
&mut self,
component_id: ComponentId,
components: &Components,
f: impl FnOnce() -> ArchetypeComponentId,
) -> &mut ResourceData<SEND> {
self.resources.get_or_insert_with(component_id, || {
let component_info = components.get_info(component_id).unwrap();
if SEND {
assert!(
component_info.is_send_and_sync(),
"Send + Sync resource {} initialized as non_send. It may have been inserted via World::insert_non_send_resource by accident. Try using World::insert_resource instead.",
component_info.name(),
);
}
// SAFETY: component_info.drop() is valid for the types that will be inserted.
let data = unsafe {
BlobVec::new(
component_info.layout(),
component_info.drop(),
1
)
};
ResourceData {
data: ManuallyDrop::new(data),
added_ticks: UnsafeCell::new(Tick::new(0)),
changed_ticks: UnsafeCell::new(Tick::new(0)),
type_name: String::from(component_info.name()),
id: f(),
#[cfg(feature = "std")]
origin_thread_id: None,
changed_by: MaybeLocation::caller().map(UnsafeCell::new),
}
})
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
for info in self.resources.values_mut() {
info.check_change_ticks(change_tick);
}
}
}

View File

@@ -0,0 +1,756 @@
use crate::{
change_detection::MaybeLocation,
component::{ComponentId, ComponentInfo, ComponentTicks, Tick, TickCells},
entity::Entity,
storage::{Column, TableRow},
};
use alloc::{boxed::Box, vec::Vec};
use bevy_ptr::{OwningPtr, Ptr};
use core::{cell::UnsafeCell, hash::Hash, marker::PhantomData, panic::Location};
use nonmax::NonMaxUsize;
type EntityIndex = u32;
#[derive(Debug)]
pub(crate) struct SparseArray<I, V = I> {
values: Vec<Option<V>>,
marker: PhantomData<I>,
}
/// A space-optimized version of [`SparseArray`] that cannot be changed
/// after construction.
#[derive(Debug)]
pub(crate) struct ImmutableSparseArray<I, V = I> {
values: Box<[Option<V>]>,
marker: PhantomData<I>,
}
impl<I: SparseSetIndex, V> Default for SparseArray<I, V> {
fn default() -> Self {
Self::new()
}
}
impl<I, V> SparseArray<I, V> {
#[inline]
pub const fn new() -> Self {
Self {
values: Vec::new(),
marker: PhantomData,
}
}
}
macro_rules! impl_sparse_array {
($ty:ident) => {
impl<I: SparseSetIndex, V> $ty<I, V> {
/// Returns `true` if the collection contains a value for the specified `index`.
#[inline]
pub fn contains(&self, index: I) -> bool {
let index = index.sparse_set_index();
self.values.get(index).is_some_and(Option::is_some)
}
/// Returns a reference to the value at `index`.
///
/// Returns `None` if `index` does not have a value or if `index` is out of bounds.
#[inline]
pub fn get(&self, index: I) -> Option<&V> {
let index = index.sparse_set_index();
self.values.get(index).and_then(Option::as_ref)
}
}
};
}
impl_sparse_array!(SparseArray);
impl_sparse_array!(ImmutableSparseArray);
impl<I: SparseSetIndex, V> SparseArray<I, V> {
/// Inserts `value` at `index` in the array.
///
/// If `index` is out-of-bounds, this will enlarge the buffer to accommodate it.
#[inline]
pub fn insert(&mut self, index: I, value: V) {
let index = index.sparse_set_index();
if index >= self.values.len() {
self.values.resize_with(index + 1, || None);
}
self.values[index] = Some(value);
}
/// Returns a mutable reference to the value at `index`.
///
/// Returns `None` if `index` does not have a value or if `index` is out of bounds.
#[inline]
pub fn get_mut(&mut self, index: I) -> Option<&mut V> {
let index = index.sparse_set_index();
self.values.get_mut(index).and_then(Option::as_mut)
}
/// Removes and returns the value stored at `index`.
///
/// Returns `None` if `index` did not have a value or if `index` is out of bounds.
#[inline]
pub fn remove(&mut self, index: I) -> Option<V> {
let index = index.sparse_set_index();
self.values.get_mut(index).and_then(Option::take)
}
/// Removes all of the values stored within.
pub fn clear(&mut self) {
self.values.clear();
}
/// Converts the [`SparseArray`] into an immutable variant.
pub(crate) fn into_immutable(self) -> ImmutableSparseArray<I, V> {
ImmutableSparseArray {
values: self.values.into_boxed_slice(),
marker: PhantomData,
}
}
}
/// A sparse data structure of [`Component`](crate::component::Component)s.
///
/// Designed for relatively fast insertions and deletions.
#[derive(Debug)]
pub struct ComponentSparseSet {
dense: Column,
// Internally this only relies on the Entity index to keep track of where the component data is
// stored for entities that are alive. The generation is not required, but is stored
// in debug builds to validate that access is correct.
#[cfg(not(debug_assertions))]
entities: Vec<EntityIndex>,
#[cfg(debug_assertions)]
entities: Vec<Entity>,
sparse: SparseArray<EntityIndex, TableRow>,
}
impl ComponentSparseSet {
/// Creates a new [`ComponentSparseSet`] with a given component type layout and
/// initial `capacity`.
pub(crate) fn new(component_info: &ComponentInfo, capacity: usize) -> Self {
Self {
dense: Column::with_capacity(component_info, capacity),
entities: Vec::with_capacity(capacity),
sparse: Default::default(),
}
}
/// Removes all of the values stored within.
pub(crate) fn clear(&mut self) {
self.dense.clear();
self.entities.clear();
self.sparse.clear();
}
/// Returns the number of component values in the sparse set.
#[inline]
pub fn len(&self) -> usize {
self.dense.len()
}
/// Returns `true` if the sparse set contains no component values.
#[inline]
pub fn is_empty(&self) -> bool {
self.dense.len() == 0
}
/// Inserts the `entity` key and component `value` pair into this sparse
/// set.
///
/// # Safety
/// The `value` pointer must point to a valid address that matches the [`Layout`](std::alloc::Layout)
/// inside the [`ComponentInfo`] given when constructing this sparse set.
pub(crate) unsafe fn insert(
&mut self,
entity: Entity,
value: OwningPtr<'_>,
change_tick: Tick,
caller: MaybeLocation,
) {
if let Some(&dense_index) = self.sparse.get(entity.index()) {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
self.dense.replace(dense_index, value, change_tick, caller);
} else {
let dense_index = self.dense.len();
self.dense
.push(value, ComponentTicks::new(change_tick), caller);
self.sparse
.insert(entity.index(), TableRow::from_usize(dense_index));
#[cfg(debug_assertions)]
assert_eq!(self.entities.len(), dense_index);
#[cfg(not(debug_assertions))]
self.entities.push(entity.index());
#[cfg(debug_assertions)]
self.entities.push(entity);
}
}
/// Returns `true` if the sparse set has a component value for the provided `entity`.
#[inline]
pub fn contains(&self, entity: Entity) -> bool {
#[cfg(debug_assertions)]
{
if let Some(&dense_index) = self.sparse.get(entity.index()) {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
true
} else {
false
}
}
#[cfg(not(debug_assertions))]
self.sparse.contains(entity.index())
}
/// Returns a reference to the entity's component value.
///
/// Returns `None` if `entity` does not have a component in the sparse set.
#[inline]
pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
self.sparse.get(entity.index()).map(|&dense_index| {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { self.dense.get_data_unchecked(dense_index) }
})
}
/// Returns references to the entity's component value and its added and changed ticks.
///
/// Returns `None` if `entity` does not have a component in the sparse set.
#[inline]
pub fn get_with_ticks(
&self,
entity: Entity,
) -> Option<(
Ptr<'_>,
TickCells<'_>,
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
)> {
let dense_index = *self.sparse.get(entity.index())?;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe {
Some((
self.dense.get_data_unchecked(dense_index),
TickCells {
added: self.dense.get_added_tick_unchecked(dense_index),
changed: self.dense.get_changed_tick_unchecked(dense_index),
},
self.dense.get_changed_by_unchecked(dense_index),
))
}
}
/// Returns a reference to the "added" tick of the entity's component value.
///
/// Returns `None` if `entity` does not have a component in the sparse set.
#[inline]
pub fn get_added_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
let dense_index = *self.sparse.get(entity.index())?;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { Some(self.dense.get_added_tick_unchecked(dense_index)) }
}
/// Returns a reference to the "changed" tick of the entity's component value.
///
/// Returns `None` if `entity` does not have a component in the sparse set.
#[inline]
pub fn get_changed_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
let dense_index = *self.sparse.get(entity.index())?;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { Some(self.dense.get_changed_tick_unchecked(dense_index)) }
}
/// Returns a reference to the "added" and "changed" ticks of the entity's component value.
///
/// Returns `None` if `entity` does not have a component in the sparse set.
#[inline]
pub fn get_ticks(&self, entity: Entity) -> Option<ComponentTicks> {
let dense_index = *self.sparse.get(entity.index())?;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { Some(self.dense.get_ticks_unchecked(dense_index)) }
}
/// Returns a reference to the calling location that last changed the entity's component value.
///
/// Returns `None` if `entity` does not have a component in the sparse set.
#[inline]
pub fn get_changed_by(
&self,
entity: Entity,
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
MaybeLocation::new_with_flattened(|| {
let dense_index = *self.sparse.get(entity.index())?;
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { Some(self.dense.get_changed_by_unchecked(dense_index)) }
})
}
/// Returns the drop function for the component type stored in the sparse set,
/// or `None` if it doesn't need to be dropped.
#[inline]
pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
self.dense.get_drop()
}
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
/// it exists).
#[must_use = "The returned pointer must be used to drop the removed component."]
pub(crate) fn remove_and_forget(&mut self, entity: Entity) -> Option<OwningPtr<'_>> {
self.sparse.remove(entity.index()).map(|dense_index| {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
self.entities.swap_remove(dense_index.as_usize());
let is_last = dense_index.as_usize() == self.dense.len() - 1;
// 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) };
if !is_last {
let swapped_entity = self.entities[dense_index.as_usize()];
#[cfg(not(debug_assertions))]
let index = swapped_entity;
#[cfg(debug_assertions)]
let index = swapped_entity.index();
*self.sparse.get_mut(index).unwrap() = dense_index;
}
value
})
}
/// Removes (and drops) the entity's component value from the sparse set.
///
/// Returns `true` if `entity` had a component value in the sparse set.
pub(crate) fn remove(&mut self, entity: Entity) -> bool {
if let Some(dense_index) = self.sparse.remove(entity.index()) {
#[cfg(debug_assertions)]
assert_eq!(entity, self.entities[dense_index.as_usize()]);
self.entities.swap_remove(dense_index.as_usize());
let is_last = dense_index.as_usize() == self.dense.len() - 1;
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe {
self.dense.swap_remove_unchecked(dense_index);
}
if !is_last {
let swapped_entity = self.entities[dense_index.as_usize()];
#[cfg(not(debug_assertions))]
let index = swapped_entity;
#[cfg(debug_assertions)]
let index = swapped_entity.index();
*self.sparse.get_mut(index).unwrap() = dense_index;
}
true
} else {
false
}
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
self.dense.check_change_ticks(change_tick);
}
}
/// A data structure that blends dense and sparse storage
///
/// `I` is the type of the indices, while `V` is the type of data stored in the dense storage.
#[derive(Debug)]
pub struct SparseSet<I, V: 'static> {
dense: Vec<V>,
indices: Vec<I>,
sparse: SparseArray<I, NonMaxUsize>,
}
/// A space-optimized version of [`SparseSet`] that cannot be changed
/// after construction.
#[derive(Debug)]
pub(crate) struct ImmutableSparseSet<I, V: 'static> {
dense: Box<[V]>,
indices: Box<[I]>,
sparse: ImmutableSparseArray<I, NonMaxUsize>,
}
macro_rules! impl_sparse_set {
($ty:ident) => {
impl<I: SparseSetIndex, V> $ty<I, V> {
/// Returns the number of elements in the sparse set.
#[inline]
pub fn len(&self) -> usize {
self.dense.len()
}
/// Returns `true` if the sparse set contains a value for `index`.
#[inline]
pub fn contains(&self, index: I) -> bool {
self.sparse.contains(index)
}
/// Returns a reference to the value for `index`.
///
/// Returns `None` if `index` does not have a value in the sparse set.
pub fn get(&self, index: I) -> Option<&V> {
self.sparse.get(index).map(|dense_index| {
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { self.dense.get_unchecked(dense_index.get()) }
})
}
/// Returns a mutable reference to the value for `index`.
///
/// Returns `None` if `index` does not have a value in the sparse set.
pub fn get_mut(&mut self, index: I) -> Option<&mut V> {
let dense = &mut self.dense;
self.sparse.get(index).map(move |dense_index| {
// SAFETY: if the sparse index points to something in the dense vec, it exists
unsafe { dense.get_unchecked_mut(dense_index.get()) }
})
}
/// Returns an iterator visiting all keys (indices) in arbitrary order.
pub fn indices(&self) -> impl Iterator<Item = I> + Clone + '_ {
self.indices.iter().cloned()
}
/// Returns an iterator visiting all values in arbitrary order.
pub fn values(&self) -> impl Iterator<Item = &V> {
self.dense.iter()
}
/// Returns an iterator visiting all values mutably in arbitrary order.
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
self.dense.iter_mut()
}
/// Returns an iterator visiting all key-value pairs in arbitrary order, with references to the values.
pub fn iter(&self) -> impl Iterator<Item = (&I, &V)> {
self.indices.iter().zip(self.dense.iter())
}
/// Returns an iterator visiting all key-value pairs in arbitrary order, with mutable references to the values.
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&I, &mut V)> {
self.indices.iter().zip(self.dense.iter_mut())
}
}
};
}
impl_sparse_set!(SparseSet);
impl_sparse_set!(ImmutableSparseSet);
impl<I: SparseSetIndex, V> Default for SparseSet<I, V> {
fn default() -> Self {
Self::new()
}
}
impl<I, V> SparseSet<I, V> {
/// Creates a new [`SparseSet`].
pub const fn new() -> Self {
Self {
dense: Vec::new(),
indices: Vec::new(),
sparse: SparseArray::new(),
}
}
}
impl<I: SparseSetIndex, V> SparseSet<I, V> {
/// Creates a new [`SparseSet`] with a specified initial capacity.
pub fn with_capacity(capacity: usize) -> Self {
Self {
dense: Vec::with_capacity(capacity),
indices: Vec::with_capacity(capacity),
sparse: Default::default(),
}
}
/// Returns the total number of elements the [`SparseSet`] can hold without needing to reallocate.
#[inline]
pub fn capacity(&self) -> usize {
self.dense.capacity()
}
/// Inserts `value` at `index`.
///
/// If a value was already present at `index`, it will be overwritten.
pub fn insert(&mut self, index: I, value: V) {
if let Some(dense_index) = self.sparse.get(index.clone()).cloned() {
// SAFETY: dense indices stored in self.sparse always exist
unsafe {
*self.dense.get_unchecked_mut(dense_index.get()) = value;
}
} else {
self.sparse
.insert(index.clone(), NonMaxUsize::new(self.dense.len()).unwrap());
self.indices.push(index);
self.dense.push(value);
}
}
/// Returns a reference to the value for `index`, inserting one computed from `func`
/// if not already present.
pub fn get_or_insert_with(&mut self, index: I, func: impl FnOnce() -> V) -> &mut V {
if let Some(dense_index) = self.sparse.get(index.clone()).cloned() {
// SAFETY: dense indices stored in self.sparse always exist
unsafe { self.dense.get_unchecked_mut(dense_index.get()) }
} else {
let value = func();
let dense_index = self.dense.len();
self.sparse
.insert(index.clone(), NonMaxUsize::new(dense_index).unwrap());
self.indices.push(index);
self.dense.push(value);
// SAFETY: dense index was just populated above
unsafe { self.dense.get_unchecked_mut(dense_index) }
}
}
/// Returns `true` if the sparse set contains no elements.
#[inline]
pub fn is_empty(&self) -> bool {
self.dense.len() == 0
}
/// Removes and returns the value for `index`.
///
/// Returns `None` if `index` does not have a value in the sparse set.
pub fn remove(&mut self, index: I) -> Option<V> {
self.sparse.remove(index).map(|dense_index| {
let index = dense_index.get();
let is_last = index == self.dense.len() - 1;
let value = self.dense.swap_remove(index);
self.indices.swap_remove(index);
if !is_last {
let swapped_index = self.indices[index].clone();
*self.sparse.get_mut(swapped_index).unwrap() = dense_index;
}
value
})
}
/// Clears all of the elements from the sparse set.
pub fn clear(&mut self) {
self.dense.clear();
self.indices.clear();
self.sparse.clear();
}
/// Converts the sparse set into its immutable variant.
pub(crate) fn into_immutable(self) -> ImmutableSparseSet<I, V> {
ImmutableSparseSet {
dense: self.dense.into_boxed_slice(),
indices: self.indices.into_boxed_slice(),
sparse: self.sparse.into_immutable(),
}
}
}
/// Represents something that can be stored in a [`SparseSet`] as an integer.
///
/// Ideally, the `usize` values should be very small (ie: incremented starting from
/// zero), as the number of bits needed to represent a `SparseSetIndex` in a `FixedBitSet`
/// is proportional to the **value** of those `usize`.
pub trait SparseSetIndex: Clone + PartialEq + Eq + Hash {
/// Gets the sparse set index corresponding to this instance.
fn sparse_set_index(&self) -> usize;
/// Creates a new instance of this type with the specified index.
fn get_sparse_set_index(value: usize) -> Self;
}
macro_rules! impl_sparse_set_index {
($($ty:ty),+) => {
$(impl SparseSetIndex for $ty {
#[inline]
fn sparse_set_index(&self) -> usize {
*self as usize
}
#[inline]
fn get_sparse_set_index(value: usize) -> Self {
value as $ty
}
})*
};
}
impl_sparse_set_index!(u8, u16, u32, u64, usize);
/// A collection of [`ComponentSparseSet`] storages, indexed by [`ComponentId`]
///
/// Can be accessed via [`Storages`](crate::storage::Storages)
#[derive(Default)]
pub struct SparseSets {
sets: SparseSet<ComponentId, ComponentSparseSet>,
}
impl SparseSets {
/// Returns the number of [`ComponentSparseSet`]s this collection contains.
#[inline]
pub fn len(&self) -> usize {
self.sets.len()
}
/// Returns true if this collection contains no [`ComponentSparseSet`]s.
#[inline]
pub fn is_empty(&self) -> bool {
self.sets.is_empty()
}
/// An Iterator visiting all ([`ComponentId`], [`ComponentSparseSet`]) pairs.
/// NOTE: Order is not guaranteed.
pub fn iter(&self) -> impl Iterator<Item = (ComponentId, &ComponentSparseSet)> {
self.sets.iter().map(|(id, data)| (*id, data))
}
/// Gets a reference to the [`ComponentSparseSet`] of a [`ComponentId`]. This may be `None` if the component has never been spawned.
#[inline]
pub fn get(&self, component_id: ComponentId) -> Option<&ComponentSparseSet> {
self.sets.get(component_id)
}
/// Gets a mutable reference of [`ComponentSparseSet`] of a [`ComponentInfo`].
/// Create a new [`ComponentSparseSet`] if not exists.
pub(crate) fn get_or_insert(
&mut self,
component_info: &ComponentInfo,
) -> &mut ComponentSparseSet {
if !self.sets.contains(component_info.id()) {
self.sets.insert(
component_info.id(),
ComponentSparseSet::new(component_info, 64),
);
}
self.sets.get_mut(component_info.id()).unwrap()
}
/// Gets a mutable reference to the [`ComponentSparseSet`] of a [`ComponentId`]. This may be `None` if the component has never been spawned.
pub(crate) fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ComponentSparseSet> {
self.sets.get_mut(component_id)
}
/// Clear entities stored in each [`ComponentSparseSet`]
pub(crate) fn clear_entities(&mut self) {
for set in self.sets.values_mut() {
set.clear();
}
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
for set in self.sets.values_mut() {
set.check_change_ticks(change_tick);
}
}
}
#[cfg(test)]
mod tests {
use super::SparseSets;
use crate::{
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo},
entity::Entity,
storage::SparseSet,
};
use alloc::{vec, vec::Vec};
#[derive(Debug, Eq, PartialEq)]
struct Foo(usize);
#[test]
fn sparse_set() {
let mut set = SparseSet::<Entity, Foo>::default();
let e0 = Entity::from_raw(0);
let e1 = Entity::from_raw(1);
let e2 = Entity::from_raw(2);
let e3 = Entity::from_raw(3);
let e4 = Entity::from_raw(4);
set.insert(e1, Foo(1));
set.insert(e2, Foo(2));
set.insert(e3, Foo(3));
assert_eq!(set.get(e0), None);
assert_eq!(set.get(e1), Some(&Foo(1)));
assert_eq!(set.get(e2), Some(&Foo(2)));
assert_eq!(set.get(e3), Some(&Foo(3)));
assert_eq!(set.get(e4), None);
{
let iter_results = set.values().collect::<Vec<_>>();
assert_eq!(iter_results, vec![&Foo(1), &Foo(2), &Foo(3)]);
}
assert_eq!(set.remove(e2), Some(Foo(2)));
assert_eq!(set.remove(e2), None);
assert_eq!(set.get(e0), None);
assert_eq!(set.get(e1), Some(&Foo(1)));
assert_eq!(set.get(e2), None);
assert_eq!(set.get(e3), Some(&Foo(3)));
assert_eq!(set.get(e4), None);
assert_eq!(set.remove(e1), Some(Foo(1)));
assert_eq!(set.get(e0), None);
assert_eq!(set.get(e1), None);
assert_eq!(set.get(e2), None);
assert_eq!(set.get(e3), Some(&Foo(3)));
assert_eq!(set.get(e4), None);
set.insert(e1, Foo(10));
assert_eq!(set.get(e1), Some(&Foo(10)));
*set.get_mut(e1).unwrap() = Foo(11);
assert_eq!(set.get(e1), Some(&Foo(11)));
}
#[test]
fn sparse_sets() {
let mut sets = SparseSets::default();
#[derive(Component, Default, Debug)]
struct TestComponent1;
#[derive(Component, Default, Debug)]
struct TestComponent2;
assert_eq!(sets.len(), 0);
assert!(sets.is_empty());
register_component::<TestComponent1>(&mut sets, 1);
assert_eq!(sets.len(), 1);
register_component::<TestComponent2>(&mut sets, 2);
assert_eq!(sets.len(), 2);
// check its shape by iter
let mut collected_sets = sets
.iter()
.map(|(id, set)| (id, set.len()))
.collect::<Vec<_>>();
collected_sets.sort();
assert_eq!(
collected_sets,
vec![(ComponentId::new(1), 0), (ComponentId::new(2), 0),]
);
fn register_component<T: Component>(sets: &mut SparseSets, id: usize) {
let descriptor = ComponentDescriptor::new::<T>();
let id = ComponentId::new(id);
let info = ComponentInfo::new(id, descriptor);
sets.get_or_insert(&info);
}
}
}

View File

@@ -0,0 +1,707 @@
use super::*;
use crate::{
change_detection::MaybeLocation,
component::TickCells,
storage::{blob_array::BlobArray, thin_array_ptr::ThinArrayPtr},
};
use alloc::vec::Vec;
use bevy_ptr::PtrMut;
use core::panic::Location;
/// Very similar to a normal [`Column`], but with the capacities and lengths cut out for performance reasons.
///
/// This type is used by [`Table`], because all of the capacities and lengths of the [`Table`]'s columns must match.
///
/// Like many other low-level storage types, [`ThinColumn`] has a limited and highly unsafe
/// interface. It's highly advised to use higher level types and their safe abstractions
/// instead of working directly with [`ThinColumn`].
pub struct ThinColumn {
pub(super) data: BlobArray,
pub(super) added_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
pub(super) changed_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
pub(super) changed_by: MaybeLocation<ThinArrayPtr<UnsafeCell<&'static Location<'static>>>>,
}
impl ThinColumn {
/// Create a new [`ThinColumn`] with the given `capacity`.
pub fn with_capacity(component_info: &ComponentInfo, capacity: usize) -> Self {
Self {
// SAFETY: The components stored in this columns will match the information in `component_info`
data: unsafe {
BlobArray::with_capacity(component_info.layout(), component_info.drop(), capacity)
},
added_ticks: ThinArrayPtr::with_capacity(capacity),
changed_ticks: ThinArrayPtr::with_capacity(capacity),
changed_by: MaybeLocation::new_with(|| ThinArrayPtr::with_capacity(capacity)),
}
}
/// Swap-remove and drop the removed element, but the component at `row` must not be the last element.
///
/// # Safety
/// - `row.as_usize()` < `len`
/// - `last_element_index` = `len - 1`
/// - `last_element_index` != `row.as_usize()`
/// - The caller should update the `len` to `len - 1`, or immediately initialize another element in the `last_element_index`
pub(crate) unsafe fn swap_remove_and_drop_unchecked_nonoverlapping(
&mut self,
last_element_index: usize,
row: TableRow,
) {
self.data
.swap_remove_and_drop_unchecked_nonoverlapping(row.as_usize(), last_element_index);
self.added_ticks
.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
self.changed_ticks
.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
self.changed_by.as_mut().map(|changed_by| {
changed_by.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
});
}
/// Swap-remove and drop the removed element.
///
/// # Safety
/// - `last_element_index` must be the index of the last element—stored in the highest place in memory.
/// - `row.as_usize()` <= `last_element_index`
/// - The caller should update the their saved length to reflect the change (decrement it by 1).
pub(crate) unsafe fn swap_remove_and_drop_unchecked(
&mut self,
last_element_index: usize,
row: TableRow,
) {
self.data
.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
self.added_ticks
.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
self.changed_ticks
.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
self.changed_by.as_mut().map(|changed_by| {
changed_by.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
});
}
/// Swap-remove and forget the removed element.
///
/// # Safety
/// - `last_element_index` must be the index of the last element—stored in the highest place in memory.
/// - `row.as_usize()` <= `last_element_index`
/// - The caller should update the their saved length to reflect the change (decrement it by 1).
pub(crate) unsafe fn swap_remove_and_forget_unchecked(
&mut self,
last_element_index: usize,
row: TableRow,
) {
let _ = self
.data
.swap_remove_unchecked(row.as_usize(), last_element_index);
self.added_ticks
.swap_remove_unchecked(row.as_usize(), last_element_index);
self.changed_ticks
.swap_remove_unchecked(row.as_usize(), last_element_index);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.swap_remove_unchecked(row.as_usize(), last_element_index));
}
/// Call [`realloc`](std::alloc::realloc) to expand / shrink the memory allocation for this [`ThinColumn`]
///
/// # Safety
/// - `current_capacity` must be the current capacity of this column (the capacity of `self.data`, `self.added_ticks`, `self.changed_tick`)
/// - The caller should make sure their saved `capacity` value is updated to `new_capacity` after this operation.
pub(crate) unsafe fn realloc(
&mut self,
current_capacity: NonZeroUsize,
new_capacity: NonZeroUsize,
) {
self.data.realloc(current_capacity, new_capacity);
self.added_ticks.realloc(current_capacity, new_capacity);
self.changed_ticks.realloc(current_capacity, new_capacity);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.realloc(current_capacity, new_capacity));
}
/// Call [`alloc`](std::alloc::alloc) to allocate memory for this [`ThinColumn`]
/// The caller should make sure their saved `capacity` value is updated to `new_capacity` after this operation.
pub(crate) fn alloc(&mut self, new_capacity: NonZeroUsize) {
self.data.alloc(new_capacity);
self.added_ticks.alloc(new_capacity);
self.changed_ticks.alloc(new_capacity);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.alloc(new_capacity));
}
/// Writes component data to the column at the given row.
/// Assumes the slot is uninitialized, drop is not called.
/// To overwrite existing initialized value, use [`Self::replace`] instead.
///
/// # Safety
/// - `row.as_usize()` must be in bounds.
/// - `comp_ptr` holds a component that matches the `component_id`
#[inline]
pub(crate) unsafe fn initialize(
&mut self,
row: TableRow,
data: OwningPtr<'_>,
tick: Tick,
caller: MaybeLocation,
) {
self.data.initialize_unchecked(row.as_usize(), data);
*self.added_ticks.get_unchecked_mut(row.as_usize()).get_mut() = tick;
*self
.changed_ticks
.get_unchecked_mut(row.as_usize())
.get_mut() = tick;
self.changed_by
.as_mut()
.map(|changed_by| changed_by.get_unchecked_mut(row.as_usize()).get_mut())
.assign(caller);
}
/// Writes component data to the column at given row. Assumes the slot is initialized, drops the previous value.
///
/// # Safety
/// - `row.as_usize()` must be in bounds.
/// - `data` holds a component that matches the `component_id`
#[inline]
pub(crate) unsafe fn replace(
&mut self,
row: TableRow,
data: OwningPtr<'_>,
change_tick: Tick,
caller: MaybeLocation,
) {
self.data.replace_unchecked(row.as_usize(), data);
*self
.changed_ticks
.get_unchecked_mut(row.as_usize())
.get_mut() = change_tick;
self.changed_by
.as_mut()
.map(|changed_by| changed_by.get_unchecked_mut(row.as_usize()).get_mut())
.assign(caller);
}
/// Removes the element from `other` at `src_row` and inserts it
/// into the current column to initialize the values at `dst_row`.
/// Does not do any bounds checking.
///
/// # Safety
/// - `other` must have the same data layout as `self`
/// - `src_row` must be in bounds for `other`
/// - `dst_row` must be in bounds for `self`
/// - `other[src_row]` must be initialized to a valid value.
/// - `self[dst_row]` must not be initialized yet.
#[inline]
pub(crate) unsafe fn initialize_from_unchecked(
&mut self,
other: &mut ThinColumn,
other_last_element_index: usize,
src_row: TableRow,
dst_row: TableRow,
) {
debug_assert!(self.data.layout() == other.data.layout());
// Init the data
let src_val = other
.data
.swap_remove_unchecked(src_row.as_usize(), other_last_element_index);
self.data.initialize_unchecked(dst_row.as_usize(), src_val);
// Init added_ticks
let added_tick = other
.added_ticks
.swap_remove_unchecked(src_row.as_usize(), other_last_element_index);
self.added_ticks
.initialize_unchecked(dst_row.as_usize(), added_tick);
// Init changed_ticks
let changed_tick = other
.changed_ticks
.swap_remove_unchecked(src_row.as_usize(), other_last_element_index);
self.changed_ticks
.initialize_unchecked(dst_row.as_usize(), changed_tick);
self.changed_by.as_mut().zip(other.changed_by.as_mut()).map(
|(self_changed_by, other_changed_by)| {
let changed_by = other_changed_by
.swap_remove_unchecked(src_row.as_usize(), other_last_element_index);
self_changed_by.initialize_unchecked(dst_row.as_usize(), changed_by);
},
);
}
/// Call [`Tick::check_tick`] on all of the ticks stored in this column.
///
/// # Safety
/// `len` is the actual length of this column
#[inline]
pub(crate) unsafe fn check_change_ticks(&mut self, len: usize, change_tick: Tick) {
for i in 0..len {
// SAFETY:
// - `i` < `len`
// we have a mutable reference to `self`
unsafe { self.added_ticks.get_unchecked_mut(i) }
.get_mut()
.check_tick(change_tick);
// SAFETY:
// - `i` < `len`
// we have a mutable reference to `self`
unsafe { self.changed_ticks.get_unchecked_mut(i) }
.get_mut()
.check_tick(change_tick);
}
}
/// Clear all the components from this column.
///
/// # Safety
/// - `len` must match the actual length of the column
/// - The caller must not use the elements this column's data until [`initializing`](Self::initialize) it again (set `len` to 0).
pub(crate) unsafe fn clear(&mut self, len: usize) {
self.added_ticks.clear_elements(len);
self.changed_ticks.clear_elements(len);
self.data.clear(len);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.clear_elements(len));
}
/// Because this method needs parameters, it can't be the implementation of the `Drop` trait.
/// The owner of this [`ThinColumn`] must call this method with the correct information.
///
/// # Safety
/// - `len` is indeed the length of the column
/// - `cap` is indeed the capacity of the column
/// - the data stored in `self` will never be used again
pub(crate) unsafe fn drop(&mut self, cap: usize, len: usize) {
self.added_ticks.drop(cap, len);
self.changed_ticks.drop(cap, len);
self.data.drop(cap, len);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.drop(cap, len));
}
/// Drops the last component in this column.
///
/// # Safety
/// - `last_element_index` is indeed the index of the last element
/// - the data stored in `last_element_index` will never be used unless properly initialized again.
pub(crate) unsafe fn drop_last_component(&mut self, last_element_index: usize) {
core::ptr::drop_in_place(self.added_ticks.get_unchecked_raw(last_element_index));
core::ptr::drop_in_place(self.changed_ticks.get_unchecked_raw(last_element_index));
self.changed_by.as_mut().map(|changed_by| {
core::ptr::drop_in_place(changed_by.get_unchecked_raw(last_element_index));
});
self.data.drop_last_element(last_element_index);
}
/// Get a slice to the data stored in this [`ThinColumn`].
///
/// # Safety
/// - `T` must match the type of data that's stored in this [`ThinColumn`]
/// - `len` must match the actual length of this column (number of elements stored)
pub unsafe fn get_data_slice<T>(&self, len: usize) -> &[UnsafeCell<T>] {
self.data.get_sub_slice(len)
}
/// Get a slice to the added [`ticks`](Tick) in this [`ThinColumn`].
///
/// # Safety
/// - `len` must match the actual length of this column (number of elements stored)
pub unsafe fn get_added_ticks_slice(&self, len: usize) -> &[UnsafeCell<Tick>] {
self.added_ticks.as_slice(len)
}
/// Get a slice to the changed [`ticks`](Tick) in this [`ThinColumn`].
///
/// # Safety
/// - `len` must match the actual length of this column (number of elements stored)
pub unsafe fn get_changed_ticks_slice(&self, len: usize) -> &[UnsafeCell<Tick>] {
self.changed_ticks.as_slice(len)
}
/// Get a slice to the calling locations that last changed each value in this [`ThinColumn`]
///
/// # Safety
/// - `len` must match the actual length of this column (number of elements stored)
pub unsafe fn get_changed_by_slice(
&self,
len: usize,
) -> MaybeLocation<&[UnsafeCell<&'static Location<'static>>]> {
self.changed_by
.as_ref()
.map(|changed_by| changed_by.as_slice(len))
}
}
/// A type-erased contiguous container for data of a homogeneous type.
///
/// Conceptually, a [`Column`] is very similar to a type-erased `Vec<T>`.
/// It also stores the change detection ticks for its components, kept in two separate
/// contiguous buffers internally. An element shares its data across these buffers by using the
/// same index (i.e. the entity at row 3 has it's data at index 3 and its change detection ticks at index 3).
///
/// Like many other low-level storage types, [`Column`] has a limited and highly unsafe
/// interface. It's highly advised to use higher level types and their safe abstractions
/// instead of working directly with [`Column`].
#[derive(Debug)]
pub struct Column {
pub(super) data: BlobVec,
pub(super) added_ticks: Vec<UnsafeCell<Tick>>,
pub(super) changed_ticks: Vec<UnsafeCell<Tick>>,
changed_by: MaybeLocation<Vec<UnsafeCell<&'static Location<'static>>>>,
}
impl Column {
/// Constructs a new [`Column`], configured with a component's layout and an initial `capacity`.
#[inline]
pub(crate) fn with_capacity(component_info: &ComponentInfo, capacity: usize) -> Self {
Column {
// SAFETY: component_info.drop() is valid for the types that will be inserted.
data: unsafe { BlobVec::new(component_info.layout(), component_info.drop(), capacity) },
added_ticks: Vec::with_capacity(capacity),
changed_ticks: Vec::with_capacity(capacity),
changed_by: MaybeLocation::new_with(|| Vec::with_capacity(capacity)),
}
}
/// Fetches the [`Layout`] for the underlying type.
#[inline]
pub fn item_layout(&self) -> Layout {
self.data.layout()
}
/// Writes component data to the column at given row.
/// Assumes the slot is initialized, calls drop.
///
/// # Safety
/// Assumes data has already been allocated for the given row.
#[inline]
pub(crate) unsafe fn replace(
&mut self,
row: TableRow,
data: OwningPtr<'_>,
change_tick: Tick,
caller: MaybeLocation,
) {
debug_assert!(row.as_usize() < self.len());
self.data.replace_unchecked(row.as_usize(), data);
*self
.changed_ticks
.get_unchecked_mut(row.as_usize())
.get_mut() = change_tick;
self.changed_by
.as_mut()
.map(|changed_by| changed_by.get_unchecked_mut(row.as_usize()).get_mut())
.assign(caller);
}
/// Gets the current number of elements stored in the column.
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
/// Checks if the column is empty. Returns `true` if there are no elements, `false` otherwise.
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
/// Removes an element from the [`Column`].
///
/// - The value will be dropped if it implements [`Drop`].
/// - This does not preserve ordering, but is O(1).
/// - This does not do any bounds checking.
/// - The element is replaced with the last element in the [`Column`].
///
/// # Safety
/// `row` must be within the range `[0, self.len())`.
#[inline]
pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) {
self.data.swap_remove_and_drop_unchecked(row.as_usize());
self.added_ticks.swap_remove(row.as_usize());
self.changed_ticks.swap_remove(row.as_usize());
self.changed_by
.as_mut()
.map(|changed_by| changed_by.swap_remove(row.as_usize()));
}
/// Removes an element from the [`Column`] and returns it and its change detection ticks.
/// This does not preserve ordering, but is O(1) and does not do any bounds checking.
///
/// The element is replaced with the last element in the [`Column`].
///
/// It's the caller's responsibility to ensure that the removed value is dropped or used.
/// Failure to do so may result in resources not being released (i.e. files handles not being
/// released, memory leaks, etc.)
///
/// # Safety
/// `row` must be within the range `[0, self.len())`.
#[inline]
#[must_use = "The returned pointer should be used to dropped the removed component"]
pub(crate) unsafe fn swap_remove_and_forget_unchecked(
&mut self,
row: TableRow,
) -> (OwningPtr<'_>, ComponentTicks, MaybeLocation) {
let data = self.data.swap_remove_and_forget_unchecked(row.as_usize());
let added = self.added_ticks.swap_remove(row.as_usize()).into_inner();
let changed = self.changed_ticks.swap_remove(row.as_usize()).into_inner();
let caller = self
.changed_by
.as_mut()
.map(|changed_by| changed_by.swap_remove(row.as_usize()).into_inner());
(data, ComponentTicks { added, changed }, caller)
}
/// Pushes a new value onto the end of the [`Column`].
///
/// # Safety
/// `ptr` must point to valid data of this column's component type
pub(crate) unsafe fn push(
&mut self,
ptr: OwningPtr<'_>,
ticks: ComponentTicks,
caller: MaybeLocation,
) {
self.data.push(ptr);
self.added_ticks.push(UnsafeCell::new(ticks.added));
self.changed_ticks.push(UnsafeCell::new(ticks.changed));
self.changed_by
.as_mut()
.zip(caller)
.map(|(changed_by, caller)| changed_by.push(UnsafeCell::new(caller)));
}
/// Fetches the data pointer to the first element of the [`Column`].
///
/// The pointer is type erased, so using this function to fetch anything
/// other than the first element will require computing the offset using
/// [`Column::item_layout`].
#[inline]
pub fn get_data_ptr(&self) -> Ptr<'_> {
self.data.get_ptr()
}
/// Fetches the slice to the [`Column`]'s data cast to a given type.
///
/// Note: The values stored within are [`UnsafeCell`].
/// Users of this API must ensure that accesses to each individual element
/// adhere to the safety invariants of [`UnsafeCell`].
///
/// # Safety
/// The type `T` must be the type of the items in this column.
pub unsafe fn get_data_slice<T>(&self) -> &[UnsafeCell<T>] {
self.data.get_slice()
}
/// Fetches the slice to the [`Column`]'s "added" change detection ticks.
///
/// Note: The values stored within are [`UnsafeCell`].
/// Users of this API must ensure that accesses to each individual element
/// adhere to the safety invariants of [`UnsafeCell`].
#[inline]
pub fn get_added_ticks_slice(&self) -> &[UnsafeCell<Tick>] {
&self.added_ticks
}
/// Fetches the slice to the [`Column`]'s "changed" change detection ticks.
///
/// Note: The values stored within are [`UnsafeCell`].
/// Users of this API must ensure that accesses to each individual element
/// adhere to the safety invariants of [`UnsafeCell`].
#[inline]
pub fn get_changed_ticks_slice(&self) -> &[UnsafeCell<Tick>] {
&self.changed_ticks
}
/// Fetches a reference to the data and change detection ticks at `row`.
///
/// Returns `None` if `row` is out of bounds.
#[inline]
pub fn get(&self, row: TableRow) -> Option<(Ptr<'_>, TickCells<'_>)> {
(row.as_usize() < self.data.len())
// SAFETY: The row is length checked before fetching the pointer. This is being
// accessed through a read-only reference to the column.
.then(|| unsafe {
(
self.data.get_unchecked(row.as_usize()),
TickCells {
added: self.added_ticks.get_unchecked(row.as_usize()),
changed: self.changed_ticks.get_unchecked(row.as_usize()),
},
)
})
}
/// Fetches a read-only reference to the data at `row`.
///
/// Returns `None` if `row` is out of bounds.
#[inline]
pub fn get_data(&self, row: TableRow) -> Option<Ptr<'_>> {
(row.as_usize() < self.data.len()).then(|| {
// SAFETY: The row is length checked before fetching the pointer. This is being
// accessed through a read-only reference to the column.
unsafe { self.data.get_unchecked(row.as_usize()) }
})
}
/// Fetches a read-only reference to the data at `row`. Unlike [`Column::get`] this does not
/// do any bounds checking.
///
/// # Safety
/// - `row` must be within the range `[0, self.len())`.
/// - no other mutable reference to the data of the same row can exist at the same time
#[inline]
pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
debug_assert!(row.as_usize() < self.data.len());
self.data.get_unchecked(row.as_usize())
}
/// Fetches a mutable reference to the data at `row`.
///
/// Returns `None` if `row` is out of bounds.
#[inline]
pub fn get_data_mut(&mut self, row: TableRow) -> Option<PtrMut<'_>> {
(row.as_usize() < self.data.len()).then(|| {
// SAFETY: The row is length checked before fetching the pointer. This is being
// accessed through an exclusive reference to the column.
unsafe { self.data.get_unchecked_mut(row.as_usize()) }
})
}
/// Fetches the "added" change detection tick for the value at `row`.
///
/// Returns `None` if `row` is out of bounds.
///
/// Note: The values stored within are [`UnsafeCell`].
/// Users of this API must ensure that accesses to each individual element
/// adhere to the safety invariants of [`UnsafeCell`].
#[inline]
pub fn get_added_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
self.added_ticks.get(row.as_usize())
}
/// Fetches the "changed" change detection tick for the value at `row`.
///
/// Returns `None` if `row` is out of bounds.
///
/// Note: The values stored within are [`UnsafeCell`].
/// Users of this API must ensure that accesses to each individual element
/// adhere to the safety invariants of [`UnsafeCell`].
#[inline]
pub fn get_changed_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
self.changed_ticks.get(row.as_usize())
}
/// Fetches the change detection ticks for the value at `row`.
///
/// Returns `None` if `row` is out of bounds.
#[inline]
pub fn get_ticks(&self, row: TableRow) -> Option<ComponentTicks> {
if row.as_usize() < self.data.len() {
// SAFETY: The size of the column has already been checked.
Some(unsafe { self.get_ticks_unchecked(row) })
} else {
None
}
}
/// Fetches the "added" change detection tick for the value at `row`. Unlike [`Column::get_added_tick`]
/// this function does not do any bounds checking.
///
/// # Safety
/// `row` must be within the range `[0, self.len())`.
#[inline]
pub unsafe fn get_added_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
debug_assert!(row.as_usize() < self.added_ticks.len());
self.added_ticks.get_unchecked(row.as_usize())
}
/// Fetches the "changed" change detection tick for the value at `row`. Unlike [`Column::get_changed_tick`]
/// this function does not do any bounds checking.
///
/// # Safety
/// `row` must be within the range `[0, self.len())`.
#[inline]
pub unsafe fn get_changed_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
debug_assert!(row.as_usize() < self.changed_ticks.len());
self.changed_ticks.get_unchecked(row.as_usize())
}
/// Fetches the change detection ticks for the value at `row`. Unlike [`Column::get_ticks`]
/// this function does not do any bounds checking.
///
/// # Safety
/// `row` must be within the range `[0, self.len())`.
#[inline]
pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
debug_assert!(row.as_usize() < self.added_ticks.len());
debug_assert!(row.as_usize() < self.changed_ticks.len());
ComponentTicks {
added: self.added_ticks.get_unchecked(row.as_usize()).read(),
changed: self.changed_ticks.get_unchecked(row.as_usize()).read(),
}
}
/// Clears the column, removing all values.
///
/// Note that this function has no effect on the allocated capacity of the [`Column`]>
pub fn clear(&mut self) {
self.data.clear();
self.added_ticks.clear();
self.changed_ticks.clear();
self.changed_by.as_mut().map(Vec::clear);
}
#[inline]
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
for component_ticks in &mut self.added_ticks {
component_ticks.get_mut().check_tick(change_tick);
}
for component_ticks in &mut self.changed_ticks {
component_ticks.get_mut().check_tick(change_tick);
}
}
/// Fetches the calling location that last changed the value at `row`.
///
/// Returns `None` if `row` is out of bounds.
///
/// Note: The values stored within are [`UnsafeCell`].
/// Users of this API must ensure that accesses to each individual element
/// adhere to the safety invariants of [`UnsafeCell`].
#[inline]
pub fn get_changed_by(
&self,
row: TableRow,
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
self.changed_by
.as_ref()
.map(|changed_by| changed_by.get(row.as_usize()))
}
/// Fetches the calling location that last changed the value at `row`.
///
/// Unlike [`Column::get_changed_by`] this function does not do any bounds checking.
///
/// # Safety
/// `row` must be within the range `[0, self.len())`.
#[inline]
pub unsafe fn get_changed_by_unchecked(
&self,
row: TableRow,
) -> MaybeLocation<&UnsafeCell<&'static Location<'static>>> {
self.changed_by.as_ref().map(|changed_by| {
debug_assert!(row.as_usize() < changed_by.len());
changed_by.get_unchecked(row.as_usize())
})
}
/// Returns the drop function for elements of the column,
/// or `None` if they don't need to be dropped.
#[inline]
pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
self.data.get_drop()
}
}

879
vendor/bevy_ecs/src/storage/table/mod.rs vendored Normal file
View File

@@ -0,0 +1,879 @@
use crate::{
change_detection::MaybeLocation,
component::{ComponentId, ComponentInfo, ComponentTicks, Components, Tick},
entity::Entity,
query::DebugCheckedUnwrap,
storage::{blob_vec::BlobVec, ImmutableSparseSet, SparseSet},
};
use alloc::{boxed::Box, vec, vec::Vec};
use bevy_platform::collections::HashMap;
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
pub use column::*;
use core::{
alloc::Layout,
cell::UnsafeCell,
num::NonZeroUsize,
ops::{Index, IndexMut},
panic::Location,
};
mod column;
/// An opaque unique ID for a [`Table`] within a [`World`].
///
/// Can be used with [`Tables::get`] to fetch the corresponding
/// table.
///
/// Each [`Archetype`] always points to a table via [`Archetype::table_id`].
/// Multiple archetypes can point to the same table so long as the components
/// stored in the table are identical, but do not share the same sparse set
/// components.
///
/// [`World`]: crate::world::World
/// [`Archetype`]: crate::archetype::Archetype
/// [`Archetype::table_id`]: crate::archetype::Archetype::table_id
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TableId(u32);
impl TableId {
pub(crate) const INVALID: TableId = TableId(u32::MAX);
/// Creates a new [`TableId`].
///
/// `index` *must* be retrieved from calling [`TableId::as_u32`] on a `TableId` you got
/// from a table of a given [`World`] or the created ID may be invalid.
///
/// [`World`]: crate::world::World
#[inline]
pub const fn from_u32(index: u32) -> Self {
Self(index)
}
/// Creates a new [`TableId`].
///
/// `index` *must* be retrieved from calling [`TableId::as_usize`] on a `TableId` you got
/// from a table of a given [`World`] or the created ID may be invalid.
///
/// [`World`]: crate::world::World
///
/// # Panics
///
/// Will panic if the provided value does not fit within a [`u32`].
#[inline]
pub const fn from_usize(index: usize) -> Self {
debug_assert!(index as u32 as usize == index);
Self(index as u32)
}
/// Gets the underlying table index from the ID.
#[inline]
pub const fn as_u32(self) -> u32 {
self.0
}
/// Gets the underlying table index from the ID.
#[inline]
pub const fn as_usize(self) -> usize {
// usize is at least u32 in Bevy
self.0 as usize
}
/// The [`TableId`] of the [`Table`] without any components.
#[inline]
pub const fn empty() -> Self {
Self(0)
}
}
/// An opaque newtype for rows in [`Table`]s. Specifies a single row in a specific table.
///
/// Values of this type are retrievable from [`Archetype::entity_table_row`] and can be
/// used alongside [`Archetype::table_id`] to fetch the exact table and row where an
/// [`Entity`]'s components are stored.
///
/// Values of this type are only valid so long as entities have not moved around.
/// Adding and removing components from an entity, or despawning it will invalidate
/// potentially any table row in the table the entity was previously stored in. Users
/// should *always* fetch the appropriate row from the entity's [`Archetype`] before
/// fetching the entity's components.
///
/// [`Archetype`]: crate::archetype::Archetype
/// [`Archetype::entity_table_row`]: crate::archetype::Archetype::entity_table_row
/// [`Archetype::table_id`]: crate::archetype::Archetype::table_id
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TableRow(u32);
impl TableRow {
pub(crate) const INVALID: TableRow = TableRow(u32::MAX);
/// Creates a `TableRow`.
#[inline]
pub const fn from_u32(index: u32) -> Self {
Self(index)
}
/// Creates a `TableRow` from a [`usize`] index.
///
/// # Panics
///
/// Will panic in debug mode if the provided value does not fit within a [`u32`].
#[inline]
pub const fn from_usize(index: usize) -> Self {
debug_assert!(index as u32 as usize == index);
Self(index as u32)
}
/// Gets the index of the row as a [`usize`].
#[inline]
pub const fn as_usize(self) -> usize {
// usize is at least u32 in Bevy
self.0 as usize
}
/// Gets the index of the row as a [`usize`].
#[inline]
pub const fn as_u32(self) -> u32 {
self.0
}
}
/// A builder type for constructing [`Table`]s.
///
/// - Use [`with_capacity`] to initialize the builder.
/// - Repeatedly call [`add_column`] to add columns for components.
/// - Finalize with [`build`] to get the constructed [`Table`].
///
/// [`with_capacity`]: Self::with_capacity
/// [`add_column`]: Self::add_column
/// [`build`]: Self::build
pub(crate) struct TableBuilder {
columns: SparseSet<ComponentId, ThinColumn>,
capacity: usize,
}
impl TableBuilder {
/// Start building a new [`Table`] with a specified `column_capacity` (How many components per column?) and a `capacity` (How many columns?)
pub fn with_capacity(capacity: usize, column_capacity: usize) -> Self {
Self {
columns: SparseSet::with_capacity(column_capacity),
capacity,
}
}
/// Add a new column to the [`Table`]. Specify the component which will be stored in the [`column`](ThinColumn) using its [`ComponentId`]
#[must_use]
pub fn add_column(mut self, component_info: &ComponentInfo) -> Self {
self.columns.insert(
component_info.id(),
ThinColumn::with_capacity(component_info, self.capacity),
);
self
}
/// Build the [`Table`], after this operation the caller wouldn't be able to add more columns. The [`Table`] will be ready to use.
#[must_use]
pub fn build(self) -> Table {
Table {
columns: self.columns.into_immutable(),
entities: Vec::with_capacity(self.capacity),
}
}
}
/// A column-oriented [structure-of-arrays] based storage for [`Component`]s of entities
/// in a [`World`].
///
/// Conceptually, a `Table` can be thought of as a `HashMap<ComponentId, Column>`, where
/// each [`ThinColumn`] is a type-erased `Vec<T: Component>`. Each row corresponds to a single entity
/// (i.e. index 3 in Column A and index 3 in Column B point to different components on the same
/// entity). Fetching components from a table involves fetching the associated column for a
/// component type (via its [`ComponentId`]), then fetching the entity's row within that column.
///
/// [structure-of-arrays]: https://en.wikipedia.org/wiki/AoS_and_SoA#Structure_of_arrays
/// [`Component`]: crate::component::Component
/// [`World`]: crate::world::World
pub struct Table {
columns: ImmutableSparseSet<ComponentId, ThinColumn>,
entities: Vec<Entity>,
}
struct AbortOnPanic;
impl Drop for AbortOnPanic {
fn drop(&mut self) {
// Panicking while unwinding will force an abort.
panic!("Aborting due to allocator error");
}
}
impl Table {
/// Fetches a read-only slice of the entities stored within the [`Table`].
#[inline]
pub fn entities(&self) -> &[Entity] {
&self.entities
}
/// Get the capacity of this table, in entities.
/// Note that if an allocation is in process, this might not match the actual capacity of the columns, but it should once the allocation ends.
#[inline]
pub fn capacity(&self) -> usize {
self.entities.capacity()
}
/// Removes the entity at the given row and returns the entity swapped in to replace it (if an
/// entity was swapped in)
///
/// # Safety
/// `row` must be in-bounds (`row.as_usize()` < `self.len()`)
pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) -> Option<Entity> {
debug_assert!(row.as_usize() < self.entity_count());
let last_element_index = self.entity_count() - 1;
if row.as_usize() != last_element_index {
// Instead of checking this condition on every `swap_remove` call, we
// check it here and use `swap_remove_nonoverlapping`.
for col in self.columns.values_mut() {
// SAFETY:
// - `row` < `len`
// - `last_element_index` = `len` - 1
// - `row` != `last_element_index`
// - the `len` is kept within `self.entities`, it will update accordingly.
unsafe {
col.swap_remove_and_drop_unchecked_nonoverlapping(last_element_index, row);
};
}
} else {
// If `row.as_usize()` == `last_element_index` than there's no point in removing the component
// at `row`, but we still need to drop it.
for col in self.columns.values_mut() {
col.drop_last_component(last_element_index);
}
}
let is_last = row.as_usize() == last_element_index;
self.entities.swap_remove(row.as_usize());
if is_last {
None
} else {
Some(self.entities[row.as_usize()])
}
}
/// Moves the `row` column values to `new_table`, for the columns shared between both tables.
/// Returns the index of the new row in `new_table` and the entity in this table swapped in
/// to replace it (if an entity was swapped in). missing columns will be "forgotten". It is
/// the caller's responsibility to drop them. Failure to do so may result in resources not
/// being released (i.e. files handles not being released, memory leaks, etc.)
///
/// # Safety
/// - `row` must be in-bounds
pub(crate) unsafe fn move_to_and_forget_missing_unchecked(
&mut self,
row: TableRow,
new_table: &mut Table,
) -> TableMoveResult {
debug_assert!(row.as_usize() < self.entity_count());
let last_element_index = self.entity_count() - 1;
let is_last = row.as_usize() == last_element_index;
let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
for (component_id, column) in self.columns.iter_mut() {
if let Some(new_column) = new_table.get_column_mut(*component_id) {
new_column.initialize_from_unchecked(column, last_element_index, row, new_row);
} else {
// It's the caller's responsibility to drop these cases.
column.swap_remove_and_forget_unchecked(last_element_index, row);
}
}
TableMoveResult {
new_row,
swapped_entity: if is_last {
None
} else {
Some(self.entities[row.as_usize()])
},
}
}
/// Moves the `row` column values to `new_table`, for the columns shared between both tables.
/// Returns the index of the new row in `new_table` and the entity in this table swapped in
/// to replace it (if an entity was swapped in).
///
/// # Safety
/// row must be in-bounds
pub(crate) unsafe fn move_to_and_drop_missing_unchecked(
&mut self,
row: TableRow,
new_table: &mut Table,
) -> TableMoveResult {
debug_assert!(row.as_usize() < self.entity_count());
let last_element_index = self.entity_count() - 1;
let is_last = row.as_usize() == last_element_index;
let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
for (component_id, column) in self.columns.iter_mut() {
if let Some(new_column) = new_table.get_column_mut(*component_id) {
new_column.initialize_from_unchecked(column, last_element_index, row, new_row);
} else {
column.swap_remove_and_drop_unchecked(last_element_index, row);
}
}
TableMoveResult {
new_row,
swapped_entity: if is_last {
None
} else {
Some(self.entities[row.as_usize()])
},
}
}
/// Moves the `row` column values to `new_table`, for the columns shared between both tables.
/// Returns the index of the new row in `new_table` and the entity in this table swapped in
/// to replace it (if an entity was swapped in).
///
/// # Safety
/// - `row` must be in-bounds
/// - `new_table` must contain every component this table has
pub(crate) unsafe fn move_to_superset_unchecked(
&mut self,
row: TableRow,
new_table: &mut Table,
) -> TableMoveResult {
debug_assert!(row.as_usize() < self.entity_count());
let last_element_index = self.entity_count() - 1;
let is_last = row.as_usize() == last_element_index;
let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
for (component_id, column) in self.columns.iter_mut() {
new_table
.get_column_mut(*component_id)
.debug_checked_unwrap()
.initialize_from_unchecked(column, last_element_index, row, new_row);
}
TableMoveResult {
new_row,
swapped_entity: if is_last {
None
} else {
Some(self.entities[row.as_usize()])
},
}
}
/// Get the data of the column matching `component_id` as a slice.
///
/// # Safety
/// `row.as_usize()` < `self.len()`
/// - `T` must match the `component_id`
pub unsafe fn get_data_slice_for<T>(
&self,
component_id: ComponentId,
) -> Option<&[UnsafeCell<T>]> {
self.get_column(component_id)
.map(|col| col.get_data_slice(self.entity_count()))
}
/// Get the added ticks of the column matching `component_id` as a slice.
pub fn get_added_ticks_slice_for(
&self,
component_id: ComponentId,
) -> Option<&[UnsafeCell<Tick>]> {
self.get_column(component_id)
// SAFETY: `self.len()` is guaranteed to be the len of the ticks array
.map(|col| unsafe { col.get_added_ticks_slice(self.entity_count()) })
}
/// Get the changed ticks of the column matching `component_id` as a slice.
pub fn get_changed_ticks_slice_for(
&self,
component_id: ComponentId,
) -> Option<&[UnsafeCell<Tick>]> {
self.get_column(component_id)
// SAFETY: `self.len()` is guaranteed to be the len of the ticks array
.map(|col| unsafe { col.get_changed_ticks_slice(self.entity_count()) })
}
/// Fetches the calling locations that last changed the each component
pub fn get_changed_by_slice_for(
&self,
component_id: ComponentId,
) -> MaybeLocation<Option<&[UnsafeCell<&'static Location<'static>>]>> {
MaybeLocation::new_with_flattened(|| {
self.get_column(component_id)
// SAFETY: `self.len()` is guaranteed to be the len of the locations array
.map(|col| unsafe { col.get_changed_by_slice(self.entity_count()) })
})
}
/// Get the specific [`change tick`](Tick) of the component matching `component_id` in `row`.
pub fn get_changed_tick(
&self,
component_id: ComponentId,
row: TableRow,
) -> Option<&UnsafeCell<Tick>> {
(row.as_usize() < self.entity_count()).then_some(
// SAFETY: `row.as_usize()` < `len`
unsafe {
self.get_column(component_id)?
.changed_ticks
.get_unchecked(row.as_usize())
},
)
}
/// Get the specific [`added tick`](Tick) of the component matching `component_id` in `row`.
pub fn get_added_tick(
&self,
component_id: ComponentId,
row: TableRow,
) -> Option<&UnsafeCell<Tick>> {
(row.as_usize() < self.entity_count()).then_some(
// SAFETY: `row.as_usize()` < `len`
unsafe {
self.get_column(component_id)?
.added_ticks
.get_unchecked(row.as_usize())
},
)
}
/// Get the specific calling location that changed the component matching `component_id` in `row`
pub fn get_changed_by(
&self,
component_id: ComponentId,
row: TableRow,
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
MaybeLocation::new_with_flattened(|| {
(row.as_usize() < self.entity_count()).then_some(
// SAFETY: `row.as_usize()` < `len`
unsafe {
self.get_column(component_id)?
.changed_by
.as_ref()
.map(|changed_by| changed_by.get_unchecked(row.as_usize()))
},
)
})
}
/// Get the [`ComponentTicks`] of the component matching `component_id` in `row`.
///
/// # Safety
/// - `row.as_usize()` < `self.len()`
pub unsafe fn get_ticks_unchecked(
&self,
component_id: ComponentId,
row: TableRow,
) -> Option<ComponentTicks> {
self.get_column(component_id).map(|col| ComponentTicks {
added: col.added_ticks.get_unchecked(row.as_usize()).read(),
changed: col.changed_ticks.get_unchecked(row.as_usize()).read(),
})
}
/// Fetches a read-only reference to the [`ThinColumn`] for a given [`Component`] within the table.
///
/// Returns `None` if the corresponding component does not belong to the table.
///
/// [`Component`]: crate::component::Component
#[inline]
pub fn get_column(&self, component_id: ComponentId) -> Option<&ThinColumn> {
self.columns.get(component_id)
}
/// Fetches a mutable reference to the [`ThinColumn`] for a given [`Component`] within the
/// table.
///
/// Returns `None` if the corresponding component does not belong to the table.
///
/// [`Component`]: crate::component::Component
#[inline]
pub(crate) fn get_column_mut(&mut self, component_id: ComponentId) -> Option<&mut ThinColumn> {
self.columns.get_mut(component_id)
}
/// Checks if the table contains a [`ThinColumn`] for a given [`Component`].
///
/// Returns `true` if the column is present, `false` otherwise.
///
/// [`Component`]: crate::component::Component
#[inline]
pub fn has_column(&self, component_id: ComponentId) -> bool {
self.columns.contains(component_id)
}
/// Reserves `additional` elements worth of capacity within the table.
pub(crate) fn reserve(&mut self, additional: usize) {
if self.capacity() - self.entity_count() < additional {
let column_cap = self.capacity();
self.entities.reserve(additional);
// use entities vector capacity as driving capacity for all related allocations
let new_capacity = self.entities.capacity();
if column_cap == 0 {
// SAFETY: the current capacity is 0
unsafe { self.alloc_columns(NonZeroUsize::new_unchecked(new_capacity)) };
} else {
// SAFETY:
// - `column_cap` is indeed the columns' capacity
unsafe {
self.realloc_columns(
NonZeroUsize::new_unchecked(column_cap),
NonZeroUsize::new_unchecked(new_capacity),
);
};
}
}
}
/// Allocate memory for the columns in the [`Table`]
///
/// The current capacity of the columns should be 0, if it's not 0, then the previous data will be overwritten and leaked.
fn alloc_columns(&mut self, new_capacity: NonZeroUsize) {
// If any of these allocations trigger an unwind, the wrong capacity will be used while dropping this table - UB.
// To avoid this, we use `AbortOnPanic`. If the allocation triggered a panic, the `AbortOnPanic`'s Drop impl will be
// called, and abort the program.
let _guard = AbortOnPanic;
for col in self.columns.values_mut() {
col.alloc(new_capacity);
}
core::mem::forget(_guard); // The allocation was successful, so we don't drop the guard.
}
/// Reallocate memory for the columns in the [`Table`]
///
/// # Safety
/// - `current_column_capacity` is indeed the capacity of the columns
unsafe fn realloc_columns(
&mut self,
current_column_capacity: NonZeroUsize,
new_capacity: NonZeroUsize,
) {
// If any of these allocations trigger an unwind, the wrong capacity will be used while dropping this table - UB.
// To avoid this, we use `AbortOnPanic`. If the allocation triggered a panic, the `AbortOnPanic`'s Drop impl will be
// called, and abort the program.
let _guard = AbortOnPanic;
// SAFETY:
// - There's no overflow
// - `current_capacity` is indeed the capacity - safety requirement
// - current capacity > 0
for col in self.columns.values_mut() {
col.realloc(current_column_capacity, new_capacity);
}
core::mem::forget(_guard); // The allocation was successful, so we don't drop the guard.
}
/// Allocates space for a new entity
///
/// # Safety
/// the allocated row must be written to immediately with valid values in each column
pub(crate) unsafe fn allocate(&mut self, entity: Entity) -> TableRow {
self.reserve(1);
let len = self.entity_count();
self.entities.push(entity);
for col in self.columns.values_mut() {
col.added_ticks
.initialize_unchecked(len, UnsafeCell::new(Tick::new(0)));
col.changed_ticks
.initialize_unchecked(len, UnsafeCell::new(Tick::new(0)));
col.changed_by
.as_mut()
.zip(MaybeLocation::caller())
.map(|(changed_by, caller)| {
changed_by.initialize_unchecked(len, UnsafeCell::new(caller));
});
}
TableRow::from_usize(len)
}
/// Gets the number of entities currently being stored in the table.
#[inline]
pub fn entity_count(&self) -> usize {
self.entities.len()
}
/// Get the drop function for some component that is stored in this table.
#[inline]
pub fn get_drop_for(&self, component_id: ComponentId) -> Option<unsafe fn(OwningPtr<'_>)> {
self.get_column(component_id)?.data.drop
}
/// Gets the number of components being stored in the table.
#[inline]
pub fn component_count(&self) -> usize {
self.columns.len()
}
/// Gets the maximum number of entities the table can currently store
/// without reallocating the underlying memory.
#[inline]
pub fn entity_capacity(&self) -> usize {
self.entities.capacity()
}
/// Checks if the [`Table`] is empty or not.
///
/// Returns `true` if the table contains no entities, `false` otherwise.
#[inline]
pub fn is_empty(&self) -> bool {
self.entities.is_empty()
}
/// Call [`Tick::check_tick`] on all of the ticks in the [`Table`]
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
let len = self.entity_count();
for col in self.columns.values_mut() {
// SAFETY: `len` is the actual length of the column
unsafe { col.check_change_ticks(len, change_tick) };
}
}
/// Iterates over the [`ThinColumn`]s of the [`Table`].
pub fn iter_columns(&self) -> impl Iterator<Item = &ThinColumn> {
self.columns.values()
}
/// Clears all of the stored components in the [`Table`].
pub(crate) fn clear(&mut self) {
let len = self.entity_count();
// We must clear the entities first, because in the drop function causes a panic, it will result in a double free of the columns.
self.entities.clear();
for column in self.columns.values_mut() {
// SAFETY: we defer `self.entities.clear()` until after clearing the columns,
// so `self.len()` should match the columns' len
unsafe { column.clear(len) };
}
}
/// Moves component data out of the [`Table`].
///
/// This function leaves the underlying memory unchanged, but the component behind
/// returned pointer is semantically owned by the caller and will not be dropped in its original location.
/// Caller is responsible to drop component data behind returned pointer.
///
/// # Safety
/// - This table must hold the component matching `component_id`
/// - `row` must be in bounds
/// - The row's inconsistent state that happens after taking the component must be resolved—either initialize a new component or remove the row.
pub(crate) unsafe fn take_component(
&mut self,
component_id: ComponentId,
row: TableRow,
) -> OwningPtr<'_> {
self.get_column_mut(component_id)
.debug_checked_unwrap()
.data
.get_unchecked_mut(row.as_usize())
.promote()
}
/// Get the component at a given `row`, if the [`Table`] stores components with the given `component_id`
///
/// # Safety
/// `row.as_usize()` < `self.len()`
pub unsafe fn get_component(
&self,
component_id: ComponentId,
row: TableRow,
) -> Option<Ptr<'_>> {
self.get_column(component_id)
.map(|col| col.data.get_unchecked(row.as_usize()))
}
}
/// A collection of [`Table`] storages, indexed by [`TableId`]
///
/// Can be accessed via [`Storages`](crate::storage::Storages)
pub struct Tables {
tables: Vec<Table>,
table_ids: HashMap<Box<[ComponentId]>, TableId>,
}
impl Default for Tables {
fn default() -> Self {
let empty_table = TableBuilder::with_capacity(0, 0).build();
Tables {
tables: vec![empty_table],
table_ids: HashMap::default(),
}
}
}
pub(crate) struct TableMoveResult {
pub swapped_entity: Option<Entity>,
pub new_row: TableRow,
}
impl Tables {
/// Returns the number of [`Table`]s this collection contains
#[inline]
pub fn len(&self) -> usize {
self.tables.len()
}
/// Returns true if this collection contains no [`Table`]s
#[inline]
pub fn is_empty(&self) -> bool {
self.tables.is_empty()
}
/// Fetches a [`Table`] by its [`TableId`].
///
/// Returns `None` if `id` is invalid.
#[inline]
pub fn get(&self, id: TableId) -> Option<&Table> {
self.tables.get(id.as_usize())
}
/// Fetches mutable references to two different [`Table`]s.
///
/// # Panics
///
/// Panics if `a` and `b` are equal.
#[inline]
pub(crate) fn get_2_mut(&mut self, a: TableId, b: TableId) -> (&mut Table, &mut Table) {
if a.as_usize() > b.as_usize() {
let (b_slice, a_slice) = self.tables.split_at_mut(a.as_usize());
(&mut a_slice[0], &mut b_slice[b.as_usize()])
} else {
let (a_slice, b_slice) = self.tables.split_at_mut(b.as_usize());
(&mut a_slice[a.as_usize()], &mut b_slice[0])
}
}
/// Attempts to fetch a table based on the provided components,
/// creating and returning a new [`Table`] if one did not already exist.
///
/// # Safety
/// `component_ids` must contain components that exist in `components`
pub(crate) unsafe fn get_id_or_insert(
&mut self,
component_ids: &[ComponentId],
components: &Components,
) -> TableId {
if component_ids.is_empty() {
return TableId::empty();
}
let tables = &mut self.tables;
let (_key, value) = self
.table_ids
.raw_entry_mut()
.from_key(component_ids)
.or_insert_with(|| {
let mut table = TableBuilder::with_capacity(0, component_ids.len());
for component_id in component_ids {
table = table.add_column(components.get_info_unchecked(*component_id));
}
tables.push(table.build());
(component_ids.into(), TableId::from_usize(tables.len() - 1))
});
*value
}
/// Iterates through all of the tables stored within in [`TableId`] order.
pub fn iter(&self) -> core::slice::Iter<'_, Table> {
self.tables.iter()
}
/// Clears all data from all [`Table`]s stored within.
pub(crate) fn clear(&mut self) {
for table in &mut self.tables {
table.clear();
}
}
pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
for table in &mut self.tables {
table.check_change_ticks(change_tick);
}
}
}
impl Index<TableId> for Tables {
type Output = Table;
#[inline]
fn index(&self, index: TableId) -> &Self::Output {
&self.tables[index.as_usize()]
}
}
impl IndexMut<TableId> for Tables {
#[inline]
fn index_mut(&mut self, index: TableId) -> &mut Self::Output {
&mut self.tables[index.as_usize()]
}
}
impl Drop for Table {
fn drop(&mut self) {
let len = self.entity_count();
let cap = self.capacity();
self.entities.clear();
for col in self.columns.values_mut() {
// SAFETY: `cap` and `len` are correct
unsafe {
col.drop(cap, len);
}
}
}
}
#[cfg(test)]
mod tests {
use crate::{
change_detection::MaybeLocation,
component::{Component, ComponentIds, Components, ComponentsRegistrator, Tick},
entity::Entity,
ptr::OwningPtr,
storage::{TableBuilder, TableId, TableRow, Tables},
};
use alloc::vec::Vec;
#[derive(Component)]
struct W<T>(T);
#[test]
fn only_one_empty_table() {
let components = Components::default();
let mut tables = Tables::default();
let component_ids = &[];
// SAFETY: component_ids is empty, so we know it cannot reference invalid component IDs
let table_id = unsafe { tables.get_id_or_insert(component_ids, &components) };
assert_eq!(table_id, TableId::empty());
}
#[test]
fn table() {
let mut components = Components::default();
let mut componentids = ComponentIds::default();
// SAFETY: They are both new.
let mut registrator =
unsafe { ComponentsRegistrator::new(&mut components, &mut componentids) };
let component_id = registrator.register_component::<W<TableRow>>();
let columns = &[component_id];
let mut table = TableBuilder::with_capacity(0, columns.len())
.add_column(components.get_info(component_id).unwrap())
.build();
let entities = (0..200).map(Entity::from_raw).collect::<Vec<_>>();
for entity in &entities {
// SAFETY: we allocate and immediately set data afterwards
unsafe {
let row = table.allocate(*entity);
let value: W<TableRow> = W(row);
OwningPtr::make(value, |value_ptr| {
table.get_column_mut(component_id).unwrap().initialize(
row,
value_ptr,
Tick::new(0),
MaybeLocation::caller(),
);
});
};
}
assert_eq!(table.entity_capacity(), 256);
assert_eq!(table.entity_count(), 200);
}
}

View File

@@ -0,0 +1,322 @@
use crate::query::DebugCheckedUnwrap;
use alloc::{
alloc::{alloc, handle_alloc_error, realloc},
boxed::Box,
};
use core::{
alloc::Layout,
mem::{needs_drop, size_of},
num::NonZeroUsize,
ptr::{self, NonNull},
};
/// Similar to [`Vec<T>`], but with the capacity and length cut out for performance reasons.
///
/// This type can be treated as a `ManuallyDrop<Box<[T]>>` without a built in length. To avoid
/// memory leaks, [`drop`](Self::drop) must be called when no longer in use.
///
/// [`Vec<T>`]: alloc::vec::Vec
pub struct ThinArrayPtr<T> {
data: NonNull<T>,
#[cfg(debug_assertions)]
capacity: usize,
}
impl<T> ThinArrayPtr<T> {
fn empty() -> Self {
#[cfg(debug_assertions)]
{
Self {
data: NonNull::dangling(),
capacity: 0,
}
}
#[cfg(not(debug_assertions))]
{
Self {
data: NonNull::dangling(),
}
}
}
#[inline(always)]
fn set_capacity(&mut self, _capacity: usize) {
#[cfg(debug_assertions)]
{
self.capacity = _capacity;
}
}
/// Create a new [`ThinArrayPtr`] with a given capacity. If the `capacity` is 0, this will no allocate any memory.
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let mut arr = Self::empty();
if capacity > 0 {
// SAFETY:
// - The `current_capacity` is 0 because it was just created
unsafe { arr.alloc(NonZeroUsize::new_unchecked(capacity)) };
}
arr
}
/// Allocate memory for the array, this should only be used if not previous allocation has been made (capacity = 0)
/// The caller should update their saved `capacity` value to reflect the fact that it was changed
///
/// # Panics
/// - Panics if the new capacity overflows `usize`
pub fn alloc(&mut self, capacity: NonZeroUsize) {
self.set_capacity(capacity.get());
if size_of::<T>() != 0 {
let new_layout = Layout::array::<T>(capacity.get())
.expect("layout should be valid (arithmetic overflow)");
// SAFETY:
// - layout has non-zero size, `capacity` > 0, `size` > 0 (`size_of::<T>() != 0`)
self.data = NonNull::new(unsafe { alloc(new_layout) })
.unwrap_or_else(|| handle_alloc_error(new_layout))
.cast();
}
}
/// Reallocate memory for the array, this should only be used if a previous allocation for this array has been made (capacity > 0).
///
/// # Panics
/// - Panics if the new capacity overflows `usize`
///
/// # Safety
/// - The current capacity is indeed greater than 0
/// - The caller should update their saved `capacity` value to reflect the fact that it was changed
pub unsafe fn realloc(&mut self, current_capacity: NonZeroUsize, new_capacity: NonZeroUsize) {
#[cfg(debug_assertions)]
assert_eq!(self.capacity, current_capacity.get());
self.set_capacity(new_capacity.get());
if size_of::<T>() != 0 {
let new_layout =
Layout::array::<T>(new_capacity.get()).expect("overflow while allocating memory");
// SAFETY:
// - ptr was be allocated via this allocator
// - the layout of the array is the same as `Layout::array::<T>(current_capacity)`
// - the size of `T` is non 0, and `new_capacity` > 0
// - "new_size, when rounded up to the nearest multiple of layout.align(), must not overflow (i.e., the rounded value must be less than usize::MAX)",
// since the item size is always a multiple of its align, the rounding cannot happen
// here and the overflow is handled in `Layout::array`
self.data = NonNull::new(unsafe {
realloc(
self.data.cast().as_ptr(),
// We can use `unwrap_unchecked` because this is the Layout of the current allocation, it must be valid
Layout::array::<T>(current_capacity.get()).debug_checked_unwrap(),
new_layout.size(),
)
})
.unwrap_or_else(|| handle_alloc_error(new_layout))
.cast();
}
}
/// Initializes the value at `index` to `value`. This function does not do any bounds checking.
///
/// # Safety
/// `index` must be in bounds i.e. within the `capacity`.
/// if `index` = `len` the caller should update their saved `len` value to reflect the fact that it was changed
#[inline]
pub unsafe fn initialize_unchecked(&mut self, index: usize, value: T) {
// SAFETY: `index` is in bounds
let ptr = unsafe { self.get_unchecked_raw(index) };
// SAFETY: `index` is in bounds, therefore the pointer to that location in the array is valid, and aligned.
unsafe { ptr::write(ptr, value) };
}
/// Get a raw pointer to the element at `index`. This method doesn't do any bounds checking.
///
/// # Safety
/// - `index` must be safe to access.
#[inline]
pub unsafe fn get_unchecked_raw(&mut self, index: usize) -> *mut T {
// SAFETY:
// - `self.data` and the resulting pointer are in the same allocated object
// - the memory address of the last element doesn't overflow `isize`, so if `index` is in bounds, it won't overflow either
unsafe { self.data.as_ptr().add(index) }
}
/// Get a reference to the element at `index`. This method doesn't do any bounds checking.
///
/// # Safety
/// - `index` must be safe to read.
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> &'_ T {
// SAFETY:
// - `self.data` and the resulting pointer are in the same allocated object
// - the memory address of the last element doesn't overflow `isize`, so if `index` is in bounds, it won't overflow either
let ptr = unsafe { self.data.as_ptr().add(index) };
// SAFETY:
// - The pointer is properly aligned
// - It is dereferenceable (all in the same allocation)
// - `index` < `len` and the element is safe to write to, so its valid
// - We have a reference to self, so no other mutable accesses to the element can occur
unsafe {
ptr.as_ref()
// SAFETY: We can use `unwarp_unchecked` because the pointer isn't null)
.debug_checked_unwrap()
}
}
/// Get a mutable reference to the element at `index`. This method doesn't do any bounds checking.
///
/// # Safety
/// - `index` must be safe to write to.
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &'_ mut T {
// SAFETY:
// - `self.data` and the resulting pointer are in the same allocated object
// - the memory address of the last element doesn't overflow `isize`, so if `index` is in bounds, it won't overflow either
let ptr = unsafe { self.data.as_ptr().add(index) };
// SAFETY:
// - The pointer is properly aligned
// - It is dereferenceable (all in the same allocation)
// - `index` < `len` and the element is safe to write to, so its valid
// - We have a mutable reference to `self`
unsafe {
ptr.as_mut()
// SAFETY: We can use `unwarp_unchecked` because the pointer isn't null)
.unwrap_unchecked()
}
}
/// Perform a [`swap-remove`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove) and return the removed value.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_unchecked_nonoverlapping(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) -> T {
#[cfg(debug_assertions)]
{
debug_assert!(self.capacity > index_to_keep);
debug_assert!(self.capacity > index_to_remove);
debug_assert_ne!(index_to_keep, index_to_remove);
}
let base_ptr = self.data.as_ptr();
let value = ptr::read(base_ptr.add(index_to_remove));
ptr::copy_nonoverlapping(
base_ptr.add(index_to_keep),
base_ptr.add(index_to_remove),
1,
);
value
}
/// Perform a [`swap-remove`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove) and return the removed value.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_unchecked(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) -> T {
if index_to_remove != index_to_keep {
return self.swap_remove_unchecked_nonoverlapping(index_to_remove, index_to_keep);
}
ptr::read(self.data.as_ptr().add(index_to_remove))
}
/// Perform a [`swap-remove`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove) and drop the removed value.
///
/// # Safety
/// - `index_to_keep` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` must be safe to access (within the bounds of the length of the array).
/// - `index_to_remove` != `index_to_keep`
/// - The caller should address the inconsistent state of the array that has occurred after the swap, either:
/// 1) initialize a different value in `index_to_keep`
/// 2) update the saved length of the array if `index_to_keep` was the last element.
#[inline]
pub unsafe fn swap_remove_and_drop_unchecked(
&mut self,
index_to_remove: usize,
index_to_keep: usize,
) {
let val = &mut self.swap_remove_unchecked(index_to_remove, index_to_keep);
ptr::drop_in_place(ptr::from_mut(val));
}
/// Get a raw pointer to the last element of the array, return `None` if the length is 0
///
/// # Safety
/// - ensure that `current_len` is indeed the len of the array
#[inline]
unsafe fn last_element(&mut self, current_len: usize) -> Option<*mut T> {
(current_len != 0).then_some(self.data.as_ptr().add(current_len - 1))
}
/// Clears the array, removing (and dropping) Note that this method has no effect on the allocated capacity of the vector.
///
/// # Safety
/// - `current_len` is indeed the length of the array
/// - The caller should update their saved length value
pub unsafe fn clear_elements(&mut self, mut current_len: usize) {
if needs_drop::<T>() {
while let Some(to_drop) = self.last_element(current_len) {
ptr::drop_in_place(to_drop);
current_len -= 1;
}
}
}
/// Drop the entire array and all its elements.
///
/// # Safety
/// - `current_len` is indeed the length of the array
/// - `current_capacity` is indeed the capacity of the array
/// - The caller must not use this `ThinArrayPtr` in any way after calling this function
pub unsafe fn drop(&mut self, current_capacity: usize, current_len: usize) {
#[cfg(debug_assertions)]
assert_eq!(self.capacity, current_capacity);
if current_capacity != 0 {
self.clear_elements(current_len);
let layout = Layout::array::<T>(current_capacity).expect("layout should be valid");
alloc::alloc::dealloc(self.data.as_ptr().cast(), layout);
}
self.set_capacity(0);
}
/// Get the [`ThinArrayPtr`] as a slice with a given length.
///
/// # Safety
/// - `slice_len` must match the actual length of the array
#[inline]
pub unsafe fn as_slice(&self, slice_len: usize) -> &[T] {
// SAFETY:
// - the data is valid - allocated with the same allocator
// - non-null and well-aligned
// - we have a shared reference to self - the data will not be mutated during 'a
unsafe { core::slice::from_raw_parts(self.data.as_ptr(), slice_len) }
}
}
impl<T> From<Box<[T]>> for ThinArrayPtr<T> {
fn from(value: Box<[T]>) -> Self {
let _len = value.len();
let slice_ptr = Box::<[T]>::into_raw(value);
// SAFETY: We just got the pointer from a reference
let first_element_ptr = unsafe { (*slice_ptr).as_mut_ptr() };
Self {
// SAFETY: The pointer can't be null, it came from a reference
data: unsafe { NonNull::new_unchecked(first_element_ptr) },
#[cfg(debug_assertions)]
capacity: _len,
}
}
}

View File

@@ -0,0 +1,233 @@
use alloc::{borrow::Cow, vec::Vec};
use super::{IntoSystem, ReadOnlySystem, System, SystemParamValidationError};
use crate::{
schedule::InternedSystemSet,
system::{input::SystemInput, SystemIn},
world::unsafe_world_cell::UnsafeWorldCell,
};
/// Customizes the behavior of an [`AdapterSystem`]
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// use bevy_ecs::system::{Adapt, AdapterSystem};
///
/// // A system adapter that inverts the result of a system.
/// // NOTE: Instead of manually implementing this, you can just use `bevy_ecs::schedule::common_conditions::not`.
/// pub type NotSystem<S> = AdapterSystem<NotMarker, S>;
///
/// // This struct is used to customize the behavior of our adapter.
/// pub struct NotMarker;
///
/// impl<S> Adapt<S> for NotMarker
/// where
/// S: System,
/// S::Out: std::ops::Not,
/// {
/// type In = S::In;
/// type Out = <S::Out as std::ops::Not>::Output;
///
/// fn adapt(
/// &mut self,
/// input: <Self::In as SystemInput>::Inner<'_>,
/// run_system: impl FnOnce(SystemIn<'_, S>) -> S::Out,
/// ) -> Self::Out {
/// !run_system(input)
/// }
/// }
/// # let mut world = World::new();
/// # let mut system = NotSystem::new(NotMarker, IntoSystem::into_system(|| false), "".into());
/// # system.initialize(&mut world);
/// # assert!(system.run((), &mut world));
/// ```
#[diagnostic::on_unimplemented(
message = "`{Self}` can not adapt a system of type `{S}`",
label = "invalid system adapter"
)]
pub trait Adapt<S: System>: Send + Sync + 'static {
/// The [input](System::In) type for an [`AdapterSystem`].
type In: SystemInput;
/// The [output](System::Out) type for an [`AdapterSystem`].
type Out;
/// When used in an [`AdapterSystem`], this function customizes how the system
/// is run and how its inputs/outputs are adapted.
fn adapt(
&mut self,
input: <Self::In as SystemInput>::Inner<'_>,
run_system: impl FnOnce(SystemIn<'_, S>) -> S::Out,
) -> Self::Out;
}
/// An [`IntoSystem`] creating an instance of [`AdapterSystem`].
#[derive(Clone)]
pub struct IntoAdapterSystem<Func, S> {
func: Func,
system: S,
}
impl<Func, S> IntoAdapterSystem<Func, S> {
/// Creates a new [`IntoSystem`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
pub const fn new(func: Func, system: S) -> Self {
Self { func, system }
}
}
#[doc(hidden)]
pub struct IsAdapterSystemMarker;
impl<Func, S, I, O, M> IntoSystem<Func::In, Func::Out, (IsAdapterSystemMarker, I, O, M)>
for IntoAdapterSystem<Func, S>
where
Func: Adapt<S::System>,
I: SystemInput,
S: IntoSystem<I, O, M>,
{
type System = AdapterSystem<Func, S::System>;
// Required method
fn into_system(this: Self) -> Self::System {
let system = IntoSystem::into_system(this.system);
let name = system.name();
AdapterSystem::new(this.func, system, name)
}
}
/// A [`System`] that takes the output of `S` and transforms it by applying `Func` to it.
#[derive(Clone)]
pub struct AdapterSystem<Func, S> {
func: Func,
system: S,
name: Cow<'static, str>,
}
impl<Func, S> AdapterSystem<Func, S>
where
Func: Adapt<S>,
S: System,
{
/// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
pub const fn new(func: Func, system: S, name: Cow<'static, str>) -> Self {
Self { func, system, name }
}
}
impl<Func, S> System for AdapterSystem<Func, S>
where
Func: Adapt<S>,
S: System,
{
type In = Func::In;
type Out = Func::Out;
fn name(&self) -> Cow<'static, str> {
self.name.clone()
}
fn component_access(&self) -> &crate::query::Access<crate::component::ComponentId> {
self.system.component_access()
}
#[inline]
fn archetype_component_access(
&self,
) -> &crate::query::Access<crate::archetype::ArchetypeComponentId> {
self.system.archetype_component_access()
}
fn is_send(&self) -> bool {
self.system.is_send()
}
fn is_exclusive(&self) -> bool {
self.system.is_exclusive()
}
fn has_deferred(&self) -> bool {
self.system.has_deferred()
}
#[inline]
unsafe fn run_unsafe(
&mut self,
input: SystemIn<'_, Self>,
world: UnsafeWorldCell,
) -> Self::Out {
// SAFETY: `system.run_unsafe` has the same invariants as `self.run_unsafe`.
self.func.adapt(input, |input| unsafe {
self.system.run_unsafe(input, world)
})
}
#[inline]
fn apply_deferred(&mut self, world: &mut crate::prelude::World) {
self.system.apply_deferred(world);
}
#[inline]
fn queue_deferred(&mut self, world: crate::world::DeferredWorld) {
self.system.queue_deferred(world);
}
#[inline]
unsafe fn validate_param_unsafe(
&mut self,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
// SAFETY: Delegate to other `System` implementations.
unsafe { self.system.validate_param_unsafe(world) }
}
fn initialize(&mut self, world: &mut crate::prelude::World) {
self.system.initialize(world);
}
#[inline]
fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
self.system.update_archetype_component_access(world);
}
fn check_change_tick(&mut self, change_tick: crate::component::Tick) {
self.system.check_change_tick(change_tick);
}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
self.system.default_system_sets()
}
fn get_last_run(&self) -> crate::component::Tick {
self.system.get_last_run()
}
fn set_last_run(&mut self, last_run: crate::component::Tick) {
self.system.set_last_run(last_run);
}
}
// SAFETY: The inner system is read-only.
unsafe impl<Func, S> ReadOnlySystem for AdapterSystem<Func, S>
where
Func: Adapt<S>,
S: ReadOnlySystem,
{
}
impl<F, S, Out> Adapt<S> for F
where
F: Send + Sync + 'static + FnMut(S::Out) -> Out,
S: System,
{
type In = S::In;
type Out = Out;
fn adapt(
&mut self,
input: <Self::In as SystemInput>::Inner<'_>,
run_system: impl FnOnce(SystemIn<'_, S>) -> S::Out,
) -> Out {
self(run_system(input))
}
}

1106
vendor/bevy_ecs/src/system/builder.rs vendored Normal file

File diff suppressed because it is too large Load Diff

512
vendor/bevy_ecs/src/system/combinator.rs vendored Normal file
View File

@@ -0,0 +1,512 @@
use alloc::{borrow::Cow, format, vec::Vec};
use core::marker::PhantomData;
use crate::{
archetype::ArchetypeComponentId,
component::{ComponentId, Tick},
prelude::World,
query::Access,
schedule::InternedSystemSet,
system::{input::SystemInput, SystemIn, SystemParamValidationError},
world::unsafe_world_cell::UnsafeWorldCell,
};
use super::{IntoSystem, ReadOnlySystem, System};
/// Customizes the behavior of a [`CombinatorSystem`].
///
/// # Examples
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_ecs::system::{CombinatorSystem, Combine};
///
/// // A system combinator that performs an exclusive-or (XOR)
/// // operation on the output of two systems.
/// pub type Xor<A, B> = CombinatorSystem<XorMarker, A, B>;
///
/// // This struct is used to customize the behavior of our combinator.
/// pub struct XorMarker;
///
/// impl<A, B> Combine<A, B> for XorMarker
/// where
/// A: System<In = (), Out = bool>,
/// B: System<In = (), Out = bool>,
/// {
/// type In = ();
/// type Out = bool;
///
/// fn combine(
/// _input: Self::In,
/// a: impl FnOnce(A::In) -> A::Out,
/// b: impl FnOnce(B::In) -> B::Out,
/// ) -> Self::Out {
/// a(()) ^ b(())
/// }
/// }
///
/// # #[derive(Resource, PartialEq, Eq)] struct A(u32);
/// # #[derive(Resource, PartialEq, Eq)] struct B(u32);
/// # #[derive(Resource, Default)] struct RanFlag(bool);
/// # let mut world = World::new();
/// # world.init_resource::<RanFlag>();
/// #
/// # let mut app = Schedule::default();
/// app.add_systems(my_system.run_if(Xor::new(
/// IntoSystem::into_system(resource_equals(A(1))),
/// IntoSystem::into_system(resource_equals(B(1))),
/// // The name of the combined system.
/// std::borrow::Cow::Borrowed("a ^ b"),
/// )));
/// # fn my_system(mut flag: ResMut<RanFlag>) { flag.0 = true; }
/// #
/// # world.insert_resource(A(0));
/// # world.insert_resource(B(0));
/// # app.run(&mut world);
/// # // Neither condition passes, so the system does not run.
/// # assert!(!world.resource::<RanFlag>().0);
/// #
/// # world.insert_resource(A(1));
/// # app.run(&mut world);
/// # // Only the first condition passes, so the system runs.
/// # assert!(world.resource::<RanFlag>().0);
/// # world.resource_mut::<RanFlag>().0 = false;
/// #
/// # world.insert_resource(B(1));
/// # app.run(&mut world);
/// # // Both conditions pass, so the system does not run.
/// # assert!(!world.resource::<RanFlag>().0);
/// #
/// # world.insert_resource(A(0));
/// # app.run(&mut world);
/// # // Only the second condition passes, so the system runs.
/// # assert!(world.resource::<RanFlag>().0);
/// # world.resource_mut::<RanFlag>().0 = false;
/// ```
#[diagnostic::on_unimplemented(
message = "`{Self}` can not combine systems `{A}` and `{B}`",
label = "invalid system combination",
note = "the inputs and outputs of `{A}` and `{B}` are not compatible with this combiner"
)]
pub trait Combine<A: System, B: System> {
/// The [input](System::In) type for a [`CombinatorSystem`].
type In: SystemInput;
/// The [output](System::Out) type for a [`CombinatorSystem`].
type Out;
/// When used in a [`CombinatorSystem`], this function customizes how
/// the two composite systems are invoked and their outputs are combined.
///
/// See the trait-level docs for [`Combine`] for an example implementation.
fn combine(
input: <Self::In as SystemInput>::Inner<'_>,
a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
) -> Self::Out;
}
/// A [`System`] defined by combining two other systems.
/// The behavior of this combinator is specified by implementing the [`Combine`] trait.
/// For a full usage example, see the docs for [`Combine`].
pub struct CombinatorSystem<Func, A, B> {
_marker: PhantomData<fn() -> Func>,
a: A,
b: B,
name: Cow<'static, str>,
component_access: Access<ComponentId>,
archetype_component_access: Access<ArchetypeComponentId>,
}
impl<Func, A, B> CombinatorSystem<Func, A, B> {
/// Creates a new system that combines two inner systems.
///
/// The returned system will only be usable if `Func` implements [`Combine<A, B>`].
pub const fn new(a: A, b: B, name: Cow<'static, str>) -> Self {
Self {
_marker: PhantomData,
a,
b,
name,
component_access: Access::new(),
archetype_component_access: Access::new(),
}
}
}
impl<A, B, Func> System for CombinatorSystem<Func, A, B>
where
Func: Combine<A, B> + 'static,
A: System,
B: System,
{
type In = Func::In;
type Out = Func::Out;
fn name(&self) -> Cow<'static, str> {
self.name.clone()
}
fn component_access(&self) -> &Access<ComponentId> {
&self.component_access
}
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
&self.archetype_component_access
}
fn is_send(&self) -> bool {
self.a.is_send() && self.b.is_send()
}
fn is_exclusive(&self) -> bool {
self.a.is_exclusive() || self.b.is_exclusive()
}
fn has_deferred(&self) -> bool {
self.a.has_deferred() || self.b.has_deferred()
}
unsafe fn run_unsafe(
&mut self,
input: SystemIn<'_, Self>,
world: UnsafeWorldCell,
) -> Self::Out {
Func::combine(
input,
// SAFETY: The world accesses for both underlying systems have been registered,
// so the caller will guarantee that no other systems will conflict with `a` or `b`.
// If either system has `is_exclusive()`, then the combined system also has `is_exclusive`.
// Since these closures are `!Send + !Sync + !'static`, they can never be called
// in parallel, so their world accesses will not conflict with each other.
// Additionally, `update_archetype_component_access` has been called,
// which forwards to the implementations for `self.a` and `self.b`.
|input| unsafe { self.a.run_unsafe(input, world) },
// SAFETY: See the comment above.
|input| unsafe { self.b.run_unsafe(input, world) },
)
}
#[inline]
fn apply_deferred(&mut self, world: &mut World) {
self.a.apply_deferred(world);
self.b.apply_deferred(world);
}
#[inline]
fn queue_deferred(&mut self, mut world: crate::world::DeferredWorld) {
self.a.queue_deferred(world.reborrow());
self.b.queue_deferred(world);
}
#[inline]
unsafe fn validate_param_unsafe(
&mut self,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
// SAFETY: Delegate to other `System` implementations.
unsafe { self.a.validate_param_unsafe(world) }
}
fn initialize(&mut self, world: &mut World) {
self.a.initialize(world);
self.b.initialize(world);
self.component_access.extend(self.a.component_access());
self.component_access.extend(self.b.component_access());
}
fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
self.a.update_archetype_component_access(world);
self.b.update_archetype_component_access(world);
self.archetype_component_access
.extend(self.a.archetype_component_access());
self.archetype_component_access
.extend(self.b.archetype_component_access());
}
fn check_change_tick(&mut self, change_tick: Tick) {
self.a.check_change_tick(change_tick);
self.b.check_change_tick(change_tick);
}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
let mut default_sets = self.a.default_system_sets();
default_sets.append(&mut self.b.default_system_sets());
default_sets
}
fn get_last_run(&self) -> Tick {
self.a.get_last_run()
}
fn set_last_run(&mut self, last_run: Tick) {
self.a.set_last_run(last_run);
self.b.set_last_run(last_run);
}
}
/// SAFETY: Both systems are read-only, so any system created by combining them will only read from the world.
unsafe impl<Func, A, B> ReadOnlySystem for CombinatorSystem<Func, A, B>
where
Func: Combine<A, B> + 'static,
A: ReadOnlySystem,
B: ReadOnlySystem,
{
}
impl<Func, A, B> Clone for CombinatorSystem<Func, A, B>
where
A: Clone,
B: Clone,
{
/// Clone the combined system. The cloned instance must be `.initialize()`d before it can run.
fn clone(&self) -> Self {
CombinatorSystem::new(self.a.clone(), self.b.clone(), self.name.clone())
}
}
/// An [`IntoSystem`] creating an instance of [`PipeSystem`].
pub struct IntoPipeSystem<A, B> {
a: A,
b: B,
}
impl<A, B> IntoPipeSystem<A, B> {
/// Creates a new [`IntoSystem`] that pipes two inner systems.
pub const fn new(a: A, b: B) -> Self {
Self { a, b }
}
}
#[doc(hidden)]
pub struct IsPipeSystemMarker;
impl<A, B, IA, OA, IB, OB, MA, MB> IntoSystem<IA, OB, (IsPipeSystemMarker, OA, IB, MA, MB)>
for IntoPipeSystem<A, B>
where
IA: SystemInput,
A: IntoSystem<IA, OA, MA>,
B: IntoSystem<IB, OB, MB>,
for<'a> IB: SystemInput<Inner<'a> = OA>,
{
type System = PipeSystem<A::System, B::System>;
fn into_system(this: Self) -> Self::System {
let system_a = IntoSystem::into_system(this.a);
let system_b = IntoSystem::into_system(this.b);
let name = format!("Pipe({}, {})", system_a.name(), system_b.name());
PipeSystem::new(system_a, system_b, Cow::Owned(name))
}
}
/// A [`System`] created by piping the output of the first system into the input of the second.
///
/// This can be repeated indefinitely, but system pipes cannot branch: the output is consumed by the receiving system.
///
/// Given two systems `A` and `B`, A may be piped into `B` as `A.pipe(B)` if the output type of `A` is
/// equal to the input type of `B`.
///
/// Note that for [`FunctionSystem`](crate::system::FunctionSystem)s the output is the return value
/// of the function and the input is the first [`SystemParam`](crate::system::SystemParam) if it is
/// tagged with [`In`](crate::system::In) or `()` if the function has no designated input parameter.
///
/// # Examples
///
/// ```
/// use std::num::ParseIntError;
///
/// use bevy_ecs::prelude::*;
///
/// fn main() {
/// let mut world = World::default();
/// world.insert_resource(Message("42".to_string()));
///
/// // pipe the `parse_message_system`'s output into the `filter_system`s input
/// let mut piped_system = IntoSystem::into_system(parse_message_system.pipe(filter_system));
/// piped_system.initialize(&mut world);
/// assert_eq!(piped_system.run((), &mut world), Some(42));
/// }
///
/// #[derive(Resource)]
/// struct Message(String);
///
/// fn parse_message_system(message: Res<Message>) -> Result<usize, ParseIntError> {
/// message.0.parse::<usize>()
/// }
///
/// fn filter_system(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
/// result.ok().filter(|&n| n < 100)
/// }
/// ```
pub struct PipeSystem<A, B> {
a: A,
b: B,
name: Cow<'static, str>,
component_access: Access<ComponentId>,
archetype_component_access: Access<ArchetypeComponentId>,
}
impl<A, B> PipeSystem<A, B>
where
A: System,
B: System,
for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
{
/// Creates a new system that pipes two inner systems.
pub const fn new(a: A, b: B, name: Cow<'static, str>) -> Self {
Self {
a,
b,
name,
component_access: Access::new(),
archetype_component_access: Access::new(),
}
}
}
impl<A, B> System for PipeSystem<A, B>
where
A: System,
B: System,
for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
{
type In = A::In;
type Out = B::Out;
fn name(&self) -> Cow<'static, str> {
self.name.clone()
}
fn component_access(&self) -> &Access<ComponentId> {
&self.component_access
}
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
&self.archetype_component_access
}
fn is_send(&self) -> bool {
self.a.is_send() && self.b.is_send()
}
fn is_exclusive(&self) -> bool {
self.a.is_exclusive() || self.b.is_exclusive()
}
fn has_deferred(&self) -> bool {
self.a.has_deferred() || self.b.has_deferred()
}
unsafe fn run_unsafe(
&mut self,
input: SystemIn<'_, Self>,
world: UnsafeWorldCell,
) -> Self::Out {
let value = self.a.run_unsafe(input, world);
self.b.run_unsafe(value, world)
}
fn apply_deferred(&mut self, world: &mut World) {
self.a.apply_deferred(world);
self.b.apply_deferred(world);
}
fn queue_deferred(&mut self, mut world: crate::world::DeferredWorld) {
self.a.queue_deferred(world.reborrow());
self.b.queue_deferred(world);
}
/// This method uses "early out" logic: if the first system fails validation,
/// the second system is not validated.
///
/// Because the system validation is performed upfront, this can lead to situations
/// where later systems pass validation, but fail at runtime due to changes made earlier
/// in the piped systems.
// TODO: ensure that systems are only validated just before they are run.
// Fixing this will require fundamentally rethinking how piped systems work:
// they're currently treated as a single system from the perspective of the scheduler.
// See https://github.com/bevyengine/bevy/issues/18796
unsafe fn validate_param_unsafe(
&mut self,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
// SAFETY: Delegate to the `System` implementation for `a`.
unsafe { self.a.validate_param_unsafe(world) }?;
// SAFETY: Delegate to the `System` implementation for `b`.
unsafe { self.b.validate_param_unsafe(world) }?;
Ok(())
}
fn initialize(&mut self, world: &mut World) {
self.a.initialize(world);
self.b.initialize(world);
self.component_access.extend(self.a.component_access());
self.component_access.extend(self.b.component_access());
}
fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
self.a.update_archetype_component_access(world);
self.b.update_archetype_component_access(world);
self.archetype_component_access
.extend(self.a.archetype_component_access());
self.archetype_component_access
.extend(self.b.archetype_component_access());
}
fn check_change_tick(&mut self, change_tick: Tick) {
self.a.check_change_tick(change_tick);
self.b.check_change_tick(change_tick);
}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
let mut default_sets = self.a.default_system_sets();
default_sets.append(&mut self.b.default_system_sets());
default_sets
}
fn get_last_run(&self) -> Tick {
self.a.get_last_run()
}
fn set_last_run(&mut self, last_run: Tick) {
self.a.set_last_run(last_run);
self.b.set_last_run(last_run);
}
}
/// SAFETY: Both systems are read-only, so any system created by piping them will only read from the world.
unsafe impl<A, B> ReadOnlySystem for PipeSystem<A, B>
where
A: ReadOnlySystem,
B: ReadOnlySystem,
for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
{
}
#[cfg(test)]
mod tests {
#[test]
fn exclusive_system_piping_is_possible() {
use crate::prelude::*;
fn my_exclusive_system(_world: &mut World) -> u32 {
1
}
fn out_pipe(input: In<u32>) {
assert!(input.0 == 1);
}
let mut world = World::new();
let mut schedule = Schedule::default();
schedule.add_systems(my_exclusive_system.pipe(out_pipe));
schedule.run(&mut world);
}
}

View File

@@ -0,0 +1,239 @@
//! Contains the definition of the [`Command`] trait,
//! as well as the blanket implementation of the trait for closures.
//!
//! It also contains functions that return closures for use with
//! [`Commands`](crate::system::Commands).
use crate::{
bundle::{Bundle, InsertMode, NoBundleEffect},
change_detection::MaybeLocation,
entity::Entity,
error::Result,
event::{Event, Events},
observer::TriggerTargets,
resource::Resource,
schedule::ScheduleLabel,
system::{IntoSystem, SystemId, SystemInput},
world::{FromWorld, SpawnBatchIter, World},
};
/// A [`World`] mutation.
///
/// Should be used with [`Commands::queue`](crate::system::Commands::queue).
///
/// The `Out` generic parameter is the returned "output" of the command.
///
/// # Usage
///
/// ```
/// # use bevy_ecs::prelude::*;
/// // Our world resource
/// #[derive(Resource, Default)]
/// struct Counter(u64);
///
/// // Our custom command
/// struct AddToCounter(u64);
///
/// impl Command for AddToCounter {
/// fn apply(self, world: &mut World) {
/// let mut counter = world.get_resource_or_insert_with(Counter::default);
/// counter.0 += self.0;
/// }
/// }
///
/// fn some_system(mut commands: Commands) {
/// commands.queue(AddToCounter(42));
/// }
/// ```
pub trait Command<Out = ()>: Send + 'static {
/// Applies this command, causing it to mutate the provided `world`.
///
/// This method is used to define what a command "does" when it is ultimately applied.
/// Because this method takes `self`, you can store data or settings on the type that implements this trait.
/// This data is set by the system or other source of the command, and then ultimately read in this method.
fn apply(self, world: &mut World) -> Out;
}
impl<F, Out> Command<Out> for F
where
F: FnOnce(&mut World) -> Out + Send + 'static,
{
fn apply(self, world: &mut World) -> Out {
self(world)
}
}
/// A [`Command`] that consumes an iterator of [`Bundles`](Bundle) to spawn a series of entities.
///
/// This is more efficient than spawning the entities individually.
#[track_caller]
pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
where
I: IntoIterator + Send + Sync + 'static,
I::Item: Bundle<Effect: NoBundleEffect>,
{
let caller = MaybeLocation::caller();
move |world: &mut World| {
SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);
}
}
/// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities.
///
/// If any entities do not exist in the world, this command will return a
/// [`TryInsertBatchError`](crate::world::error::TryInsertBatchError).
///
/// This is more efficient than inserting the bundles individually.
#[track_caller]
pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle<Effect: NoBundleEffect>,
{
let caller = MaybeLocation::caller();
move |world: &mut World| -> Result {
world.try_insert_batch_with_caller(batch, insert_mode, caller)?;
Ok(())
}
}
/// A [`Command`] that inserts a [`Resource`] into the world using a value
/// created with the [`FromWorld`] trait.
#[track_caller]
pub fn init_resource<R: Resource + FromWorld>() -> impl Command {
move |world: &mut World| {
world.init_resource::<R>();
}
}
/// A [`Command`] that inserts a [`Resource`] into the world.
#[track_caller]
pub fn insert_resource<R: Resource>(resource: R) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
world.insert_resource_with_caller(resource, caller);
}
}
/// A [`Command`] that removes a [`Resource`] from the world.
pub fn remove_resource<R: Resource>() -> impl Command {
move |world: &mut World| {
world.remove_resource::<R>();
}
}
/// A [`Command`] that runs the system corresponding to the given [`SystemId`].
pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command<Result> {
move |world: &mut World| -> Result {
world.run_system(id)?;
Ok(())
}
}
/// A [`Command`] that runs the system corresponding to the given [`SystemId`]
/// and provides the given input value.
pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command<Result>
where
I: SystemInput<Inner<'static>: Send> + 'static,
{
move |world: &mut World| -> Result {
world.run_system_with(id, input)?;
Ok(())
}
}
/// A [`Command`] that runs the given system,
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>
where
M: 'static,
S: IntoSystem<(), (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached(system)?;
Ok(())
}
}
/// A [`Command`] that runs the given system with the given input value,
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>
where
I: SystemInput<Inner<'static>: Send> + Send + 'static,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached_with(system, input)?;
Ok(())
}
}
/// A [`Command`] that removes a system previously registered with
/// [`Commands::register_system`](crate::system::Commands::register_system) or
/// [`World::register_system`].
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>
where
I: SystemInput + Send + 'static,
O: Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system(system_id)?;
Ok(())
}
}
/// A [`Command`] that removes a system previously registered with one of the following:
/// - [`Commands::run_system_cached`](crate::system::Commands::run_system_cached)
/// - [`World::run_system_cached`]
/// - [`World::register_system_cached`]
pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command<Result>
where
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system_cached(system)?;
Ok(())
}
}
/// A [`Command`] that runs the schedule corresponding to the given [`ScheduleLabel`].
pub fn run_schedule(label: impl ScheduleLabel) -> impl Command<Result> {
move |world: &mut World| -> Result {
world.try_run_schedule(label)?;
Ok(())
}
}
/// A [`Command`] that sends a global [`Trigger`](crate::observer::Trigger) without any targets.
#[track_caller]
pub fn trigger(event: impl Event) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
world.trigger_with_caller(event, caller);
}
}
/// A [`Command`] that sends a [`Trigger`](crate::observer::Trigger) for the given targets.
pub fn trigger_targets(
event: impl Event,
targets: impl TriggerTargets + Send + Sync + 'static,
) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
world.trigger_targets_with_caller(event, targets, caller);
}
}
/// A [`Command`] that sends an arbitrary [`Event`].
#[track_caller]
pub fn send_event<E: Event>(event: E) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
let mut events = world.resource_mut::<Events<E>>();
events.send_with_caller(event, caller);
}
}

View File

@@ -0,0 +1,282 @@
//! Contains the definition of the [`EntityCommand`] trait,
//! as well as the blanket implementation of the trait for closures.
//!
//! It also contains functions that return closures for use with
//! [`EntityCommands`](crate::system::EntityCommands).
use alloc::vec::Vec;
use log::info;
use crate::{
bundle::{Bundle, InsertMode},
change_detection::MaybeLocation,
component::{Component, ComponentId, ComponentInfo},
entity::{Entity, EntityClonerBuilder},
event::Event,
relationship::RelationshipHookMode,
system::IntoObserverSystem,
world::{error::EntityMutableFetchError, EntityWorldMut, FromWorld},
};
use bevy_ptr::OwningPtr;
/// A command which gets executed for a given [`Entity`].
///
/// Should be used with [`EntityCommands::queue`](crate::system::EntityCommands::queue).
///
/// The `Out` generic parameter is the returned "output" of the command.
///
/// # Examples
///
/// ```
/// # use std::collections::HashSet;
/// # use bevy_ecs::prelude::*;
/// use bevy_ecs::system::EntityCommand;
/// #
/// # #[derive(Component, PartialEq)]
/// # struct Name(String);
/// # impl Name {
/// # fn new(s: String) -> Self { Name(s) }
/// # fn as_str(&self) -> &str { &self.0 }
/// # }
///
/// #[derive(Resource, Default)]
/// struct Counter(i64);
///
/// /// A `Command` which names an entity based on a global counter.
/// fn count_name(mut entity: EntityWorldMut) {
/// // Get the current value of the counter, and increment it for next time.
/// let i = {
/// let mut counter = entity.resource_mut::<Counter>();
/// let i = counter.0;
/// counter.0 += 1;
/// i
/// };
/// // Name the entity after the value of the counter.
/// entity.insert(Name::new(format!("Entity #{i}")));
/// }
///
/// // App creation boilerplate omitted...
/// # let mut world = World::new();
/// # world.init_resource::<Counter>();
/// #
/// # let mut setup_schedule = Schedule::default();
/// # setup_schedule.add_systems(setup);
/// # let mut assert_schedule = Schedule::default();
/// # assert_schedule.add_systems(assert_names);
/// #
/// # setup_schedule.run(&mut world);
/// # assert_schedule.run(&mut world);
///
/// fn setup(mut commands: Commands) {
/// commands.spawn_empty().queue(count_name);
/// commands.spawn_empty().queue(count_name);
/// }
///
/// fn assert_names(named: Query<&Name>) {
/// // We use a HashSet because we do not care about the order.
/// let names: HashSet<_> = named.iter().map(Name::as_str).collect();
/// assert_eq!(names, HashSet::from_iter(["Entity #0", "Entity #1"]));
/// }
/// ```
pub trait EntityCommand<Out = ()>: Send + 'static {
/// Executes this command for the given [`Entity`].
fn apply(self, entity: EntityWorldMut) -> Out;
}
/// An error that occurs when running an [`EntityCommand`] on a specific entity.
#[derive(thiserror::Error, Debug)]
pub enum EntityCommandError<E> {
/// The entity this [`EntityCommand`] tried to run on could not be fetched.
#[error(transparent)]
EntityFetchError(#[from] EntityMutableFetchError),
/// An error that occurred while running the [`EntityCommand`].
#[error("{0}")]
CommandFailed(E),
}
impl<Out, F> EntityCommand<Out> for F
where
F: FnOnce(EntityWorldMut) -> Out + Send + 'static,
{
fn apply(self, entity: EntityWorldMut) -> Out {
self(entity)
}
}
/// An [`EntityCommand`] that adds the components in a [`Bundle`] to an entity.
#[track_caller]
pub fn insert(bundle: impl Bundle, mode: InsertMode) -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.insert_with_caller(bundle, mode, caller, RelationshipHookMode::Run);
}
}
/// An [`EntityCommand`] that adds a dynamic component to an entity.
///
/// # Safety
///
/// - [`ComponentId`] must be from the same world as the target entity.
/// - `T` must have the same layout as the one passed during `component_id` creation.
#[track_caller]
pub unsafe fn insert_by_id<T: Send + 'static>(
component_id: ComponentId,
value: T,
mode: InsertMode,
) -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
// SAFETY:
// - `component_id` safety is ensured by the caller
// - `ptr` is valid within the `make` block
OwningPtr::make(value, |ptr| unsafe {
entity.insert_by_id_with_caller(
component_id,
ptr,
mode,
caller,
RelationshipHookMode::Run,
);
});
}
}
/// An [`EntityCommand`] that adds a component to an entity using
/// the component's [`FromWorld`] implementation.
#[track_caller]
pub fn insert_from_world<T: Component + FromWorld>(mode: InsertMode) -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
let value = entity.world_scope(|world| T::from_world(world));
entity.insert_with_caller(value, mode, caller, RelationshipHookMode::Run);
}
}
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity.
#[track_caller]
pub fn remove<T: Bundle>() -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.remove_with_caller::<T>(caller);
}
}
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity,
/// as well as the required components for each component removed.
#[track_caller]
pub fn remove_with_requires<T: Bundle>() -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.remove_with_requires_with_caller::<T>(caller);
}
}
/// An [`EntityCommand`] that removes a dynamic component from an entity.
#[track_caller]
pub fn remove_by_id(component_id: ComponentId) -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.remove_by_id_with_caller(component_id, caller);
}
}
/// An [`EntityCommand`] that removes all components from an entity.
#[track_caller]
pub fn clear() -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.clear_with_caller(caller);
}
}
/// An [`EntityCommand`] that removes all components from an entity,
/// except for those in the given [`Bundle`].
#[track_caller]
pub fn retain<T: Bundle>() -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.retain_with_caller::<T>(caller);
}
}
/// An [`EntityCommand`] that despawns an entity.
///
/// # Note
///
/// This will also despawn the entities in any [`RelationshipTarget`](crate::relationship::RelationshipTarget)
/// that is configured to despawn descendants.
///
/// For example, this will recursively despawn [`Children`](crate::hierarchy::Children).
#[track_caller]
pub fn despawn() -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |entity: EntityWorldMut| {
entity.despawn_with_caller(caller);
}
}
/// An [`EntityCommand`] that creates an [`Observer`](crate::observer::Observer)
/// listening for events of type `E` targeting an entity
#[track_caller]
pub fn observe<E: Event, B: Bundle, M>(
observer: impl IntoObserverSystem<E, B, M>,
) -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
entity.observe_with_caller(observer, caller);
}
}
/// An [`EntityCommand`] that sends a [`Trigger`](crate::observer::Trigger) targeting an entity.
///
/// This will run any [`Observer`](crate::observer::Observer) of the given [`Event`] watching the entity.
#[track_caller]
pub fn trigger(event: impl Event) -> impl EntityCommand {
let caller = MaybeLocation::caller();
move |mut entity: EntityWorldMut| {
let id = entity.id();
entity.world_scope(|world| {
world.trigger_targets_with_caller(event, id, caller);
});
}
}
/// An [`EntityCommand`] that clones parts of an entity onto another entity,
/// configured through [`EntityClonerBuilder`].
pub fn clone_with(
target: Entity,
config: impl FnOnce(&mut EntityClonerBuilder) + Send + Sync + 'static,
) -> impl EntityCommand {
move |mut entity: EntityWorldMut| {
entity.clone_with(target, config);
}
}
/// An [`EntityCommand`] that clones the specified components of an entity
/// and inserts them into another entity.
pub fn clone_components<B: Bundle>(target: Entity) -> impl EntityCommand {
move |mut entity: EntityWorldMut| {
entity.clone_components::<B>(target);
}
}
/// An [`EntityCommand`] that clones the specified components of an entity
/// and inserts them into another entity, then removes them from the original entity.
pub fn move_components<B: Bundle>(target: Entity) -> impl EntityCommand {
move |mut entity: EntityWorldMut| {
entity.move_components::<B>(target);
}
}
/// An [`EntityCommand`] that logs the components of an entity.
pub fn log_components() -> impl EntityCommand {
move |entity: EntityWorldMut| {
let debug_infos: Vec<_> = entity
.world()
.inspect_entity(entity.id())
.expect("Entity existence is verified before an EntityCommand is executed")
.map(ComponentInfo::name)
.collect();
info!("Entity {}: {debug_infos:?}", entity.id());
}
}

2613
vendor/bevy_ecs/src/system/commands/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More