From 2ba0e86334cb4ad0bde238c06f0c56287fc2bd9a Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Mon, 11 Jul 2022 14:11:24 +0000 Subject: [PATCH] Add apply_or_insert functions to reflected component and resources (#5201) # Objective `ReflectResource` and `ReflectComponent` will panic on `apply` method if there is no such component. It's not very ergonomic. And not very good for performance since I need to check if such component exists first. ## Solution * Add `ReflectComponent::apply_or_insert` and `ReflectResource::apply_or_insert` functions. * Rename `ReflectComponent::add` into `ReflectComponent::insert` for consistency. --- ## Changelog ### Added * `ReflectResource::apply_or_insert` and `ReflectComponent::apply_on_insert`. ### Changed * Rename `ReflectComponent::add` into `ReflectComponent::insert` for consistency. * Use `ReflectComponent::apply_on_insert` in `DynamicScene` instead of manual checking. ## Migration Guide * Rename `ReflectComponent::add` into `ReflectComponent::insert`. --- crates/bevy_ecs/src/reflect.rs | 42 +++++++++++++++++++++++--- crates/bevy_scene/src/dynamic_scene.rs | 9 +----- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/crates/bevy_ecs/src/reflect.rs b/crates/bevy_ecs/src/reflect.rs index 9f97d08aec34a..0b288b3aa7ac0 100644 --- a/crates/bevy_ecs/src/reflect.rs +++ b/crates/bevy_ecs/src/reflect.rs @@ -18,8 +18,9 @@ use bevy_reflect::{ /// [`bevy_reflect::TypeRegistration::data`]. #[derive(Clone)] pub struct ReflectComponent { - add: fn(&mut World, Entity, &dyn Reflect), + insert: fn(&mut World, Entity, &dyn Reflect), apply: fn(&mut World, Entity, &dyn Reflect), + apply_or_insert: fn(&mut World, Entity, &dyn Reflect), remove: fn(&mut World, Entity), reflect: fn(&World, Entity) -> Option<&dyn Reflect>, reflect_mut: unsafe fn(&World, Entity) -> Option, @@ -32,8 +33,8 @@ impl ReflectComponent { /// # Panics /// /// Panics if there is no such entity. - pub fn add(&self, world: &mut World, entity: Entity, component: &dyn Reflect) { - (self.add)(world, entity, component); + pub fn insert(&self, world: &mut World, entity: Entity, component: &dyn Reflect) { + (self.insert)(world, entity, component); } /// Uses reflection to set the value of this [`Component`] type in the entity to the given value. @@ -45,6 +46,15 @@ impl ReflectComponent { (self.apply)(world, entity, component); } + /// Uses reflection to set the value of this [`Component`] type in the entity to the given value or insert a new one if it does not exist. + /// + /// # Panics + /// + /// Panics if the `entity` does not exist. + pub fn apply_or_insert(&self, world: &mut World, entity: Entity, component: &dyn Reflect) { + (self.apply_or_insert)(world, entity, component); + } + /// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist. /// /// # Panics @@ -103,7 +113,7 @@ impl ReflectComponent { impl FromType for ReflectComponent { fn from_type() -> Self { ReflectComponent { - add: |world, entity, reflected_component| { + insert: |world, entity, reflected_component| { let mut component = C::from_world(world); component.apply(reflected_component); world.entity_mut(entity).insert(component); @@ -112,6 +122,15 @@ impl FromType for ReflectComponent { let mut component = world.get_mut::(entity).unwrap(); component.apply(reflected_component); }, + apply_or_insert: |world, entity, reflected_component| { + if let Some(mut component) = world.get_mut::(entity) { + component.apply(reflected_component); + } else { + let mut component = C::from_world(world); + component.apply(reflected_component); + world.entity_mut(entity).insert(component); + } + }, remove: |world, entity| { world.entity_mut(entity).remove::(); }, @@ -154,6 +173,7 @@ impl FromType for ReflectComponent { pub struct ReflectResource { insert: fn(&mut World, &dyn Reflect), apply: fn(&mut World, &dyn Reflect), + apply_or_insert: fn(&mut World, &dyn Reflect), remove: fn(&mut World), reflect: fn(&World) -> Option<&dyn Reflect>, reflect_unchecked_mut: unsafe fn(&World) -> Option, @@ -175,6 +195,11 @@ impl ReflectResource { (self.apply)(world, resource); } + /// Uses reflection to set the value of this [`Resource`] type in the world to the given value or insert a new one if it does not exist. + pub fn apply_or_insert(&self, world: &mut World, resource: &dyn Reflect) { + (self.apply_or_insert)(world, resource); + } + /// Removes this [`Resource`] type from the world. Does nothing if it doesn't exist. pub fn remove(&self, world: &mut World) { (self.remove)(world); @@ -224,6 +249,15 @@ impl FromType for ReflectResource { let mut resource = world.resource_mut::(); resource.apply(reflected_resource); }, + apply_or_insert: |world, reflected_resource| { + if let Some(mut resource) = world.get_resource_mut::() { + resource.apply(reflected_resource); + } else { + let mut resource = C::from_world(world); + resource.apply(reflected_resource); + world.insert_resource(resource); + } + }, remove: |world| { world.remove_resource::(); }, diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index 12f456d60ced4..7328f5f366267 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -112,14 +112,7 @@ impl DynamicScene { // If the entity already has the given component attached, // just apply the (possibly) new value, otherwise add the // component to the entity. - if world - .entity(entity) - .contains_type_id(registration.type_id()) - { - reflect_component.apply(world, entity, &**component); - } else { - reflect_component.add(world, entity, &**component); - } + reflect_component.apply_or_insert(world, entity, &**component); } }