From d7b6e81fb2f6f4cfe0b6db96387578a8e1f333e7 Mon Sep 17 00:00:00 2001 From: Luca Della Vedova Date: Tue, 20 Aug 2024 05:29:30 +0800 Subject: [PATCH] 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 --- crates/bevy_ecs/src/system/commands/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index ba766c5fbd..473b8c3b80 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -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::>()); } + fn is_send() {} + fn is_sync() {} + + #[test] + fn test_commands_are_send_and_sync() { + is_send::(); + is_sync::(); + } + #[test] fn append() { let mut world = World::default();