Add documentation to ParamSet (#6998)

# Objective

Fixes #4729.
Continuation of #4854.

## Solution

Add documentation to `ParamSet` and its methods. Includes examples suggested by community members in the original PR.


Co-authored-by: Nanox19435 <50684926+Nanox19435@users.noreply.github.com>
Co-authored-by: JoJoJet <21144246+JoJoJet@users.noreply.github.com>
This commit is contained in:
JoJoJet 2022-12-25 00:06:22 +00:00
parent ca87830450
commit fa2b5f2b36
2 changed files with 118 additions and 0 deletions

View file

@ -222,7 +222,17 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
for (i, param) in params.iter().enumerate() {
let fn_name = Ident::new(&format!("p{i}"), Span::call_site());
let index = Index::from(i);
let ordinal = match i {
1 => "1st".to_owned(),
2 => "2nd".to_owned(),
3 => "3rd".to_owned(),
x => format!("{x}th"),
};
let comment =
format!("Gets exclusive access to the {ordinal} parameter in this [`ParamSet`].");
param_fn_muts.push(quote! {
#[doc = #comment]
/// No other parameters may be accessed while this one is active.
pub fn #fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, #param> {
// SAFETY: systems run without conflicts with other systems.
// Conflicting params in ParamSet are not accessible at the same time

View file

@ -239,6 +239,114 @@ fn assert_component_access_compatibility(
query_type, filter_type, system_name, accesses);
}
/// A collection of potentially conflicting [`SystemParam`]s allowed by disjoint access.
///
/// Allows systems to safely access and interact with up to 8 mutually exclusive [`SystemParam`]s, such as
/// two queries that reference the same mutable data or an event reader and writer of the same type.
///
/// Each individual [`SystemParam`] can be accessed by using the functions `p0()`, `p1()`, ..., `p7()`,
/// according to the order they are defined in the `ParamSet`. This ensures that there's either
/// only one mutable reference to a parameter at a time or any number of immutable references.
///
/// # Examples
///
/// The following system mutably accesses the same component two times,
/// which is not allowed due to rust's mutability rules.
///
/// ```should_panic
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct Health;
/// #
/// # #[derive(Component)]
/// # struct Enemy;
/// #
/// # #[derive(Component)]
/// # struct Ally;
/// #
/// // This will panic at runtime when the system gets initialized.
/// fn bad_system(
/// mut enemies: Query<&mut Health, With<Enemy>>,
/// mut allies: Query<&mut Health, With<Ally>>,
/// ) {
/// // ...
/// }
/// #
/// # let mut bad_system_system = bevy_ecs::system::IntoSystem::into_system(bad_system);
/// # let mut world = World::new();
/// # bad_system_system.initialize(&mut world);
/// # bad_system_system.run((), &mut world);
/// ```
///
/// Conflicing `SystemParam`s like these can be placed in a `ParamSet`,
/// which leverages the borrow checker to ensure that only one of the contained parameters are accessed at a given time.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct Health;
/// #
/// # #[derive(Component)]
/// # struct Enemy;
/// #
/// # #[derive(Component)]
/// # struct Ally;
/// #
/// // Given the following system
/// fn fancy_system(
/// mut set: ParamSet<(
/// Query<&mut Health, With<Enemy>>,
/// Query<&mut Health, With<Ally>>,
/// )>
/// ) {
/// // This will access the first `SystemParam`.
/// for mut health in set.p0().iter_mut() {
/// // Do your fancy stuff here...
/// }
///
/// // The second `SystemParam`.
/// // This would fail to compile if the previous parameter was still borrowed.
/// for mut health in set.p1().iter_mut() {
/// // Do even fancier stuff here...
/// }
/// }
/// # bevy_ecs::system::assert_is_system(fancy_system);
/// ```
///
/// Of course, `ParamSet`s can be used with any kind of `SystemParam`, not just [queries](Query).
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # struct MyEvent;
/// # impl MyEvent {
/// # pub fn new() -> Self { Self }
/// # }
/// fn event_system(
/// mut set: ParamSet<(
/// // `EventReader`s and `EventWriter`s conflict with each other,
/// // since they both access the event queue resource for `MyEvent`.
/// EventReader<MyEvent>,
/// EventWriter<MyEvent>,
/// // `&World` reads the entire world, so a `ParamSet` is the only way
/// // that it can be used in the same system as any mutable accesses.
/// &World,
/// )>,
/// ) {
/// for event in set.p0().iter() {
/// // ...
/// # let _event = event;
/// }
/// set.p1().send(MyEvent::new());
///
/// let entities = set.p2().entities();
/// // ...
/// # let _entities = entities;
/// }
/// # bevy_ecs::system::assert_is_system(event_system);
/// ```
pub struct ParamSet<'w, 's, T: SystemParam> {
param_states: &'s mut T::State,
world: &'w World,