Improve bevy_ecs::system module docs (#1932)

This includes a lot of single line comments where either saying more wasn't helpful or due to me not knowing enough about things yet to be able to go more indepth. Proofreading is very much welcome.
This commit is contained in:
Lukas Wirth 2021-04-15 20:36:16 +00:00
parent 9657f58f6a
commit 0a6fee5d17
6 changed files with 297 additions and 65 deletions

View File

@ -7,17 +7,20 @@ use crate::{
use bevy_utils::tracing::debug; use bevy_utils::tracing::debug;
use std::marker::PhantomData; use std::marker::PhantomData;
/// A [World] mutation /// A [`World`] mutation.
pub trait Command: Send + Sync + 'static { pub trait Command: Send + Sync + 'static {
fn write(self: Box<Self>, world: &mut World); fn write(self: Box<Self>, world: &mut World);
} }
/// A queue of [`Command`]s.
#[derive(Default)] #[derive(Default)]
pub struct CommandQueue { pub struct CommandQueue {
commands: Vec<Box<dyn Command>>, commands: Vec<Box<dyn Command>>,
} }
impl CommandQueue { impl CommandQueue {
/// Execute the queued [`Command`]s in the world.
/// This clears the queue.
pub fn apply(&mut self, world: &mut World) { pub fn apply(&mut self, world: &mut World) {
world.flush(); world.flush();
for command in self.commands.drain(..) { for command in self.commands.drain(..) {
@ -25,24 +28,27 @@ impl CommandQueue {
} }
} }
/// Push a boxed [`Command`] onto the queue.
#[inline] #[inline]
pub fn push_boxed(&mut self, command: Box<dyn Command>) { pub fn push_boxed(&mut self, command: Box<dyn Command>) {
self.commands.push(command); self.commands.push(command);
} }
/// Push a [`Command`] onto the queue.
#[inline] #[inline]
pub fn push<T: Command>(&mut self, command: T) { pub fn push<T: Command>(&mut self, command: T) {
self.push_boxed(Box::new(command)); self.push_boxed(Box::new(command));
} }
} }
/// A list of commands that will be run to modify a `World` /// A list of commands that will be run to modify a [`World`].
pub struct Commands<'a> { pub struct Commands<'a> {
queue: &'a mut CommandQueue, queue: &'a mut CommandQueue,
entities: &'a Entities, entities: &'a Entities,
} }
impl<'a> Commands<'a> { impl<'a> Commands<'a> {
/// Create a new `Commands` from a queue and a world.
pub fn new(queue: &'a mut CommandQueue, world: &'a World) -> Self { pub fn new(queue: &'a mut CommandQueue, world: &'a World) -> Self {
Self { Self {
queue, queue,
@ -50,7 +56,7 @@ impl<'a> Commands<'a> {
} }
} }
/// Creates a new empty entity and returns an [EntityCommands] builder for it. /// Creates a new empty [`Entity`] and returns an [`EntityCommands`] builder for it.
/// ///
/// # Example /// # Example
/// ///
@ -80,10 +86,10 @@ impl<'a> Commands<'a> {
/// Creates a new entity with the components contained in `bundle`. /// Creates a new entity with the components contained in `bundle`.
/// ///
/// This returns an [EntityCommands] builder, which enables inserting more components and bundles /// This returns an [`EntityCommands`] builder, which enables inserting more components and bundles
/// using a "builder pattern". /// using a "builder pattern".
/// ///
/// Note that `bundle` is a [Bundle], which is a collection of components. [Bundle] is /// Note that `bundle` is a [`Bundle`], which is a collection of components. [`Bundle`] is
/// automatically implemented for tuples of components. You can also create your own bundle /// automatically implemented for tuples of components. You can also create your own bundle
/// types by deriving [`derive@Bundle`]. /// types by deriving [`derive@Bundle`].
/// ///
@ -124,7 +130,7 @@ impl<'a> Commands<'a> {
e e
} }
/// Returns an [EntityCommands] builder for the requested `entity`. /// Returns an [`EntityCommands`] builder for the requested [`Entity`].
/// ///
/// # Example /// # Example
/// ///
@ -160,39 +166,38 @@ impl<'a> Commands<'a> {
self.queue.push(SpawnBatch { bundles_iter }); self.queue.push(SpawnBatch { bundles_iter });
} }
/// See [World::insert_resource]. /// See [`World::insert_resource`].
pub fn insert_resource<T: Component>(&mut self, resource: T) { pub fn insert_resource<T: Component>(&mut self, resource: T) {
self.queue.push(InsertResource { resource }) self.queue.push(InsertResource { resource })
} }
/// Queue a resource removal.
pub fn remove_resource<T: Component>(&mut self) { pub fn remove_resource<T: Component>(&mut self) {
self.queue.push(RemoveResource::<T> { self.queue.push(RemoveResource::<T> {
phantom: PhantomData, phantom: PhantomData,
}); });
} }
/// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if /// Adds a command directly to the command list.
/// the type of `command` is statically known.
pub fn add<C: Command>(&mut self, command: C) { pub fn add<C: Command>(&mut self, command: C) {
self.queue.push(command); self.queue.push(command);
} }
} }
/// A list of commands that will be run to modify an [`Entity`].
pub struct EntityCommands<'a, 'b> { pub struct EntityCommands<'a, 'b> {
entity: Entity, entity: Entity,
commands: &'b mut Commands<'a>, commands: &'b mut Commands<'a>,
} }
impl<'a, 'b> EntityCommands<'a, 'b> { impl<'a, 'b> EntityCommands<'a, 'b> {
/// Retrieves the current entity's unique [Entity] id. /// Retrieves the current entity's unique [`Entity`] id.
#[inline] #[inline]
pub fn id(&self) -> Entity { pub fn id(&self) -> Entity {
self.entity self.entity
} }
/// Adds a bundle of components to the current entity. /// Adds a [`Bundle`] of components to the current entity.
///
/// See [`Self::with`], [`Self::current_entity`].
pub fn insert_bundle(&mut self, bundle: impl Bundle) -> &mut Self { pub fn insert_bundle(&mut self, bundle: impl Bundle) -> &mut Self {
self.commands.add(InsertBundle { self.commands.add(InsertBundle {
entity: self.entity, entity: self.entity,
@ -201,9 +206,8 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
self self
} }
/// Adds a single component to the current entity. /// Adds a single [`Component`] to the current entity.
/// ///
/// See [`Self::insert_bundle`], [`Self::id`].
/// ///
/// # Warning /// # Warning
/// ///
@ -214,7 +218,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
/// ///
/// # Example /// # Example
/// ///
/// [`Self::insert`] can be chained with [`Self::spawn`]. /// `Self::insert` can be chained with [`Commands::spawn`].
/// ///
/// ``` /// ```
/// use bevy_ecs::prelude::*; /// use bevy_ecs::prelude::*;
@ -242,7 +246,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
self self
} }
/// See [crate::world::EntityMut::remove_bundle]. /// See [`EntityMut::remove_bundle`](crate::world::EntityMut::remove_bundle).
pub fn remove_bundle<T>(&mut self) -> &mut Self pub fn remove_bundle<T>(&mut self) -> &mut Self
where where
T: Bundle, T: Bundle,
@ -254,7 +258,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
self self
} }
/// See [crate::world::EntityMut::remove]. /// See [`EntityMut::remove`](crate::world::EntityMut::remove).
pub fn remove<T>(&mut self) -> &mut Self pub fn remove<T>(&mut self) -> &mut Self
where where
T: Component, T: Component,
@ -273,6 +277,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
}) })
} }
/// Returns the underlying `[Commands]`.
pub fn commands(&mut self) -> &mut Commands<'a> { pub fn commands(&mut self) -> &mut Commands<'a> {
self.commands self.commands
} }
@ -323,7 +328,7 @@ impl Command for Despawn {
} }
} }
pub struct InsertBundle<T> { pub(crate) struct InsertBundle<T> {
entity: Entity, entity: Entity,
bundle: T, bundle: T,
} }
@ -388,7 +393,7 @@ where
} }
} }
pub struct InsertResource<T: Component> { pub(crate) struct InsertResource<T: Component> {
resource: T, resource: T,
} }
@ -398,7 +403,7 @@ impl<T: Component> Command for InsertResource<T> {
} }
} }
pub struct RemoveResource<T: Component> { pub(crate) struct RemoveResource<T: Component> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }

View File

@ -10,6 +10,7 @@ use crate::{
use bevy_ecs_macros::all_tuples; use bevy_ecs_macros::all_tuples;
use std::{borrow::Cow, marker::PhantomData}; use std::{borrow::Cow, marker::PhantomData};
/// The state of a [`System`].
pub struct SystemState { pub struct SystemState {
pub(crate) id: SystemId, pub(crate) id: SystemId,
pub(crate) name: Cow<'static, str>, pub(crate) name: Cow<'static, str>,
@ -33,18 +34,37 @@ impl SystemState {
} }
} }
/// Returns true if the system is [`Send`].
#[inline] #[inline]
pub fn is_send(&self) -> bool { pub fn is_send(&self) -> bool {
self.is_send self.is_send
} }
/// Sets the system to be not [`Send`].
///
/// This is irreversible.
#[inline] #[inline]
pub fn set_non_send(&mut self) { pub fn set_non_send(&mut self) {
self.is_send = false; self.is_send = false;
} }
} }
/// Conversion trait to turn something into a [`System`].
///
/// Use this to get a system from a function. Also note that every system implements this trait as well.
///
/// # Examples
///
/// ```
/// use bevy_ecs::system::IntoSystem;
/// use bevy_ecs::system::Res;
///
/// fn my_system_function(an_usize_resource: Res<usize>) {}
///
/// let system = my_system_function.system();
/// ```
pub trait IntoSystem<Params, SystemType: System> { pub trait IntoSystem<Params, SystemType: System> {
/// Turns this value into its corresponding [`System`].
fn system(self) -> SystemType; fn system(self) -> SystemType;
} }
@ -55,9 +75,40 @@ impl<Sys: System> IntoSystem<(), Sys> for Sys {
} }
} }
/// Wrapper type to mark a [`SystemParam`] as an input.
///
/// [`System`]s may take an optional input which they require to be passed to them when they
/// are being [`run`](System::run). For [`FunctionSystems`](FunctionSystem) the input may be marked
/// with this `In` type, but only the first param of a function may be tagged as an input. This also
/// means a system can only have one or zero input paramaters.
///
/// # Examples
///
/// Here is a simple example of a system that takes a [`usize`] returning the square of it.
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// fn main() {
/// let mut square_system = square.system();
///
/// let mut world = World::default();
/// square_system.initialize(&mut world);
/// assert_eq!(square_system.run(12, &mut world), 144);
/// }
///
/// fn square(In(input): In<usize>) -> usize {
/// input * input
/// }
/// ```
pub struct In<In>(pub In); pub struct In<In>(pub In);
pub struct InputMarker; pub struct InputMarker;
/// The [`System`] counter part of an ordinary function.
///
/// You get this by calling [`IntoSystem::system`] on a function that only accepts [`SystemParam`]s.
/// The output of the system becomes the functions return type, while the input becomes the functions
/// [`In`] tagged parameter or `()` if no such paramater exists.
pub struct FunctionSystem<In, Out, Param, Marker, F> pub struct FunctionSystem<In, Out, Param, Marker, F>
where where
Param: SystemParam, Param: SystemParam,
@ -71,6 +122,21 @@ where
} }
impl<In, Out, Param: SystemParam, Marker, F> FunctionSystem<In, Out, Param, Marker, F> { impl<In, Out, Param: SystemParam, Marker, F> FunctionSystem<In, Out, Param, Marker, F> {
/// Gives mutable access to the systems config via a callback. This is useful to set up system
/// [`Local`](crate::system::Local)s.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let world = &mut World::default();
/// fn local_is_42(local: Local<usize>) {
/// assert_eq!(*local, 42);
/// }
/// let mut system = local_is_42.system().config(|config| config.0 = Some(42));
/// system.initialize(world);
/// system.run((), world);
/// ```
pub fn config( pub fn config(
mut self, mut self,
f: impl FnOnce(&mut <Param::Fetch as SystemParamState>::Config), f: impl FnOnce(&mut <Param::Fetch as SystemParamState>::Config),
@ -180,6 +246,7 @@ where
} }
} }
/// A trait implemented for all functions that can be used as [`System`]s.
pub trait SystemParamFunction<In, Out, Param: SystemParam, Marker>: Send + Sync + 'static { pub trait SystemParamFunction<In, Out, Param: SystemParam, Marker>: Send + Sync + 'static {
fn run( fn run(
&mut self, &mut self,

View File

@ -10,7 +10,7 @@ use bevy_tasks::TaskPool;
use std::{any::TypeId, fmt::Debug}; use std::{any::TypeId, fmt::Debug};
use thiserror::Error; use thiserror::Error;
/// Provides scoped access to a World according to a given [WorldQuery] and query filter /// Provides scoped access to a [`World`] according to a given [`WorldQuery`] and query filter.
pub struct Query<'w, Q: WorldQuery, F: WorldQuery = ()> pub struct Query<'w, Q: WorldQuery, F: WorldQuery = ()>
where where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,
@ -25,9 +25,12 @@ impl<'w, Q: WorldQuery, F: WorldQuery> Query<'w, Q, F>
where where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,
{ {
/// Creates a new query.
///
/// # Safety /// # Safety
/// This will create a Query that could violate memory safety rules. Make sure that this is only ///
/// called in ways that ensure the Queries have unique mutable access. /// This will create a query that could violate memory safety rules. Make sure that this is only
/// called in ways that ensure the queries have unique mutable access.
#[inline] #[inline]
pub(crate) unsafe fn new( pub(crate) unsafe fn new(
world: &'w World, world: &'w World,
@ -43,7 +46,9 @@ where
} }
} }
/// Iterates over the query results. This can only be called for read-only queries /// Returns an [`Iterator`] over the query results.
///
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
#[inline] #[inline]
pub fn iter(&self) -> QueryIter<'_, '_, Q, F> pub fn iter(&self) -> QueryIter<'_, '_, Q, F>
where where
@ -57,7 +62,7 @@ where
} }
} }
/// Iterates over the query results /// Returns an [`Iterator`] over the query results.
#[inline] #[inline]
pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, F> { pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, F> {
// SAFE: system runs without conflicts with other systems. // SAFE: system runs without conflicts with other systems.
@ -68,11 +73,12 @@ where
} }
} }
/// Iterates over the query results /// Returns an [`Iterator`] over the query results.
/// ///
/// # Safety /// # Safety
/// This allows aliased mutability. You must make sure this call does not result in multiple ///
/// mutable references to the same component /// This function makes it possible to violate Rust's aliasing guarantees. You must make sure
/// this call does not result in multiple mutable references to the same component
#[inline] #[inline]
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, '_, Q, F> { pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, '_, Q, F> {
// SEMI-SAFE: system runs without conflicts with other systems. // SEMI-SAFE: system runs without conflicts with other systems.
@ -82,7 +88,9 @@ where
} }
/// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot /// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot
/// be chained like a normal iterator. This can only be called for read-only queries /// be chained like a normal [`Iterator`].
///
/// This can only be called for read-only queries, see [`Self::for_each_mut`] for write-queries.
#[inline] #[inline]
pub fn for_each(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item)) pub fn for_each(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item))
where where
@ -101,7 +109,7 @@ where
} }
/// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot /// Runs `f` on each query result. This is faster than the equivalent iter() method, but cannot
/// be chained like a normal iterator. /// be chained like a normal [`Iterator`].
#[inline] #[inline]
pub fn for_each_mut(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item)) { pub fn for_each_mut(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item)) {
// SAFE: system runs without conflicts with other systems. same-system queries have runtime // SAFE: system runs without conflicts with other systems. same-system queries have runtime
@ -117,6 +125,8 @@ where
} }
/// Runs `f` on each query result in parallel using the given task pool. /// Runs `f` on each query result in parallel using the given task pool.
///
/// This can only be called for read-only queries, see [`Self::par_for_each_mut`] for write-queries.
#[inline] #[inline]
pub fn par_for_each( pub fn par_for_each(
&self, &self,
@ -162,7 +172,9 @@ where
}; };
} }
/// Gets the query result for the given `entity` /// Gets the query result for the given [`Entity`].
///
/// This can only be called for read-only queries, see [`Self::get_mut`] for write-queries.
#[inline] #[inline]
pub fn get(&self, entity: Entity) -> Result<<Q::Fetch as Fetch>::Item, QueryEntityError> pub fn get(&self, entity: Entity) -> Result<<Q::Fetch as Fetch>::Item, QueryEntityError>
where where
@ -180,7 +192,7 @@ where
} }
} }
/// Gets the query result for the given `entity` /// Gets the query result for the given [`Entity`].
#[inline] #[inline]
pub fn get_mut( pub fn get_mut(
&mut self, &mut self,
@ -198,11 +210,12 @@ where
} }
} }
/// Gets the query result for the given `entity` /// Gets the query result for the given [`Entity`].
/// ///
/// # Safety /// # Safety
/// This allows aliased mutability. You must make sure this call does not result in multiple ///
/// mutable references to the same component /// This function makes it possible to violate Rust's aliasing guarantees. You must make sure
/// this call does not result in multiple mutable references to the same component
#[inline] #[inline]
pub unsafe fn get_unchecked( pub unsafe fn get_unchecked(
&self, &self,
@ -214,8 +227,8 @@ where
.get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick) .get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
} }
/// Gets a reference to the entity's component of the given type. This will fail if the entity /// Gets a reference to the [`Entity`]'s [`Component`] of the given type. This will fail if the
/// does not have the given component type or if the given component type does not match /// entity does not have the given component type or if the given component type does not match
/// this query. /// this query.
#[inline] #[inline]
pub fn get_component<T: Component>(&self, entity: Entity) -> Result<&T, QueryComponentError> { pub fn get_component<T: Component>(&self, entity: Entity) -> Result<&T, QueryComponentError> {
@ -244,8 +257,8 @@ where
} }
} }
/// Gets a mutable reference to the entity's component of the given type. This will fail if the /// Gets a mutable reference to the [`Entity`]'s [`Component`] of the given type. This will fail
/// entity does not have the given component type or if the given component type does not /// if the entity does not have the given component type or if the given component type does not
/// match this query. /// match this query.
#[inline] #[inline]
pub fn get_component_mut<T: Component>( pub fn get_component_mut<T: Component>(
@ -256,12 +269,13 @@ where
unsafe { self.get_component_unchecked_mut(entity) } unsafe { self.get_component_unchecked_mut(entity) }
} }
/// Gets a mutable reference to the entity's component of the given type. This will fail if the /// Gets a mutable reference to the [`Entity`]'s [`Component`] of the given type. This will fail
/// entity does not have the given component type or the component does not match the query. /// if the entity does not have the given component type or the component does not match the query.
/// ///
/// # Safety /// # Safety
/// This allows aliased mutability. You must make sure this call does not result in multiple ///
/// mutable references to the same component /// This function makes it possible to violate Rust's aliasing guarantees. You must make sure
/// this call does not result in multiple mutable references to the same component
#[inline] #[inline]
pub unsafe fn get_component_unchecked_mut<T: Component>( pub unsafe fn get_component_unchecked_mut<T: Component>(
&self, &self,
@ -292,11 +306,11 @@ where
} }
} }
/// Gets the result of a single-result query /// Gets the result of a single-result query.
/// ///
/// If the query has exactly one result, returns the result inside `Ok` /// If the query has exactly one result, returns the result inside `Ok`
/// otherwise returns either `Err(QuerySingleError::NoEntities(...))` /// otherwise returns either [`QuerySingleError::NoEntities`]
/// or `Err(QuerySingleError::MultipleEntities(...))`, as appropriate /// or [`QuerySingleError::MultipleEntities`], as appropriate.
/// ///
/// # Examples /// # Examples
/// ///
@ -319,6 +333,8 @@ where
/// } /// }
/// # let _check_that_its_a_system = player_scoring_system.system(); /// # let _check_that_its_a_system = player_scoring_system.system();
/// ``` /// ```
///
/// This can only be called for read-only queries, see [`Self::single_mut`] for write-queries.
pub fn single(&self) -> Result<<Q::Fetch as Fetch<'_>>::Item, QuerySingleError> pub fn single(&self) -> Result<<Q::Fetch as Fetch<'_>>::Item, QuerySingleError>
where where
Q::Fetch: ReadOnlyFetch, Q::Fetch: ReadOnlyFetch,
@ -336,7 +352,7 @@ where
} }
} }
/// See [`Query::single`] /// Gets the query result if it is only a single result, otherwise returns a [`QuerySingleError`].
pub fn single_mut(&mut self) -> Result<<Q::Fetch as Fetch<'_>>::Item, QuerySingleError> { pub fn single_mut(&mut self) -> Result<<Q::Fetch as Fetch<'_>>::Item, QuerySingleError> {
let mut query = self.iter_mut(); let mut query = self.iter_mut();
let first = query.next(); let first = query.next();
@ -352,7 +368,7 @@ where
} }
} }
/// An error that occurs when retrieving a specific [Entity]'s component from a [Query] /// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`]
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum QueryComponentError { pub enum QueryComponentError {
#[error("This query does not have read access to the requested component.")] #[error("This query does not have read access to the requested component.")]
@ -365,6 +381,8 @@ pub enum QueryComponentError {
NoSuchEntity, NoSuchEntity,
} }
/// An error that occurs when evaluating a [`Query`] as a single expected resulted via [`Query::single`]
/// or [`Query::single_mut`].
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum QuerySingleError { pub enum QuerySingleError {
#[error("No entities fit the query {0}")] #[error("No entities fit the query {0}")]

View File

@ -8,10 +8,12 @@ use crate::{
}; };
use std::borrow::Cow; use std::borrow::Cow;
/// A [`System`] identifier.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct SystemId(pub usize); pub struct SystemId(pub usize);
impl SystemId { impl SystemId {
/// Creates a new random `SystemId`.
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
pub fn new() -> Self { pub fn new() -> Self {
SystemId(rand::random::<usize>()) SystemId(rand::random::<usize>())
@ -29,29 +31,46 @@ impl SystemId {
/// It's possible to specify explicit execution order between specific systems, /// It's possible to specify explicit execution order between specific systems,
/// see [SystemDescriptor](crate::schedule::SystemDescriptor). /// see [SystemDescriptor](crate::schedule::SystemDescriptor).
pub trait System: Send + Sync + 'static { pub trait System: Send + Sync + 'static {
/// The system's input. See [`In`](crate::system::In) for [`FunctionSystem`](crate::system::FunctionSystem)s.
type In; type In;
/// The system's output.
type Out; type Out;
/// Returns the system's name.
fn name(&self) -> Cow<'static, str>; fn name(&self) -> Cow<'static, str>;
/// Returns the system's [`SystemId`].
fn id(&self) -> SystemId; fn id(&self) -> SystemId;
/// Register a new archetype for this system.
fn new_archetype(&mut self, archetype: &Archetype); fn new_archetype(&mut self, archetype: &Archetype);
/// Returns the system's component [`Access`].
fn component_access(&self) -> &Access<ComponentId>; fn component_access(&self) -> &Access<ComponentId>;
/// Returns the system's archetype component [`Access`].
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId>; fn archetype_component_access(&self) -> &Access<ArchetypeComponentId>;
/// Returns true if the system is [`Send`].
fn is_send(&self) -> bool; fn is_send(&self) -> bool;
/// Runs the system with the given input in the world. Unlike [`System::run`], this function
/// takes a shared reference to [`World`] and may therefore break Rust's aliasing rules, making
/// it unsafe to call.
///
/// # Safety /// # Safety
/// This might access World and Resources in an unsafe manner. This should only be called in one ///
/// of the following contexts: 1. This system is the only system running on the given World /// This might access world and resources in an unsafe manner. This should only be called in one
/// across all threads 2. This system only runs in parallel with other systems that do not /// of the following contexts:
/// conflict with the `archetype_component_access()` /// 1. This system is the only system running on the given world across all threads.
/// 2. This system only runs in parallel with other systems that do not conflict with the
/// [`System::archetype_component_access()`].
unsafe fn run_unsafe(&mut self, input: Self::In, world: &World) -> Self::Out; unsafe fn run_unsafe(&mut self, input: Self::In, world: &World) -> Self::Out;
/// Runs the system with the given input in the world.
fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out { fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out {
// SAFE: world and resources are exclusively borrowed // SAFE: world and resources are exclusively borrowed
unsafe { self.run_unsafe(input, world) } unsafe { self.run_unsafe(input, world) }
} }
fn apply_buffers(&mut self, world: &mut World); fn apply_buffers(&mut self, world: &mut World);
/// Initialize the system.
fn initialize(&mut self, _world: &mut World); fn initialize(&mut self, _world: &mut World);
fn check_change_tick(&mut self, change_tick: u32); fn check_change_tick(&mut self, change_tick: u32);
} }
/// A convenience type alias for a boxed [`System`] trait object.
pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>; pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>;
pub(crate) fn check_system_change_tick( pub(crate) fn check_system_change_tick(

View File

@ -7,6 +7,43 @@ use crate::{
}; };
use std::borrow::Cow; use std::borrow::Cow;
/// A [`System`] that chains two systems together, creating a new system that routes the output of
/// the first system into the input of the second system, yielding the output of the second system.
///
/// Given two systems A and B, A may be chained with B as `A.chain(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()));
///
/// // chain the `parse_message_system`'s output into the `filter_system`s input
/// let mut chained_system = parse_message_system.system().chain(filter_system.system());
/// chained_system.initialize(&mut world);
/// assert_eq!(chained_system.run((), &mut world), Some(42));
/// }
///
/// 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 ChainSystem<SystemA, SystemB> { pub struct ChainSystem<SystemA, SystemB> {
system_a: SystemA, system_a: SystemA,
system_b: SystemB, system_b: SystemB,
@ -75,10 +112,18 @@ impl<SystemA: System, SystemB: System<In = SystemA::Out>> System for ChainSystem
} }
} }
/// An extension trait providing the [`IntoChainSystem::chain`] method for convenient [`System`]
/// chaining.
///
/// This trait is blanket implemented for all system pairs that fulfill the chaining requirement.
///
/// See [`ChainSystem`].
pub trait IntoChainSystem<SystemB>: System + Sized pub trait IntoChainSystem<SystemB>: System + Sized
where where
SystemB: System<In = Self::Out>, SystemB: System<In = Self::Out>,
{ {
/// Chain this system `A` with another system `B` creating a new system that feeds system A's
/// output into system `B`, returning the output of system `B`.
fn chain(self, system: SystemB) -> ChainSystem<Self, SystemB>; fn chain(self, system: SystemB) -> ChainSystem<Self, SystemB>;
} }

View File

@ -14,10 +14,11 @@ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
}; };
/// A parameter that can be used in a system function /// A parameter that can be used in a [`System`](super::System).
/// ///
/// # Derive /// # Derive
/// This trait can be derived. ///
/// This trait can be derived with the [`derive@super::SystemParam`] macro.
/// ///
/// ``` /// ```
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
@ -36,9 +37,12 @@ pub trait SystemParam: Sized {
type Fetch: for<'a> SystemParamFetch<'a>; type Fetch: for<'a> SystemParamFetch<'a>;
} }
/// The state of a [`SystemParam`].
///
/// # Safety /// # Safety
///
/// It is the implementor's responsibility to ensure `system_state` is populated with the _exact_ /// It is the implementor's responsibility to ensure `system_state` is populated with the _exact_
/// [World] access used by the SystemParamState (and associated FetchSystemParam). /// [`World`] access used by the `SystemParamState` (and associated [`SystemParamFetch`]).
/// Additionally, it is the implementor's responsibility to ensure there is no /// Additionally, it is the implementor's responsibility to ensure there is no
/// conflicting access across all SystemParams. /// conflicting access across all SystemParams.
pub unsafe trait SystemParamState: Send + Sync + 'static { pub unsafe trait SystemParamState: Send + Sync + 'static {
@ -54,8 +58,9 @@ pub unsafe trait SystemParamState: Send + Sync + 'static {
pub trait SystemParamFetch<'a>: SystemParamState { pub trait SystemParamFetch<'a>: SystemParamState {
type Item; type Item;
/// # Safety /// # Safety
///
/// This call might access any of the input parameters in an unsafe way. Make sure the data /// This call might access any of the input parameters in an unsafe way. Make sure the data
/// access is safe in the context of the system scheduler /// access is safe in the context of the system scheduler.
unsafe fn get_param( unsafe fn get_param(
state: &'a mut Self, state: &'a mut Self,
system_state: &'a SystemState, system_state: &'a SystemState,
@ -153,11 +158,13 @@ pub struct QuerySetState<T>(T);
impl_query_set!(); impl_query_set!();
/// Shared borrow of a Resource /// Shared borrow of a resource.
/// ///
/// When used as a system parameter, panics if resource does not exist. /// # Panics
/// ///
/// Use `Option<Res<T>>` if the resource might not always exist. /// Panics when used as a [`SystemParameter`](SystemParam) if the resource does not exist.
///
/// Use `Option<Res<T>>` instead if the resource might not always exist.
pub struct Res<'w, T> { pub struct Res<'w, T> {
value: &'w T, value: &'w T,
ticks: &'w ComponentTicks, ticks: &'w ComponentTicks,
@ -188,6 +195,7 @@ impl<'w, T: Component> Deref for Res<'w, T> {
} }
} }
/// The [`SystemParamState`] of [`Res`].
pub struct ResState<T> { pub struct ResState<T> {
component_id: ComponentId, component_id: ComponentId,
marker: PhantomData<T>, marker: PhantomData<T>,
@ -256,6 +264,7 @@ impl<'a, T: Component> SystemParamFetch<'a> for ResState<T> {
} }
} }
/// The [`SystemParamState`] of `Option<Res<T>>`.
pub struct OptionResState<T>(ResState<T>); pub struct OptionResState<T>(ResState<T>);
impl<'a, T: Component> SystemParam for Option<Res<'a, T>> { impl<'a, T: Component> SystemParam for Option<Res<'a, T>> {
@ -293,11 +302,13 @@ impl<'a, T: Component> SystemParamFetch<'a> for OptionResState<T> {
} }
} }
/// Unique borrow of a Resource /// Unique borrow of a resource.
/// ///
/// When used as a system parameter, panics if resource does not exist. /// # Panics
/// ///
/// Use `Option<ResMut<T>>` if the resource might not always exist. /// Panics when used as a [`SystemParameter`](SystemParam) if the resource does not exist.
///
/// Use `Option<ResMut<T>>` instead if the resource might not always exist.
pub struct ResMut<'w, T> { pub struct ResMut<'w, T> {
value: &'w mut T, value: &'w mut T,
ticks: &'w mut ComponentTicks, ticks: &'w mut ComponentTicks,
@ -335,6 +346,7 @@ impl<'w, T: Component> DerefMut for ResMut<'w, T> {
} }
} }
/// The [`SystemParamState`] of [`ResMut`].
pub struct ResMutState<T> { pub struct ResMutState<T> {
component_id: ComponentId, component_id: ComponentId,
marker: PhantomData<T>, marker: PhantomData<T>,
@ -406,6 +418,7 @@ impl<'a, T: Component> SystemParamFetch<'a> for ResMutState<T> {
} }
} }
/// The [`SystemParamState`] of `Option<ResMut<T>>`.
pub struct OptionResMutState<T>(ResMutState<T>); pub struct OptionResMutState<T>(ResMutState<T>);
impl<'a, T: Component> SystemParam for Option<ResMut<'a, T>> { impl<'a, T: Component> SystemParam for Option<ResMut<'a, T>> {
@ -476,6 +489,32 @@ impl<'a> SystemParamFetch<'a> for CommandQueue {
} }
} }
/// A system local [`SystemParam`].
///
/// A local may only be accessed by the system itself and is therefore not visible to other systems.
/// If two or more systems specify the same local type each will have their own unique local.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # let world = &mut World::default();
/// fn write_to_local(mut local: Local<usize>) {
/// *local = 42;
/// }
/// fn read_from_local(local: Local<usize>) -> usize {
/// *local
/// }
/// let mut write_system = write_to_local.system();
/// let mut read_system = read_from_local.system();
/// write_system.initialize(world);
/// read_system.initialize(world);
///
/// assert_eq!(read_system.run((), world), 0);
/// write_system.run((), world);
/// // Note how the read local is still 0 due to the locals not being shared.
/// assert_eq!(read_system.run((), world), 0);
/// ```
pub struct Local<'a, T: Component>(&'a mut T); pub struct Local<'a, T: Component>(&'a mut T);
impl<'a, T: Component> Deref for Local<'a, T> { impl<'a, T: Component> Deref for Local<'a, T> {
@ -494,6 +533,7 @@ impl<'a, T: Component> DerefMut for Local<'a, T> {
} }
} }
/// The [`SystemParamState`] of [`Local`].
pub struct LocalState<T: Component>(T); pub struct LocalState<T: Component>(T);
impl<'a, T: Component + FromWorld> SystemParam for Local<'a, T> { impl<'a, T: Component + FromWorld> SystemParam for Local<'a, T> {
@ -527,6 +567,17 @@ impl<'a, T: Component + FromWorld> SystemParamFetch<'a> for LocalState<T> {
} }
} }
/// A [`SystemParam`] that grants access to the entities that had their `T` [`Component`] removed.
///
/// # Examples
///
/// Basic usage:
///
/// ```ignore
/// fn react_on_removal(removed: RemovedComponents<MyComponent>) {
/// removed.iter().for_each(|removed_entity| println!("{}", removed_entity));
/// }
/// ```
pub struct RemovedComponents<'a, T> { pub struct RemovedComponents<'a, T> {
world: &'a World, world: &'a World,
component_id: ComponentId, component_id: ComponentId,
@ -534,11 +585,13 @@ pub struct RemovedComponents<'a, T> {
} }
impl<'a, T> RemovedComponents<'a, T> { impl<'a, T> RemovedComponents<'a, T> {
/// Returns an iterator over the entities that had their `T` [`Component`] removed.
pub fn iter(&self) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> { pub fn iter(&self) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> {
self.world.removed_with_id(self.component_id) self.world.removed_with_id(self.component_id)
} }
} }
/// The [`SystemParamState`] of [`RemovedComponents`].
pub struct RemovedComponentsState<T> { pub struct RemovedComponentsState<T> {
component_id: ComponentId, component_id: ComponentId,
marker: PhantomData<T>, marker: PhantomData<T>,
@ -581,7 +634,16 @@ impl<'a, T: Component> SystemParamFetch<'a> for RemovedComponentsState<T> {
} }
} }
/// Shared borrow of a NonSend resource /// Shared borrow of a non-[`Send`] resource.
///
/// Only `Send` resources may be accessed with the [`Res`] [`SystemParam`]. In case that the
/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
/// over to another thread.
///
/// # Panics
///
/// Panics when used as a `SystemParameter` if the resource does not exist.
pub struct NonSend<'w, T> { pub struct NonSend<'w, T> {
pub(crate) value: &'w T, pub(crate) value: &'w T,
ticks: ComponentTicks, ticks: ComponentTicks,
@ -612,6 +674,7 @@ impl<'w, T: 'static> Deref for NonSend<'w, T> {
} }
} }
/// The [`SystemParamState`] of [`NonSend`].
pub struct NonSendState<T> { pub struct NonSendState<T> {
component_id: ComponentId, component_id: ComponentId,
marker: PhantomData<fn() -> T>, marker: PhantomData<fn() -> T>,
@ -682,7 +745,16 @@ impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState<T> {
} }
} }
/// Unique borrow of a NonSend resource /// Unique borrow of a non-[`Send`] resource.
///
/// Only `Send` resources may be accessed with the [`ResMut`] [`SystemParam`]. In case that the
/// resource does not implement `Send`, this `SystemParam` wrapper can be used. This will instruct
/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
/// over to another thread.
///
/// # Panics
///
/// Panics when used as a `SystemParameter` if the resource does not exist.
pub struct NonSendMut<'a, T: 'static> { pub struct NonSendMut<'a, T: 'static> {
pub(crate) value: &'a mut T, pub(crate) value: &'a mut T,
ticks: &'a mut ComponentTicks, ticks: &'a mut ComponentTicks,
@ -728,6 +800,7 @@ impl<'a, T: 'static + core::fmt::Debug> core::fmt::Debug for NonSendMut<'a, T> {
} }
} }
/// The [`SystemParamState`] of [`NonSendMut`].
pub struct NonSendMutState<T> { pub struct NonSendMutState<T> {
component_id: ComponentId, component_id: ComponentId,
marker: PhantomData<fn() -> T>, marker: PhantomData<fn() -> T>,
@ -808,6 +881,7 @@ impl<'a> SystemParam for &'a Archetypes {
type Fetch = ArchetypesState; type Fetch = ArchetypesState;
} }
/// The [`SystemParamState`] of [`Archetypes`].
pub struct ArchetypesState; pub struct ArchetypesState;
// SAFE: no component value access // SAFE: no component value access
@ -839,6 +913,7 @@ impl<'a> SystemParam for &'a Components {
type Fetch = ComponentsState; type Fetch = ComponentsState;
} }
/// The [`SystemParamState`] of [`Components`].
pub struct ComponentsState; pub struct ComponentsState;
// SAFE: no component value access // SAFE: no component value access
@ -870,6 +945,7 @@ impl<'a> SystemParam for &'a Entities {
type Fetch = EntitiesState; type Fetch = EntitiesState;
} }
/// The [`SystemParamState`] of [`Entities`].
pub struct EntitiesState; pub struct EntitiesState;
// SAFE: no component value access // SAFE: no component value access
@ -901,6 +977,7 @@ impl<'a> SystemParam for &'a Bundles {
type Fetch = BundlesState; type Fetch = BundlesState;
} }
/// The [`SystemParamState`] of [`Bundles`].
pub struct BundlesState; pub struct BundlesState;
// SAFE: no component value access // SAFE: no component value access
@ -938,6 +1015,7 @@ impl SystemParam for SystemChangeTick {
type Fetch = SystemChangeTickState; type Fetch = SystemChangeTickState;
} }
/// The [`SystemParamState`] of [`SystemChangeTickState`].
pub struct SystemChangeTickState {} pub struct SystemChangeTickState {}
unsafe impl SystemParamState for SystemChangeTickState { unsafe impl SystemParamState for SystemChangeTickState {