refactor: Simplify lifetimes for Commands and related types (#11445)

# Objective

It would be convenient to be able to call functions with `Commands` as a
parameter without having to move your own instance of `Commands`. Since
this struct is composed entirely of references, we can easily get an
owned instance of `Commands` by shortening the lifetime.

## Solution

Add `Commands::reborrow`, `EntiyCommands::reborrow`, and
`Deferred::reborrow`, which returns an owned version of themselves with
a shorter lifetime.

Remove unnecessary lifetimes from `EntityCommands`. The `'w` and `'s`
lifetimes only have to be separate for `Commands` because it's used as a
`SystemParam` -- this is not the case for `EntityCommands`.

---

## Changelog

Added `Commands::reborrow`. This is useful if you have `&mut Commands`
but need `Commands`. Also added `EntityCommands::reborrow` and
`Deferred:reborrow` which serve the same purpose.

## Migration Guide

The lifetimes for `EntityCommands` have been simplified.

```rust
// Before (Bevy 0.12)
struct MyStruct<'w, 's, 'a> {
     commands: EntityCommands<'w, 's, 'a>,
}

// After (Bevy 0.13)
struct MyStruct<'a> {
    commands: EntityCommands<'a>,
}
```

The method `EntityCommands::commands` now returns `Commands` rather than
`&mut Commands`.

```rust
// Before (Bevy 0.12)
let commands = entity_commands.commands();
commands.spawn(...);

// After (Bevy 0.13)
let mut commands = entity_commands.commands();
commands.spawn(...);
```
This commit is contained in:
Joseph 2024-01-22 07:35:42 -08:00 committed by GitHub
parent e2e4e8eb9a
commit 7d69d3195f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 65 additions and 23 deletions

View file

@ -140,7 +140,7 @@ pub trait ReflectCommandExt {
) -> &mut Self;
}
impl<'w, 's, 'a> ReflectCommandExt for EntityCommands<'w, 's, 'a> {
impl ReflectCommandExt for EntityCommands<'_> {
fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self {
self.commands.add(InsertReflect {
entity: self.entity,

View file

@ -146,6 +146,31 @@ impl<'w, 's> Commands<'w, 's> {
}
}
/// Returns a [`Commands`] with a smaller lifetime.
/// This is useful if you have `&mut Commands` but need `Commands`.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::prelude::*;
/// fn my_system(mut commands: Commands) {
/// // We do our initialization in a separate function,
/// // which expects an owned `Commands`.
/// do_initialization(commands.reborrow());
///
/// // Since we only reborrowed the commands instead of moving them, we can still use them.
/// commands.spawn_empty();
/// }
/// #
/// # fn do_initialization(_: Commands) {}
/// ```
pub fn reborrow(&mut self) -> Commands<'w, '_> {
Commands {
queue: self.queue.reborrow(),
entities: self.entities,
}
}
/// Take all commands from `other` and append them to `self`, leaving `other` empty
pub fn append(&mut self, other: &mut CommandQueue) {
self.queue.append(other);
@ -186,11 +211,11 @@ impl<'w, 's> Commands<'w, 's> {
///
/// - [`spawn`](Self::spawn) to spawn an entity with a bundle.
/// - [`spawn_batch`](Self::spawn_batch) to spawn entities with a bundle each.
pub fn spawn_empty<'a>(&'a mut self) -> EntityCommands<'w, 's, 'a> {
pub fn spawn_empty(&mut self) -> EntityCommands {
let entity = self.entities.reserve_entity();
EntityCommands {
entity,
commands: self,
commands: self.reborrow(),
}
}
@ -208,13 +233,13 @@ impl<'w, 's> Commands<'w, 's> {
/// [`Commands::spawn`]. This method should generally only be used for sharing entities across
/// apps, and only when they have a scheme worked out to share an ID space (which doesn't happen
/// by default).
pub fn get_or_spawn<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> {
pub fn get_or_spawn(&mut self, entity: Entity) -> EntityCommands {
self.add(move |world: &mut World| {
world.get_or_spawn(entity);
});
EntityCommands {
entity,
commands: self,
commands: self.reborrow(),
}
}
@ -268,7 +293,7 @@ impl<'w, 's> Commands<'w, 's> {
///
/// - [`spawn_empty`](Self::spawn_empty) to spawn an entity without any components.
/// - [`spawn_batch`](Self::spawn_batch) to spawn entities with a bundle each.
pub fn spawn<'a, T: Bundle>(&'a mut self, bundle: T) -> EntityCommands<'w, 's, 'a> {
pub fn spawn<T: Bundle>(&mut self, bundle: T) -> EntityCommands {
let mut e = self.spawn_empty();
e.insert(bundle);
e
@ -310,7 +335,7 @@ impl<'w, 's> Commands<'w, 's> {
/// - [`get_entity`](Self::get_entity) for the fallible version.
#[inline]
#[track_caller]
pub fn entity<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> {
pub fn entity(&mut self, entity: Entity) -> EntityCommands {
#[inline(never)]
#[cold]
#[track_caller]
@ -359,10 +384,10 @@ impl<'w, 's> Commands<'w, 's> {
/// - [`entity`](Self::entity) for the panicking version.
#[inline]
#[track_caller]
pub fn get_entity<'a>(&'a mut self, entity: Entity) -> Option<EntityCommands<'w, 's, 'a>> {
pub fn get_entity(&mut self, entity: Entity) -> Option<EntityCommands> {
self.entities.contains(entity).then_some(EntityCommands {
entity,
commands: self,
commands: self.reborrow(),
})
}
@ -674,12 +699,12 @@ where
}
/// A list of commands that will be run to modify an [entity](crate::entity).
pub struct EntityCommands<'w, 's, 'a> {
pub struct EntityCommands<'a> {
pub(crate) entity: Entity,
pub(crate) commands: &'a mut Commands<'w, 's>,
pub(crate) commands: Commands<'a, 'a>,
}
impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
impl EntityCommands<'_> {
/// Returns the [`Entity`] id of the entity.
///
/// # Example
@ -698,6 +723,15 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
self.entity
}
/// Returns an [`EntityCommands`] with a smaller lifetime.
/// This is useful if you have `&mut EntityCommands` but you need `EntityCommands`.
pub fn reborrow(&mut self) -> EntityCommands {
EntityCommands {
entity: self.entity,
commands: self.commands.reborrow(),
}
}
/// Adds a [`Bundle`] of components to the entity.
///
/// This will overwrite any previous value(s) of the same component type.
@ -956,8 +990,8 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
}
/// Returns the underlying [`Commands`].
pub fn commands(&mut self) -> &mut Commands<'w, 's> {
self.commands
pub fn commands(&mut self) -> Commands {
self.commands.reborrow()
}
}

View file

@ -919,6 +919,14 @@ impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> {
}
}
impl<T: SystemBuffer> Deferred<'_, T> {
/// Returns a [`Deferred<T>`] with a smaller lifetime.
/// This is useful if you have `&mut Deferred<T>` but need `Deferred<T>`.
pub fn reborrow(&mut self) -> Deferred<T> {
Deferred(self.0)
}
}
// SAFETY: Only local state is accessed.
unsafe impl<T: SystemBuffer> ReadOnlySystemParam for Deferred<'_, T> {}

View file

@ -274,15 +274,15 @@ impl Command for RemoveParent {
/// });
/// # }
/// ```
pub struct ChildBuilder<'w, 's, 'a> {
commands: &'a mut Commands<'w, 's>,
pub struct ChildBuilder<'a> {
commands: Commands<'a, 'a>,
push_children: PushChildren,
}
impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> {
impl ChildBuilder<'_> {
/// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`].
/// Also adds [`Parent`] component to the created entity.
pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands<'w, 's, '_> {
pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands {
let e = self.commands.spawn(bundle);
self.push_children.children.push(e.id());
e
@ -290,7 +290,7 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> {
/// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`].
/// Also adds [`Parent`] component to the created entity.
pub fn spawn_empty(&mut self) -> EntityCommands<'w, 's, '_> {
pub fn spawn_empty(&mut self) -> EntityCommands {
let e = self.commands.spawn_empty();
self.push_children.children.push(e.id());
e
@ -302,7 +302,7 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> {
}
/// Adds a command to be executed, like [`Commands::add`].
pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self {
pub fn add_command<C: Command>(&mut self, command: C) -> &mut Self {
self.commands.add(command);
self
}
@ -374,7 +374,7 @@ pub trait BuildChildren {
fn remove_parent(&mut self) -> &mut Self;
}
impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> {
impl BuildChildren for EntityCommands<'_> {
fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self {
let parent = self.id();
let mut builder = ChildBuilder {

View file

@ -89,7 +89,7 @@ pub trait DespawnRecursiveExt {
fn despawn_descendants(&mut self) -> &mut Self;
}
impl<'w, 's, 'a> DespawnRecursiveExt for EntityCommands<'w, 's, 'a> {
impl DespawnRecursiveExt for EntityCommands<'_> {
/// Despawns the provided entity and its children.
fn despawn_recursive(mut self) {
let entity = self.id();

View file

@ -85,7 +85,7 @@ pub trait BuildChildrenTransformExt {
/// (during [`apply_deferred`](bevy_ecs::schedule::apply_deferred)).
fn remove_parent_in_place(&mut self) -> &mut Self;
}
impl<'w, 's, 'a> BuildChildrenTransformExt for EntityCommands<'w, 's, 'a> {
impl BuildChildrenTransformExt for EntityCommands<'_> {
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
let child = self.id();
self.commands().add(PushChildInPlace { child, parent });