Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make from_reflect_or_world also try ReflectDefault and improve some comments and panic messages #12499

Merged
merged 2 commits into from Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions crates/bevy_ecs/src/reflect/component.rs
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
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>(
SkiFire13 marked this conversation as resolved.
Show resolved Hide resolved
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>(),
SkiFire13 marked this conversation as resolved.
Show resolved Hide resolved
);
};
}

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 `{}`",
SkiFire13 marked this conversation as resolved.
Show resolved Hide resolved
// FIXME: once we have unique reflect, use `TypePath`.
std::any::type_name::<T>(),
SkiFire13 marked this conversation as resolved.
Show resolved Hide resolved
);
Expand Down
9 changes: 5 additions & 4 deletions crates/bevy_ecs/src/reflect/resource.rs
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