Skip to content

Commit

Permalink
Add apply_or_insert functions to reflected component and resources (b…
Browse files Browse the repository at this point in the history
…evyengine#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`.
  • Loading branch information
Shatur authored and ItsDoot committed Feb 1, 2023
1 parent 31fcf37 commit 2ba0e86
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 12 deletions.
42 changes: 38 additions & 4 deletions crates/bevy_ecs/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ReflectMut>,
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -103,7 +113,7 @@ impl ReflectComponent {
impl<C: Component + Reflect + FromWorld> FromType<C> 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);
Expand All @@ -112,6 +122,15 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
let mut component = world.get_mut::<C>(entity).unwrap();
component.apply(reflected_component);
},
apply_or_insert: |world, entity, reflected_component| {
if let Some(mut component) = world.get_mut::<C>(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::<C>();
},
Expand Down Expand Up @@ -154,6 +173,7 @@ impl<C: Component + Reflect + FromWorld> FromType<C> 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<ReflectMut>,
Expand All @@ -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);
Expand Down Expand Up @@ -224,6 +249,15 @@ impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
let mut resource = world.resource_mut::<C>();
resource.apply(reflected_resource);
},
apply_or_insert: |world, reflected_resource| {
if let Some(mut resource) = world.get_resource_mut::<C>() {
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::<C>();
},
Expand Down
9 changes: 1 addition & 8 deletions crates/bevy_scene/src/dynamic_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down

0 comments on commit 2ba0e86

Please sign in to comment.