mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
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:
parent
9657f58f6a
commit
0a6fee5d17
6 changed files with 297 additions and 65 deletions
|
@ -7,17 +7,20 @@ use crate::{
|
|||
use bevy_utils::tracing::debug;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A [World] mutation
|
||||
/// A [`World`] mutation.
|
||||
pub trait Command: Send + Sync + 'static {
|
||||
fn write(self: Box<Self>, world: &mut World);
|
||||
}
|
||||
|
||||
/// A queue of [`Command`]s.
|
||||
#[derive(Default)]
|
||||
pub struct CommandQueue {
|
||||
commands: Vec<Box<dyn Command>>,
|
||||
}
|
||||
|
||||
impl CommandQueue {
|
||||
/// Execute the queued [`Command`]s in the world.
|
||||
/// This clears the queue.
|
||||
pub fn apply(&mut self, world: &mut World) {
|
||||
world.flush();
|
||||
for command in self.commands.drain(..) {
|
||||
|
@ -25,24 +28,27 @@ impl CommandQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Push a boxed [`Command`] onto the queue.
|
||||
#[inline]
|
||||
pub fn push_boxed(&mut self, command: Box<dyn Command>) {
|
||||
self.commands.push(command);
|
||||
}
|
||||
|
||||
/// Push a [`Command`] onto the queue.
|
||||
#[inline]
|
||||
pub fn push<T: Command>(&mut self, command: T) {
|
||||
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> {
|
||||
queue: &'a mut CommandQueue,
|
||||
entities: &'a Entities,
|
||||
}
|
||||
|
||||
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 {
|
||||
Self {
|
||||
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
|
||||
///
|
||||
|
@ -80,10 +86,10 @@ impl<'a> Commands<'a> {
|
|||
|
||||
/// 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".
|
||||
///
|
||||
/// 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
|
||||
/// types by deriving [`derive@Bundle`].
|
||||
///
|
||||
|
@ -124,7 +130,7 @@ impl<'a> Commands<'a> {
|
|||
e
|
||||
}
|
||||
|
||||
/// Returns an [EntityCommands] builder for the requested `entity`.
|
||||
/// Returns an [`EntityCommands`] builder for the requested [`Entity`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -160,39 +166,38 @@ impl<'a> Commands<'a> {
|
|||
self.queue.push(SpawnBatch { bundles_iter });
|
||||
}
|
||||
|
||||
/// See [World::insert_resource].
|
||||
/// See [`World::insert_resource`].
|
||||
pub fn insert_resource<T: Component>(&mut self, resource: T) {
|
||||
self.queue.push(InsertResource { resource })
|
||||
}
|
||||
|
||||
/// Queue a resource removal.
|
||||
pub fn remove_resource<T: Component>(&mut self) {
|
||||
self.queue.push(RemoveResource::<T> {
|
||||
phantom: PhantomData,
|
||||
});
|
||||
}
|
||||
|
||||
/// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if
|
||||
/// the type of `command` is statically known.
|
||||
/// Adds a command directly to the command list.
|
||||
pub fn add<C: Command>(&mut self, command: C) {
|
||||
self.queue.push(command);
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of commands that will be run to modify an [`Entity`].
|
||||
pub struct EntityCommands<'a, 'b> {
|
||||
entity: Entity,
|
||||
commands: &'b mut Commands<'a>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> EntityCommands<'a, 'b> {
|
||||
/// Retrieves the current entity's unique [Entity] id.
|
||||
/// Retrieves the current entity's unique [`Entity`] id.
|
||||
#[inline]
|
||||
pub fn id(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
/// Adds a bundle of components to the current entity.
|
||||
///
|
||||
/// See [`Self::with`], [`Self::current_entity`].
|
||||
/// Adds a [`Bundle`] of components to the current entity.
|
||||
pub fn insert_bundle(&mut self, bundle: impl Bundle) -> &mut Self {
|
||||
self.commands.add(InsertBundle {
|
||||
entity: self.entity,
|
||||
|
@ -201,9 +206,8 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Adds a single component to the current entity.
|
||||
/// Adds a single [`Component`] to the current entity.
|
||||
///
|
||||
/// See [`Self::insert_bundle`], [`Self::id`].
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
|
@ -214,7 +218,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// [`Self::insert`] can be chained with [`Self::spawn`].
|
||||
/// `Self::insert` can be chained with [`Commands::spawn`].
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_ecs::prelude::*;
|
||||
|
@ -242,7 +246,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
|
|||
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
|
||||
where
|
||||
T: Bundle,
|
||||
|
@ -254,7 +258,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
|
|||
self
|
||||
}
|
||||
|
||||
/// See [crate::world::EntityMut::remove].
|
||||
/// See [`EntityMut::remove`](crate::world::EntityMut::remove).
|
||||
pub fn remove<T>(&mut self) -> &mut Self
|
||||
where
|
||||
T: Component,
|
||||
|
@ -273,6 +277,7 @@ impl<'a, 'b> EntityCommands<'a, 'b> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns the underlying `[Commands]`.
|
||||
pub fn commands(&mut self) -> &mut Commands<'a> {
|
||||
self.commands
|
||||
}
|
||||
|
@ -323,7 +328,7 @@ impl Command for Despawn {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct InsertBundle<T> {
|
||||
pub(crate) struct InsertBundle<T> {
|
||||
entity: Entity,
|
||||
bundle: T,
|
||||
}
|
||||
|
@ -388,7 +393,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub struct InsertResource<T: Component> {
|
||||
pub(crate) struct InsertResource<T: Component> {
|
||||
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>,
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
use bevy_ecs_macros::all_tuples;
|
||||
use std::{borrow::Cow, marker::PhantomData};
|
||||
|
||||
/// The state of a [`System`].
|
||||
pub struct SystemState {
|
||||
pub(crate) id: SystemId,
|
||||
pub(crate) name: Cow<'static, str>,
|
||||
|
@ -33,18 +34,37 @@ impl SystemState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the system is [`Send`].
|
||||
#[inline]
|
||||
pub fn is_send(&self) -> bool {
|
||||
self.is_send
|
||||
}
|
||||
|
||||
/// Sets the system to be not [`Send`].
|
||||
///
|
||||
/// This is irreversible.
|
||||
#[inline]
|
||||
pub fn set_non_send(&mut self) {
|
||||
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> {
|
||||
/// Turns this value into its corresponding [`System`].
|
||||
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 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>
|
||||
where
|
||||
Param: SystemParam,
|
||||
|
@ -71,6 +122,21 @@ where
|
|||
}
|
||||
|
||||
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(
|
||||
mut self,
|
||||
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 {
|
||||
fn run(
|
||||
&mut self,
|
||||
|
|
|
@ -10,7 +10,7 @@ use bevy_tasks::TaskPool;
|
|||
use std::{any::TypeId, fmt::Debug};
|
||||
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 = ()>
|
||||
where
|
||||
F::Fetch: FilterFetch,
|
||||
|
@ -25,9 +25,12 @@ impl<'w, Q: WorldQuery, F: WorldQuery> Query<'w, Q, F>
|
|||
where
|
||||
F::Fetch: FilterFetch,
|
||||
{
|
||||
/// Creates a new query.
|
||||
///
|
||||
/// # 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]
|
||||
pub(crate) unsafe fn new(
|
||||
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]
|
||||
pub fn iter(&self) -> QueryIter<'_, '_, Q, F>
|
||||
where
|
||||
|
@ -57,7 +62,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Iterates over the query results
|
||||
/// Returns an [`Iterator`] over the query results.
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, F> {
|
||||
// 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
|
||||
/// 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]
|
||||
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, '_, Q, F> {
|
||||
// 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
|
||||
/// 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]
|
||||
pub fn for_each(&self, f: impl FnMut(<Q::Fetch as Fetch<'w>>::Item))
|
||||
where
|
||||
|
@ -101,7 +109,7 @@ where
|
|||
}
|
||||
|
||||
/// 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]
|
||||
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
|
||||
|
@ -117,6 +125,8 @@ where
|
|||
}
|
||||
|
||||
/// 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]
|
||||
pub fn par_for_each(
|
||||
&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]
|
||||
pub fn get(&self, entity: Entity) -> Result<<Q::Fetch as Fetch>::Item, QueryEntityError>
|
||||
where
|
||||
|
@ -180,7 +192,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the query result for the given `entity`
|
||||
/// Gets the query result for the given [`Entity`].
|
||||
#[inline]
|
||||
pub fn get_mut(
|
||||
&mut self,
|
||||
|
@ -198,11 +210,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the query result for the given `entity`
|
||||
/// Gets the query result for the given [`Entity`].
|
||||
///
|
||||
/// # 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]
|
||||
pub unsafe fn get_unchecked(
|
||||
&self,
|
||||
|
@ -214,8 +227,8 @@ where
|
|||
.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
|
||||
/// does not have the given component type or if the given component type does not match
|
||||
/// Gets a reference to the [`Entity`]'s [`Component`] of the given type. This will fail if the
|
||||
/// entity does not have the given component type or if the given component type does not match
|
||||
/// this query.
|
||||
#[inline]
|
||||
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
|
||||
/// entity does not have the given component type or if the given component type does not
|
||||
/// Gets a mutable reference to the [`Entity`]'s [`Component`] of the given type. This will fail
|
||||
/// if the entity does not have the given component type or if the given component type does not
|
||||
/// match this query.
|
||||
#[inline]
|
||||
pub fn get_component_mut<T: Component>(
|
||||
|
@ -256,12 +269,13 @@ where
|
|||
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
|
||||
/// entity does not have the given component type or the component does not match the query.
|
||||
/// Gets a mutable reference to the [`Entity`]'s [`Component`] of the given type. This will fail
|
||||
/// if the entity does not have the given component type or the component does not match the query.
|
||||
///
|
||||
/// # 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]
|
||||
pub unsafe fn get_component_unchecked_mut<T: Component>(
|
||||
&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`
|
||||
/// otherwise returns either `Err(QuerySingleError::NoEntities(...))`
|
||||
/// or `Err(QuerySingleError::MultipleEntities(...))`, as appropriate
|
||||
/// otherwise returns either [`QuerySingleError::NoEntities`]
|
||||
/// or [`QuerySingleError::MultipleEntities`], as appropriate.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -319,6 +333,8 @@ where
|
|||
/// }
|
||||
/// # 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>
|
||||
where
|
||||
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> {
|
||||
let mut query = self.iter_mut();
|
||||
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)]
|
||||
pub enum QueryComponentError {
|
||||
#[error("This query does not have read access to the requested component.")]
|
||||
|
@ -365,6 +381,8 @@ pub enum QueryComponentError {
|
|||
NoSuchEntity,
|
||||
}
|
||||
|
||||
/// An error that occurs when evaluating a [`Query`] as a single expected resulted via [`Query::single`]
|
||||
/// or [`Query::single_mut`].
|
||||
#[derive(Debug, Error)]
|
||||
pub enum QuerySingleError {
|
||||
#[error("No entities fit the query {0}")]
|
||||
|
|
|
@ -8,10 +8,12 @@ use crate::{
|
|||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// A [`System`] identifier.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct SystemId(pub usize);
|
||||
|
||||
impl SystemId {
|
||||
/// Creates a new random `SystemId`.
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
SystemId(rand::random::<usize>())
|
||||
|
@ -29,29 +31,46 @@ impl SystemId {
|
|||
/// It's possible to specify explicit execution order between specific systems,
|
||||
/// see [SystemDescriptor](crate::schedule::SystemDescriptor).
|
||||
pub trait System: Send + Sync + 'static {
|
||||
/// The system's input. See [`In`](crate::system::In) for [`FunctionSystem`](crate::system::FunctionSystem)s.
|
||||
type In;
|
||||
/// The system's output.
|
||||
type Out;
|
||||
/// Returns the system's name.
|
||||
fn name(&self) -> Cow<'static, str>;
|
||||
/// Returns the system's [`SystemId`].
|
||||
fn id(&self) -> SystemId;
|
||||
/// Register a new archetype for this system.
|
||||
fn new_archetype(&mut self, archetype: &Archetype);
|
||||
/// Returns the system's component [`Access`].
|
||||
fn component_access(&self) -> &Access<ComponentId>;
|
||||
/// Returns the system's archetype component [`Access`].
|
||||
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId>;
|
||||
/// Returns true if the system is [`Send`].
|
||||
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
|
||||
/// 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
|
||||
/// across all threads 2. This system only runs in parallel with other systems that do not
|
||||
/// conflict with the `archetype_component_access()`
|
||||
///
|
||||
/// 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 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;
|
||||
/// Runs the system with the given input in the world.
|
||||
fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out {
|
||||
// SAFE: world and resources are exclusively borrowed
|
||||
unsafe { self.run_unsafe(input, world) }
|
||||
}
|
||||
fn apply_buffers(&mut self, world: &mut World);
|
||||
/// Initialize the system.
|
||||
fn initialize(&mut self, _world: &mut World);
|
||||
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(crate) fn check_system_change_tick(
|
||||
|
|
|
@ -7,6 +7,43 @@ use crate::{
|
|||
};
|
||||
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> {
|
||||
system_a: SystemA,
|
||||
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
|
||||
where
|
||||
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>;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,10 +14,11 @@ use std::{
|
|||
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
|
||||
/// This trait can be derived.
|
||||
///
|
||||
/// This trait can be derived with the [`derive@super::SystemParam`] macro.
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
|
@ -36,9 +37,12 @@ pub trait SystemParam: Sized {
|
|||
type Fetch: for<'a> SystemParamFetch<'a>;
|
||||
}
|
||||
|
||||
/// The state of a [`SystemParam`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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
|
||||
/// conflicting access across all SystemParams.
|
||||
pub unsafe trait SystemParamState: Send + Sync + 'static {
|
||||
|
@ -54,8 +58,9 @@ pub unsafe trait SystemParamState: Send + Sync + 'static {
|
|||
pub trait SystemParamFetch<'a>: SystemParamState {
|
||||
type Item;
|
||||
/// # Safety
|
||||
///
|
||||
/// 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(
|
||||
state: &'a mut Self,
|
||||
system_state: &'a SystemState,
|
||||
|
@ -153,11 +158,13 @@ pub struct QuerySetState<T>(T);
|
|||
|
||||
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> {
|
||||
value: &'w T,
|
||||
ticks: &'w ComponentTicks,
|
||||
|
@ -188,6 +195,7 @@ impl<'w, T: Component> Deref for Res<'w, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`Res`].
|
||||
pub struct ResState<T> {
|
||||
component_id: ComponentId,
|
||||
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>);
|
||||
|
||||
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> {
|
||||
value: &'w mut T,
|
||||
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> {
|
||||
component_id: ComponentId,
|
||||
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>);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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> {
|
||||
world: &'a World,
|
||||
component_id: ComponentId,
|
||||
|
@ -534,11 +585,13 @@ pub struct 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>> {
|
||||
self.world.removed_with_id(self.component_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`RemovedComponents`].
|
||||
pub struct RemovedComponentsState<T> {
|
||||
component_id: ComponentId,
|
||||
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(crate) value: &'w T,
|
||||
ticks: ComponentTicks,
|
||||
|
@ -612,6 +674,7 @@ impl<'w, T: 'static> Deref for NonSend<'w, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`NonSend`].
|
||||
pub struct NonSendState<T> {
|
||||
component_id: ComponentId,
|
||||
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(crate) value: &'a mut T,
|
||||
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> {
|
||||
component_id: ComponentId,
|
||||
marker: PhantomData<fn() -> T>,
|
||||
|
@ -808,6 +881,7 @@ impl<'a> SystemParam for &'a Archetypes {
|
|||
type Fetch = ArchetypesState;
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`Archetypes`].
|
||||
pub struct ArchetypesState;
|
||||
|
||||
// SAFE: no component value access
|
||||
|
@ -839,6 +913,7 @@ impl<'a> SystemParam for &'a Components {
|
|||
type Fetch = ComponentsState;
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`Components`].
|
||||
pub struct ComponentsState;
|
||||
|
||||
// SAFE: no component value access
|
||||
|
@ -870,6 +945,7 @@ impl<'a> SystemParam for &'a Entities {
|
|||
type Fetch = EntitiesState;
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`Entities`].
|
||||
pub struct EntitiesState;
|
||||
|
||||
// SAFE: no component value access
|
||||
|
@ -901,6 +977,7 @@ impl<'a> SystemParam for &'a Bundles {
|
|||
type Fetch = BundlesState;
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`Bundles`].
|
||||
pub struct BundlesState;
|
||||
|
||||
// SAFE: no component value access
|
||||
|
@ -938,6 +1015,7 @@ impl SystemParam for SystemChangeTick {
|
|||
type Fetch = SystemChangeTickState;
|
||||
}
|
||||
|
||||
/// The [`SystemParamState`] of [`SystemChangeTickState`].
|
||||
pub struct SystemChangeTickState {}
|
||||
|
||||
unsafe impl SystemParamState for SystemChangeTickState {
|
||||
|
|
Loading…
Reference in a new issue