diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 35234213259f8..e3083b5958af0 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1143,14 +1143,25 @@ impl World { self.entities.clear(); } + /// Create a version of this [`World`] which can be sent to another thread + /// + /// # Panics + /// + /// If `self` contains any [`!Send`] resources, e.g. from calls to [`World::insert_non_send`] + /// + /// [`!Send`]: Send + pub fn turtle(self) -> Turtle { let non_send = self.components().non_send_components().collect::>(); for id in non_send { assert!( - self.get_populated_resource_column(id).is_some(), + self.get_populated_resource_column(id).is_none(), "Tried to create a Turtle from a World containing a !Send resource" ); } + // Safety: this world does not contain anything !Send, as confirmed by the check above + // In practise this method is used for GLTF loading, which does not add any resources to the given world + // (i.e. the above check is trivially true) Turtle { world: self } } } @@ -1173,29 +1184,44 @@ impl fmt::Debug for World { unsafe impl Sync for World {} /// A world which does not contain any [`!Send`] resources, and therefore -/// can be safely sent between threads +/// can be safely sent between threads. +/// +/// The name turtle is derived from this being something which is moving a +/// [`World`] (between threads) /// /// [`!Send`]: Send #[derive(Debug)] pub struct Turtle { + // Safety: does not have any !Send resources world: World, } +// Safety: The contained world does not contain anything which is !Send unsafe impl Send for Turtle {} impl Turtle { + /// The [`World`] this [`Turtle`] was created from. + /// + /// The returned [`World`] does not contain any [`!Send`] resources + /// + /// [`!Send`]: Send pub fn world(self) -> World { self.world } + /// A view on this [`Turtle`]'s [`World`], which contains no [`!Send`] resources + /// + /// [`!Send`]: Send + // Safety: NonSend resources cannot be added using a raw reference + // to the world, so this cannot break our invariants pub fn world_ref(&self) -> &World { &self.world } } -impl Into for Turtle { - fn into(self) -> World { - self.world() +impl From for World { + fn from(turtle: Turtle) -> Self { + turtle.world() } } diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index 2dc215d422861..e75a308aaca94 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -27,7 +27,7 @@ pub struct DynamicEntity { impl DynamicScene { /// Create a new dynamic scene from a given scene. pub fn from_scene(scene: &Scene, type_registry: &TypeRegistryArc) -> Self { - Self::from_world(&scene.turtle.world_ref(), type_registry) + Self::from_world(scene.turtle.world_ref(), type_registry) } /// Create a new dynamic scene from a given world. diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index f65af56dd3367..2f9914eef0dbd 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -179,12 +179,7 @@ impl SceneSpawner { } }) })?; - reflect_component.copy_component( - &scene_world, - world, - *scene_entity, - entity, - ); + reflect_component.copy_component(scene_world, world, *scene_entity, entity); } } }