From 7c274e5a4465458a1917a0074fd3149601fa51a0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 22 Apr 2021 19:09:09 +0000 Subject: [PATCH] Improve bevy_ecs query docs (#1935) Mainly documents Query, WorldQuery and the various Query Filter types as well as some smaller doc changes. --- crates/bevy_ecs/src/component/mod.rs | 15 ++- crates/bevy_ecs/src/component/type_info.rs | 4 +- crates/bevy_ecs/src/entity/mod.rs | 38 +++--- crates/bevy_ecs/src/event.rs | 4 +- crates/bevy_ecs/src/query/access.rs | 16 +++ crates/bevy_ecs/src/query/fetch.rs | 147 +++++++++++++++------ crates/bevy_ecs/src/query/filter.rs | 137 ++++++++++++++++--- crates/bevy_ecs/src/query/iter.rs | 4 + crates/bevy_ecs/src/query/state.rs | 31 +++-- crates/bevy_ecs/src/system/query.rs | 95 +++++++++++++ crates/bevy_ecs/src/system/system_param.rs | 2 - 11 files changed, 396 insertions(+), 97 deletions(-) diff --git a/crates/bevy_ecs/src/component/mod.rs b/crates/bevy_ecs/src/component/mod.rs index e8fba0b62b..3ee166d9c0 100644 --- a/crates/bevy_ecs/src/component/mod.rs +++ b/crates/bevy_ecs/src/component/mod.rs @@ -10,19 +10,19 @@ use std::{ }; use thiserror::Error; -/// A component is data associated with an `Entity`. Each entity can have multiple different types -/// of components, but only one of them per type. +/// A component is data associated with an [`Entity`](crate::entity::Entity). Each entity can have +/// multiple different types of components, but only one of them per type. /// /// Any type that is `Send + Sync + 'static` automatically implements `Component`. /// -/// Components are added with new entities using [Commands::spawn](crate::system::Commands::spawn), -/// or to existing entities with [Commands::insert](crate::system::Commands::insert), -/// or their [World](crate::world::World) equivalents. +/// Components are added with new entities using [`Commands::spawn`](crate::system::Commands::spawn), +/// or to existing entities with [`EntityCommands::insert`](crate::system::EntityCommands::insert), +/// or their [`World`](crate::world::World) equivalents. /// -/// Components can be accessed in systems by using a [Query](crate::system::Query) +/// Components can be accessed in systems by using a [`Query`](crate::system::Query) /// as one of the arguments. /// -/// Components can be grouped together into a [Bundle](crate::bundle::Bundle). +/// Components can be grouped together into a [`Bundle`](crate::bundle::Bundle). pub trait Component: Send + Sync + 'static {} impl Component for T {} @@ -241,6 +241,7 @@ impl Components { } /// # Safety + /// /// `id` must be a valid [ComponentId] #[inline] pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo { diff --git a/crates/bevy_ecs/src/component/type_info.rs b/crates/bevy_ecs/src/component/type_info.rs index ca83036b4c..58839632f4 100644 --- a/crates/bevy_ecs/src/component/type_info.rs +++ b/crates/bevy_ecs/src/component/type_info.rs @@ -1,6 +1,6 @@ use std::{alloc::Layout, any::TypeId}; -/// Metadata required to store a component +/// Metadata required to store a component. #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeInfo { type_id: TypeId, @@ -11,7 +11,7 @@ pub struct TypeInfo { } impl TypeInfo { - /// Metadata for `T` + /// Metadata for `T`. pub fn of() -> Self { Self { type_id: TypeId::of::(), diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index cb1dda1a0e..a1fd3e4bf4 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -11,15 +11,15 @@ use std::{ sync::atomic::{AtomicI64, Ordering}, }; -/// Lightweight unique ID of an entity +/// Lightweight unique ID of an entity. /// -/// Obtained from [World::spawn](crate::world::World::spawn), typically via -/// [Commands::spawn](crate::system::Commands::spawn). Can be stored to refer to an entity in the +/// Obtained from [`World::spawn`](crate::world::World::spawn), typically via +/// [`Commands::spawn`](crate::system::Commands::spawn). Can be stored to refer to an entity in the /// future. /// /// `Entity` can be a part of a query, e.g. `Query<(Entity, &MyComponent)>`. /// Components of a specific entity can be accessed using -/// [Query::get](crate::system::Query::get) and related methods. +/// [`Query::get`](crate::system::Query::get) and related methods. #[derive(Clone, Copy, Hash, Eq, Ord, PartialEq, PartialOrd)] pub struct Entity { pub(crate) generation: u32, @@ -27,12 +27,12 @@ pub struct Entity { } impl Entity { - /// Creates a new entity reference with a generation of 0 + /// Creates a new entity reference with a generation of 0. pub fn new(id: u32) -> Entity { Entity { id, generation: 0 } } - /// Convert to a form convenient for passing outside of rust + /// Convert to a form convenient for passing outside of rust. /// /// Only useful for identifying entities within the same instance of an application. Do not use /// for serialization between runs. @@ -42,7 +42,7 @@ impl Entity { u64::from(self.generation) << 32 | u64::from(self.id) } - /// Reconstruct an `Entity` previously destructured with `to_bits` + /// Reconstruct an `Entity` previously destructured with [`Entity::to_bits`]. /// /// Only useful when applied to results from `to_bits` in the same instance of an application. pub fn from_bits(bits: u64) -> Self { @@ -52,7 +52,7 @@ impl Entity { } } - /// Return a transiently unique identifier + /// Return a transiently unique identifier. /// /// No two simultaneously-live entities share the same ID, but dead entities' IDs may collide /// with both live and dead entities. Useful for compactly representing entities within a @@ -87,7 +87,8 @@ impl SparseSetIndex for Entity { } } -/// An iterator returning a sequence of Entity values from `Entities::reserve_entities`. +/// An [`Iterator`] returning a sequence of [`Entity`] values from +/// [`Entities::reserve_entities`](crate::entity::Entities::reserve_entities). pub struct ReserveEntitiesIterator<'a> { // Metas, so we can recover the current generation for anything in the freelist. meta: &'a [EntityMeta], @@ -165,7 +166,7 @@ pub struct Entities { } impl Entities { - /// Reserve entity IDs concurrently + /// Reserve entity IDs concurrently. /// /// Storage for entity generation and location is lazily allocated by calling `flush`. pub fn reserve_entities(&self, count: u32) -> ReserveEntitiesIterator { @@ -207,7 +208,7 @@ impl Entities { } } - /// Reserve one entity ID concurrently + /// Reserve one entity ID concurrently. /// /// Equivalent to `self.reserve_entities(1).next().unwrap()`, but more efficient. pub fn reserve_entity(&self) -> Entity { @@ -240,7 +241,7 @@ impl Entities { ); } - /// Allocate an entity ID directly + /// Allocate an entity ID directly. /// /// Location should be written immediately. pub fn alloc(&mut self) -> Entity { @@ -261,7 +262,7 @@ impl Entities { } } - /// Allocate a specific entity ID, overwriting its generation + /// Allocate a specific entity ID, overwriting its generation. /// /// Returns the location of the entity currently using the given ID, if any. Location should be /// written immediately. @@ -293,7 +294,7 @@ impl Entities { loc } - /// Destroy an entity, allowing it to be reused + /// Destroy an entity, allowing it to be reused. /// /// Must not be called while reserved entities are awaiting `flush()`. pub fn free(&mut self, entity: Entity) -> Option { @@ -315,7 +316,7 @@ impl Entities { Some(loc) } - /// Ensure at least `n` allocations can succeed without reallocating + /// Ensure at least `n` allocations can succeed without reallocating. pub fn reserve(&mut self, additional: u32) { self.verify_flushed(); @@ -340,7 +341,7 @@ impl Entities { *self.free_cursor.get_mut() = 0; } - /// Access the location storage of an entity + /// Access the location storage of an entity. /// /// Must not be called on pending entities. pub fn get_mut(&mut self, entity: Entity) -> Option<&mut EntityLocation> { @@ -352,7 +353,7 @@ impl Entities { } } - /// Returns `Ok(Location { archetype: 0, index: undefined })` for pending entities + /// Returns `Ok(Location { archetype: 0, index: undefined })` for pending entities. pub fn get(&self, entity: Entity) -> Option { if (entity.id as usize) < self.meta.len() { let meta = &self.meta[entity.id as usize]; @@ -368,6 +369,7 @@ impl Entities { /// Panics if the given id would represent an index outside of `meta`. /// /// # Safety + /// /// Must only be called for currently allocated `id`s. pub unsafe fn resolve_unknown_gen(&self, id: u32) -> Entity { let meta_len = self.meta.len(); @@ -463,7 +465,7 @@ impl EntityMeta { }; } -/// A location of an entity in an archetype +/// A location of an entity in an archetype. #[derive(Copy, Clone, Debug)] pub struct EntityLocation { /// The archetype index diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index b4519b7ab7..889d9d22e8 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -69,7 +69,7 @@ enum State { /// /// [`Events::update_system`] is a system that does this, typically intialized automatically using /// [`AppBuilder::add_event`]. [EventReader]s are expected to read events from this collection at -/// least once per loop/frame. +/// 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 @@ -116,6 +116,8 @@ enum State { /// 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 [`AppBuilder::add_event`]. +/// +/// [`AppBuilder::add_event`]: https://docs.rs/bevy/*/bevy/app/struct.AppBuilder.html#method.add_event #[derive(Debug)] pub struct Events { events_a: Vec>, diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index f22b58d5de..dcf5c691c0 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -2,6 +2,9 @@ use crate::storage::SparseSetIndex; use fixedbitset::FixedBitSet; use std::marker::PhantomData; +/// `Access` keeps track of read and write accesses to values within a collection. +/// +/// This is used for ensuring systems are executed soundly. #[derive(Debug, Eq, PartialEq, Clone)] pub struct Access { reads_all: bool, @@ -28,11 +31,13 @@ impl Access { self.writes.grow(bits); } + /// Adds a read access for the given index. pub fn add_read(&mut self, index: T) { self.reads_and_writes.grow(index.sparse_set_index() + 1); self.reads_and_writes.insert(index.sparse_set_index()); } + /// Adds a write access for the given index. pub fn add_write(&mut self, index: T) { self.reads_and_writes.grow(index.sparse_set_index() + 1); self.writes.grow(index.sparse_set_index() + 1); @@ -40,6 +45,7 @@ impl Access { self.writes.insert(index.sparse_set_index()); } + /// Returns true if this `Access` contains a read access for the given index. pub fn has_read(&self, index: T) -> bool { if self.reads_all { true @@ -48,30 +54,39 @@ impl Access { } } + /// Returns true if this `Access` contains a write access for the given index. pub fn has_write(&self, index: T) -> bool { self.writes.contains(index.sparse_set_index()) } + /// Sets this `Access` to having read access for all indices. pub fn read_all(&mut self) { self.reads_all = true; } + /// Returns true if this `Access` has read access to all indices. pub fn reads_all(&self) -> bool { self.reads_all } + /// Clears all recorded accesses. pub fn clear(&mut self) { self.reads_all = false; self.reads_and_writes.clear(); self.writes.clear(); } + /// Extends this `Access` with another, copying all accesses of `other` into this. pub fn extend(&mut self, other: &Access) { self.reads_all = self.reads_all || other.reads_all; self.reads_and_writes.union_with(&other.reads_and_writes); self.writes.union_with(&other.writes); } + /// Returns true if this `Access` is compatible with `other`. + /// + /// Two `Access` instances are incompatible with each other if one `Access` has a write for + /// which the other also has a write or a read. pub fn is_compatible(&self, other: &Access) -> bool { if self.reads_all { 0 == other.writes.count_ones(..) @@ -83,6 +98,7 @@ impl Access { } } + /// Calculates conflicting accesses between this `Access` and `other`. pub fn get_conflicts(&self, other: &Access) -> Vec { let mut conflicts = FixedBitSet::default(); if self.reads_all { diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 0350651f68..480bf3e136 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -12,6 +12,32 @@ use std::{ ptr::{self, NonNull}, }; +/// Types that can be queried from a [`World`]. +/// +/// Notable types that implement this trait are `&T` and `&mut T` where `T` implements [`Component`], +/// allowing you to query for components immutably and mutably accordingly. +/// +/// See [`Query`](crate::system::Query) for a primer on queries. +/// +/// # Basic WorldQueries +/// +/// Here is a small list of the most important world queries to know about where `C` stands for a +/// [`Component`] and `WQ` stands for a [`WorldQuery`]: +/// - `&C`: Queries immutably for the component `C` +/// - `&mut C`: Queries mutably for the component `C` +/// - `Option`: Queries the inner WorldQuery `WQ` but instead of discarding the entity if the world +/// query fails it returns [`None`]. See [`Query`](crate::system::Query). +/// - `(WQ1, WQ2, ...)`: Queries all contained world queries allowing to query for more than one thing. +/// This is the `And` operator for filters. See [`Or`]. +/// - `ChangeTrackers`: See the docs of [`ChangeTrackers`]. +/// - [`Entity`]: Using the entity type as a world query will grant access to the entity that is +/// being queried for. See [`Entity`]. +/// +/// Bevy also offers a few filters like [`Added`](crate::query::Added), [`Changed`](crate::query::Changed), +/// [`With`](crate::query::With), [`Without`](crate::query::Without) and [`Or`]. +/// For more information on these consult the item's corresponding documentation. +/// +/// [`Or`]: crate::query::Or pub trait WorldQuery { type Fetch: for<'a> Fetch<'a, State = Self::State>; type State: FetchState; @@ -24,6 +50,7 @@ pub trait Fetch<'w>: Sized { /// Creates a new instance of this fetch. /// /// # Safety + /// /// `state` must have been initialized (via [FetchState::init]) using the same `world` passed in /// to this function. unsafe fn init( @@ -35,52 +62,58 @@ pub trait Fetch<'w>: Sized { /// 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, [Fetch::set_table] and [Fetch::table_fetch] - /// will be called for iterators If this returns false, [Fetch::set_archetype] and - /// [Fetch::archetype_fetch] will be called for iterators + /// for "dense" queries. If this returns true, [`Fetch::set_table`] and [`Fetch::table_fetch`] + /// will be called for iterators. If this returns false, [`Fetch::set_archetype`] and + /// [`Fetch::archetype_fetch`] will be called for iterators. fn is_dense(&self) -> bool; - /// Adjusts internal state to account for the next [Archetype]. This will always be called on - /// archetypes that match this [Fetch] + /// Adjusts internal state to account for the next [`Archetype`]. This will always be called on + /// archetypes that match this [`Fetch`]. /// /// # Safety - /// `archetype` and `tables` must be from the [World] [Fetch::init] was called on. `state` must + /// + /// `archetype` and `tables` must be from the [`World`] [`Fetch::init`] was called on. `state` must /// be the [Self::State] this was initialized with. unsafe fn set_archetype(&mut self, state: &Self::State, archetype: &Archetype, tables: &Tables); - /// Adjusts internal state to account for the next [Table]. This will always be called on tables - /// that match this [Fetch] + /// Adjusts internal state to account for the next [`Table`]. This will always be called on tables + /// that match this [`Fetch`]. /// /// # Safety - /// `table` must be from the [World] [Fetch::init] was called on. `state` must be the + /// + /// `table` must be from the [`World`] [`Fetch::init`] was called on. `state` must be the /// [Self::State] this was initialized with. unsafe fn set_table(&mut self, state: &Self::State, table: &Table); - /// Fetch [Self::Item] for the given `archetype_index` in the current [Archetype]. This must - /// always be called after [Fetch::set_archetype] with an `archetype_index` in the range of - /// the current [Archetype] + /// Fetch [`Self::Item`] for the given `archetype_index` in the current [`Archetype`]. This must + /// always be called after [`Fetch::set_archetype`] with an `archetype_index` in the range of + /// the current [`Archetype`] /// /// # Safety - /// Must always be called _after_ [Fetch::set_archetype]. `archetype_index` must be in the range + /// Must always be called _after_ [`Fetch::set_archetype`]. `archetype_index` must be in the range /// of the current archetype unsafe fn archetype_fetch(&mut self, archetype_index: usize) -> Self::Item; - /// Fetch [Self::Item] for the given `table_row` in the current [Table]. This must always be - /// called after [Fetch::set_table] with a `table_row` in the range of the current [Table] + /// Fetch [`Self::Item`] for the given `table_row` in the current [`Table`]. This must always be + /// called after [`Fetch::set_table`] with a `table_row` in the range of the current [`Table`] /// /// # Safety - /// Must always be called _after_ [Fetch::set_table]. `table_row` must be in the range of the + /// + /// Must always be called _after_ [`Fetch::set_table`]. `table_row` must be in the range of the /// current table unsafe fn table_fetch(&mut self, table_row: usize) -> Self::Item; } -/// State used to construct a Fetch. This will be cached inside QueryState, so it is best to move as -/// much data / computation here as possible to reduce the cost of constructing Fetch. -/// SAFETY: -/// Implementor must ensure that [FetchState::update_component_access] and -/// [FetchState::update_archetype_component_access] exactly reflects the results of -/// [FetchState::matches_archetype], [FetchState::matches_table], [Fetch::archetype_fetch], and -/// [Fetch::table_fetch] +/// State used to construct a 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 Fetch. +/// +/// # Safety +/// +/// Implementor must ensure that [`FetchState::update_component_access`] and +/// [`FetchState::update_archetype_component_access`] exactly reflects the results of +/// [`FetchState::matches_archetype`], [`FetchState::matches_table`], [`Fetch::archetype_fetch`], and +/// [`Fetch::table_fetch`]. pub unsafe trait FetchState: Send + Sync + Sized { fn init(world: &mut World) -> Self; fn update_component_access(&self, access: &mut FilteredAccess); @@ -101,16 +134,18 @@ impl WorldQuery for Entity { type State = EntityState; } +/// The [`Fetch`] of [`Entity`]. pub struct EntityFetch { entities: *const Entity, } -/// SAFE: access is read only +/// SAFETY: access is read only unsafe impl ReadOnlyFetch for EntityFetch {} +/// The [`FetchState`] of [`Entity`]. pub struct EntityState; -// SAFE: no component or archetype access +// SAFETY: no component or archetype access unsafe impl FetchState for EntityState { fn init(_world: &mut World) -> Self { Self @@ -187,13 +222,14 @@ impl WorldQuery for &T { type State = ReadState; } +/// The [`FetchState`] of `&T`. pub struct ReadState { component_id: ComponentId, storage_type: StorageType, marker: PhantomData, } -// SAFE: component access and archetype component access are properly updated to reflect that T is +// SAFETY: component access and archetype component access are properly updated to reflect that T is // read unsafe impl FetchState for ReadState { fn init(world: &mut World) -> Self { @@ -234,6 +270,7 @@ unsafe impl FetchState for ReadState { } } +/// The [`Fetch`] of `&T`. pub struct ReadFetch { storage_type: StorageType, table_components: NonNull, @@ -242,7 +279,7 @@ pub struct ReadFetch { sparse_set: *const ComponentSparseSet, } -/// SAFE: access is read only +/// SAFETY: access is read only unsafe impl ReadOnlyFetch for ReadFetch {} impl<'w, T: Component> Fetch<'w> for ReadFetch { @@ -333,6 +370,7 @@ impl WorldQuery for &mut T { type State = WriteState; } +/// The [`Fetch`] of `&mut T`. pub struct WriteFetch { storage_type: StorageType, table_components: NonNull, @@ -344,13 +382,14 @@ pub struct WriteFetch { change_tick: u32, } +/// The [`FetchState`] of `&mut T`. pub struct WriteState { component_id: ComponentId, storage_type: StorageType, marker: PhantomData, } -// SAFE: component access and archetype component access are properly updated to reflect that T is +// SAFETY: component access and archetype component access are properly updated to reflect that T is // written unsafe impl FetchState for WriteState { fn init(world: &mut World) -> Self { @@ -498,19 +537,21 @@ impl WorldQuery for Option { type State = OptionState; } +/// The [`Fetch`] of `Option`. pub struct OptionFetch { fetch: T, matches: bool, } -/// SAFE: OptionFetch is read only because T is read only +/// SAFETY: OptionFetch is read only because T is read only unsafe impl ReadOnlyFetch for OptionFetch {} +/// The [`FetchState`] of `Option`. pub struct OptionState { state: T, } -// SAFE: component access and archetype component access are properly updated according to the +// SAFETY: component access and archetype component access are properly updated according to the // internal Fetch unsafe impl FetchState for OptionState { fn init(world: &mut World) -> Self { @@ -604,7 +645,36 @@ impl<'w, T: Fetch<'w>> Fetch<'w> for OptionFetch { } } -/// Change trackers for component `T` +/// [`WorldQuery`] that tracks changes and additions for component `T`. +/// +/// Wraps a [`Component`] to track whether the component changed for the corresponding entities in +/// a query since the last time the system that includes these queries ran. +/// +/// If you only care about entities that changed or that got added use the +/// [`Changed`](crate::query::Changed) and [`Added`](crate::query::Added) filters instead. +/// +/// # Examples +/// +/// ``` +/// # use bevy_ecs::system::Query; +/// # use bevy_ecs::query::ChangeTrackers; +/// # use bevy_ecs::system::IntoSystem; +/// # +/// # #[derive(Debug)] +/// # struct Name {}; +/// # struct Transform {}; +/// # +/// fn print_moving_objects_system(query: Query<(&Name, ChangeTrackers)>) { +/// for (name, tracker) in query.iter() { +/// if tracker.is_changed() { +/// println!("Entity moved: {:?}", name); +/// } else { +/// println!("Entity stood still: {:?}", name); +/// } +/// } +/// } +/// # print_moving_objects_system.system(); +/// ``` #[derive(Clone)] pub struct ChangeTrackers { pub(crate) component_ticks: ComponentTicks, @@ -612,6 +682,7 @@ pub struct ChangeTrackers { pub(crate) change_tick: u32, marker: PhantomData, } + impl std::fmt::Debug for ChangeTrackers { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ChangeTrackers") @@ -623,13 +694,13 @@ impl std::fmt::Debug for ChangeTrackers { } impl ChangeTrackers { - /// Has this component been added since the last execution of this system. + /// Returns true if this component has been added since the last execution of this system. pub fn is_added(&self) -> bool { self.component_ticks .is_added(self.last_change_tick, self.change_tick) } - /// Has this component been changed since the last execution of this system. + /// Returns true if this component has been changed since the last execution of this system. pub fn is_changed(&self) -> bool { self.component_ticks .is_changed(self.last_change_tick, self.change_tick) @@ -641,13 +712,14 @@ impl WorldQuery for ChangeTrackers { type State = ChangeTrackersState; } +/// The [`FetchState`] of [`ChangeTrackers`]. pub struct ChangeTrackersState { component_id: ComponentId, storage_type: StorageType, marker: PhantomData, } -// SAFE: component access and archetype component access are properly updated to reflect that T is +// SAFETY: component access and archetype component access are properly updated to reflect that T is // read unsafe impl FetchState for ChangeTrackersState { fn init(world: &mut World) -> Self { @@ -688,6 +760,7 @@ unsafe impl FetchState for ChangeTrackersState { } } +/// The [`Fetch`] of [`ChangeTrackers`]. pub struct ChangeTrackersFetch { storage_type: StorageType, table_ticks: *const ComponentTicks, @@ -699,7 +772,7 @@ pub struct ChangeTrackersFetch { change_tick: u32, } -/// SAFE: access is read only +/// SAFETY: access is read only unsafe impl ReadOnlyFetch for ChangeTrackersFetch {} impl<'w, T: Component> Fetch<'w> for ChangeTrackersFetch { @@ -849,7 +922,7 @@ macro_rules! impl_tuple_fetch { } } - // SAFE: update_component_access and update_archetype_component_access are called for each item in the tuple + // SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple #[allow(non_snake_case)] unsafe impl<$($name: FetchState),*> FetchState for ($($name,)*) { fn init(_world: &mut World) -> Self { @@ -882,7 +955,7 @@ macro_rules! impl_tuple_fetch { type State = ($($name::State,)*); } - /// SAFE: each item in the tuple is read only + /// SAFETY: each item in the tuple is read only unsafe impl<$($name: ReadOnlyFetch),*> ReadOnlyFetch for ($($name,)*) {} }; diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index 4f4204ed90..f4a48a2633 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -21,17 +21,19 @@ use std::{marker::PhantomData, ptr}; // impl QueryFilter for T where T::Fetch: FilterFetch { // } -/// Fetch methods used by query filters. This trait exists to allow "short circuit" behaviors for -/// relevant query filter fetches. +/// Extension trait for [`Fetch`] containing methods used by query filters. +/// This trait exists to allow "short circuit" behaviors for relevant query filter fetches. pub trait FilterFetch: for<'a> Fetch<'a> { /// # Safety - /// Must always be called _after_ [Fetch::set_archetype]. `archetype_index` must be in the range - /// of the current archetype + /// + /// Must always be called _after_ [`Fetch::set_archetype`]. `archetype_index` must be in the range + /// of the current archetype. unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool; /// # Safety - /// Must always be called _after_ [Fetch::set_table]. `table_row` must be in the range of the - /// current table + /// + /// Must always be called _after_ [`Fetch::set_table`]. `table_row` must be in the range of the + /// current table. unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool; } @@ -50,7 +52,31 @@ where } } -/// Filter that selects entities with a component `T` +/// Filter that selects entities with a component `T`. +/// +/// This can be used in a [`Query`](crate::system::Query) if entities are required to have the +/// component `T` but you don't actually care about components value. +/// +/// This is the negation of [`Without`]. +/// +/// # Examples +/// +/// ``` +/// # use bevy_ecs::system::Query; +/// # use bevy_ecs::query::With; +/// # use bevy_ecs::system::IntoSystem; +/// # +/// # #[derive(Debug)] +/// # struct IsBeautiful {}; +/// # struct Name { name: &'static str }; +/// # +/// fn compliment_entity_system(query: Query<&Name, With>) { +/// for name in query.iter() { +/// println!("{} is looking lovely today!", name.name); +/// } +/// } +/// # compliment_entity_system.system(); +/// ``` pub struct With(PhantomData); impl WorldQuery for With { @@ -58,17 +84,20 @@ impl WorldQuery for With { type State = WithState; } +/// The [`Fetch`] of [`With`]. pub struct WithFetch { storage_type: StorageType, marker: PhantomData, } + +/// The [`FetchState`] of [`With`]. pub struct WithState { component_id: ComponentId, storage_type: StorageType, marker: PhantomData, } -// SAFE: no component access or archetype component access +// SAFETY: no component access or archetype component access unsafe impl FetchState for WithState { fn init(world: &mut World) -> Self { let component_info = world.components.get_or_insert_info::(); @@ -145,7 +174,28 @@ impl<'a, T: Component> Fetch<'a> for WithFetch { } } -/// Filter that selects entities without a component `T` +/// Filter that selects entities without a component `T`. +/// +/// This is the negation of [`With`]. +/// +/// # Examples +/// +/// ``` +/// # use bevy_ecs::system::Query; +/// # use bevy_ecs::query::Without; +/// # use bevy_ecs::system::IntoSystem; +/// # +/// # #[derive(Debug)] +/// # struct Permit; +/// # struct Name { name: &'static str }; +/// # +/// fn no_permit_system(query: Query<&Name, Without>) { +/// for name in query.iter() { +/// println!("{} has no permit!", name.name); +/// } +/// } +/// # no_permit_system.system(); +/// ``` pub struct Without(PhantomData); impl WorldQuery for Without { @@ -153,18 +203,20 @@ impl WorldQuery for Without { type State = WithoutState; } +/// The [`Fetch`] of [`Without`]. pub struct WithoutFetch { storage_type: StorageType, marker: PhantomData, } +/// The [`FetchState`] of [`Without`]. pub struct WithoutState { component_id: ComponentId, storage_type: StorageType, marker: PhantomData, } -// SAFE: no component access or archetype component access +// SAFETY: no component access or archetype component access unsafe impl FetchState for WithoutState { fn init(world: &mut World) -> Self { let component_info = world.components.get_or_insert_info::(); @@ -254,7 +306,7 @@ pub struct WithBundleState { marker: PhantomData, } -// SAFE: no component access or archetype component access +// SAFETY: no component access or archetype component access unsafe impl FetchState for WithBundleState { fn init(world: &mut World) -> Self { let bundle_info = world.bundles.init_info::(&mut world.components); @@ -336,7 +388,37 @@ impl<'a, T: Bundle> Fetch<'a> for WithBundleFetch { } } +/// A filter that tests if any of the given filters apply. +/// +/// This is useful for example if a system with multiple components in a query only wants to run +/// when one or more of the components have changed. +/// +/// The `And` equivalent to this filter is a [`prim@tuple`] testing that all the contained filters +/// apply instead. +/// +/// # Examples +/// +/// ``` +/// # use bevy_ecs::entity::Entity; +/// # use bevy_ecs::system::Query; +/// # use bevy_ecs::system::IntoSystem; +/// # use bevy_ecs::query::Changed; +/// # use bevy_ecs::query::Or; +/// # +/// # #[derive(Debug)] +/// # struct Color {}; +/// # struct Style {}; +/// # +/// fn print_cool_entity_system(query: Query, Changed