Fix commands not being Send / Sync in 0.14 (#14392)

# Objective

Fixes Commands not being `Send` or `Sync` anymore in 0.14 by
implementing `Send` and `Sync` for `RawCommandQueue`.

## Solution

Reference discussion in
[discord](https://discord.com/channels/691052431525675048/691052431974465548/1259464518539411570).
It seems that in https://github.com/bevyengine/bevy/pull/13249, when
adding a `RawCommandQueue` variant to the `InternalQueue`, the `Send /
Sync` traits were not implemented for it, which bubbled up all the way
to `Commands` not being `Send / Sync` anymore.
I am not very familiar with the ECS internals so I can't say whether the
`RawCommandQueue` is safe to be shared between threads, but I know for
sure that before the linked PR `Commands` were indeed `Send` and `Sync`
so that PR broke "some workflows" (mandatory
[xkcd](https://xkcd.com/1172/)).

## Testing

This PR itself includes a compile test to make sure `Commands` will
implement `Send` and `Sync`. The test itself fails without the
implementation and succeeds with it.
Furthermore, if I cherry pick the test to a previous release (i.e. 0.13)
it indeed succeeds, showing that this is a regression specific to 0.14.

---------

Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
This commit is contained in:
Luca Della Vedova 2024-08-20 05:29:30 +08:00 committed by François
parent 6a4b48ba6b
commit d7b6e81fb2
No known key found for this signature in database

View file

@ -72,6 +72,12 @@ pub struct Commands<'w, 's> {
entities: &'w Entities,
}
// SAFETY: All commands [`Command`] implement [`Send`]
unsafe impl Send for Commands<'_, '_> {}
// SAFETY: `Commands` never gives access to the inner commands.
unsafe impl Sync for Commands<'_, '_> {}
const _: () = {
type __StructFieldsAlias<'w, 's> = (Deferred<'s, CommandQueue>, &'w Entities);
#[doc(hidden)]
@ -1556,6 +1562,15 @@ mod tests {
assert!(world.contains_resource::<W<f64>>());
}
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
#[test]
fn test_commands_are_send_and_sync() {
is_send::<Commands>();
is_sync::<Commands>();
}
#[test]
fn append() {
let mut world = World::default();