Skip to content

Commit

Permalink
Make from_reflect_or_world also try ReflectDefault and improve some c…
Browse files Browse the repository at this point in the history
…omments
  • Loading branch information
SkiFire13 committed Mar 15, 2024
1 parent fec0004 commit 6618d7e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 20 deletions.
8 changes: 4 additions & 4 deletions crates/bevy_ecs/src/reflect/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
//!
//! [`get_type_registration`]: bevy_reflect::GetTypeRegistration::get_type_registration

use super::from_reflect_or_world;
use super::from_reflect_with_fallback;
use crate::{
change_detection::Mut,
component::Component,
Expand Down Expand Up @@ -258,7 +258,7 @@ impl<C: Component + Reflect + FromReflect> FromType<C> for ReflectComponent {
ReflectComponent(ReflectComponentFns {
insert: |entity, reflected_component, registry| {
let component = entity.world_scope(|world| {
from_reflect_or_world::<C>(reflected_component, world, registry)
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
entity.insert(component);
},
Expand All @@ -271,7 +271,7 @@ impl<C: Component + Reflect + FromReflect> FromType<C> for ReflectComponent {
component.apply(reflected_component);
} else {
let component = entity.world_scope(|world| {
from_reflect_or_world::<C>(reflected_component, world, registry)
from_reflect_with_fallback::<C>(reflected_component, world, registry)
});
entity.insert(component);
}
Expand All @@ -283,7 +283,7 @@ impl<C: Component + Reflect + FromReflect> FromType<C> for ReflectComponent {
copy: |source_world, destination_world, source_entity, destination_entity, registry| {
let source_component = source_world.get::<C>(source_entity).unwrap();
let destination_component =
from_reflect_or_world::<C>(source_component, destination_world, registry);
from_reflect_with_fallback::<C>(source_component, destination_world, registry);
destination_world
.entity_mut(destination_entity)
.insert(destination_component);
Expand Down
40 changes: 28 additions & 12 deletions crates/bevy_ecs/src/reflect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::ops::{Deref, DerefMut};

use crate as bevy_ecs;
use crate::{system::Resource, world::World};
use bevy_reflect::std_traits::ReflectDefault;
use bevy_reflect::{FromReflect, Reflect, TypeRegistry, TypeRegistryArc};

mod bundle;
Expand Down Expand Up @@ -45,12 +46,13 @@ impl DerefMut for AppTypeRegistry {
/// Creates a `T` from a `&dyn Reflect`.
///
/// The first approach uses `T`'s implementation of `FromReflect`.
/// If this fails, it falls back to default-initializing a new instance of `T` using its
/// `ReflectFromWorld` data from the `world`'s `AppTypeRegistry` and `apply`ing the
/// If this fails, it falls back to default-initializing a new instance of `T` using
/// either its `ReflectDefault` or its `ReflectFromWorld` registration in `registry`
/// (whichever is found, preferring `ReflectDefault` if present) and `apply`ing the
/// `&dyn Reflect` on it.
///
/// Panics if both approaches fail.
fn from_reflect_or_world<T: FromReflect>(
/// Panics if all approaches fail.
fn from_reflect_with_fallback<T: FromReflect>(
reflected: &dyn Reflect,
world: &mut World,
registry: &TypeRegistry,
Expand All @@ -59,20 +61,34 @@ fn from_reflect_or_world<T: FromReflect>(
return value;
}

// Clone the `ReflectFromWorld` because it's cheap and "frees"
// the borrow of `world` so that it can be passed to `from_world`.
let Some(reflect_from_world) = registry.get_type_data::<ReflectFromWorld>(TypeId::of::<T>())
else {
fn different_type_error<T>(reflected: &str) -> ! {
panic!(
"`FromReflect` failed and no `ReflectFromWorld` registration found for `{}`",
"the registration for the reflected `{}` trait for the type `{}` produced \
a value of a different type",
reflected,
// FIXME: once we have unique reflect, use `TypePath`.
std::any::type_name::<T>(),
);
};
}

let Ok(mut value) = reflect_from_world.from_world(world).take::<T>() else {
let mut value = if let Some(reflect_default) =
registry.get_type_data::<ReflectDefault>(TypeId::of::<T>())
{
reflect_default
.default()
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("Default"))
} else if let Some(reflect_from_world) =
registry.get_type_data::<ReflectFromWorld>(TypeId::of::<T>())
{
reflect_from_world
.from_world(world)
.take::<T>()
.unwrap_or_else(|_| different_type_error::<T>("FromWorld"))
} else {
panic!(
"the `ReflectFromWorld` registration for `{}` produced a value of a different type",
"`FromReflect::from_reflect` failed and no registration for the reflected \
`Default` or `FromWorld` traits was found for the type `{}`",
// FIXME: once we have unique reflect, use `TypePath`.
std::any::type_name::<T>(),
);
Expand Down
9 changes: 5 additions & 4 deletions crates/bevy_ecs/src/reflect/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
};
use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};

use super::from_reflect_or_world;
use super::from_reflect_with_fallback;

/// A struct used to operate on reflected [`Resource`] of a type.
///
Expand Down Expand Up @@ -180,7 +180,7 @@ impl<R: Resource + FromReflect> FromType<R> for ReflectResource {
fn from_type() -> Self {
ReflectResource(ReflectResourceFns {
insert: |world, reflected_resource, registry| {
let resource = from_reflect_or_world::<R>(reflected_resource, world, registry);
let resource = from_reflect_with_fallback::<R>(reflected_resource, world, registry);
world.insert_resource(resource);
},
apply: |world, reflected_resource| {
Expand All @@ -191,7 +191,8 @@ impl<R: Resource + FromReflect> FromType<R> for ReflectResource {
if let Some(mut resource) = world.get_resource_mut::<R>() {
resource.apply(reflected_resource);
} else {
let resource = from_reflect_or_world::<R>(reflected_resource, world, registry);
let resource =
from_reflect_with_fallback::<R>(reflected_resource, world, registry);
world.insert_resource(resource);
}
},
Expand All @@ -212,7 +213,7 @@ impl<R: Resource + FromReflect> FromType<R> for ReflectResource {
copy: |source_world, destination_world, registry| {
let source_resource = source_world.resource::<R>();
let destination_resource =
from_reflect_or_world::<R>(source_resource, destination_world, registry);
from_reflect_with_fallback::<R>(source_resource, destination_world, registry);
destination_world.insert_resource(destination_resource);
},
})
Expand Down

0 comments on commit 6618d7e

Please sign in to comment.