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

reflect: implement the unique reflect rfc #7207

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
10 changes: 5 additions & 5 deletions crates/bevy_asset/src/reflect.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::any::{Any, TypeId};

use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World};
use bevy_reflect::{FromReflect, FromType, Reflect};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect};

use crate::{Asset, Assets, Handle, UntypedAssetId, UntypedHandle};

Expand All @@ -22,8 +22,8 @@ pub struct ReflectAsset {
// - may only be called with an [`UnsafeWorldCell`] which can be used to access the corresponding `Assets<T>` resource mutably
// - may only be used to access **at most one** access at once
get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, UntypedHandle) -> Option<&mut dyn Reflect>,
add: fn(&mut World, &dyn Reflect) -> UntypedHandle,
insert: fn(&mut World, UntypedHandle, &dyn Reflect),
add: fn(&mut World, &dyn PartialReflect) -> UntypedHandle,
insert: fn(&mut World, UntypedHandle, &dyn PartialReflect),
len: fn(&World) -> usize,
ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = UntypedAssetId> + 'w>,
remove: fn(&mut World, UntypedHandle) -> Option<Box<dyn Reflect>>,
Expand Down Expand Up @@ -94,11 +94,11 @@ impl ReflectAsset {
}

/// Equivalent of [`Assets::add`]
pub fn add(&self, world: &mut World, value: &dyn Reflect) -> UntypedHandle {
pub fn add(&self, world: &mut World, value: &dyn PartialReflect) -> UntypedHandle {
(self.add)(world, value)
}
/// Equivalent of [`Assets::insert`]
pub fn insert(&self, world: &mut World, handle: UntypedHandle, value: &dyn Reflect) {
pub fn insert(&self, world: &mut World, handle: UntypedHandle, value: &dyn PartialReflect) {
(self.insert)(world, handle, value);
}

Expand Down
56 changes: 31 additions & 25 deletions crates/bevy_ecs/src/reflect/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use std::any::TypeId;

use crate::{prelude::Bundle, world::EntityWorldMut};
use bevy_reflect::{FromReflect, FromType, Reflect, ReflectRef, TypeRegistry};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, ReflectRef, TypeRegistry};

use super::ReflectComponent;

Expand All @@ -24,11 +24,11 @@ pub struct ReflectBundle(ReflectBundleFns);
#[derive(Clone)]
pub struct ReflectBundleFns {
/// Function pointer implementing [`ReflectBundle::insert()`].
pub insert: fn(&mut EntityWorldMut, &dyn Reflect),
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect),
/// Function pointer implementing [`ReflectBundle::apply()`].
pub apply: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub apply: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply_or_insert()`].
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::remove()`].
pub remove: fn(&mut EntityWorldMut),
}
Expand All @@ -46,7 +46,7 @@ impl ReflectBundleFns {

impl ReflectBundle {
/// Insert a reflected [`Bundle`] into the entity like [`insert()`](EntityWorldMut::insert).
pub fn insert(&self, entity: &mut EntityWorldMut, bundle: &dyn Reflect) {
pub fn insert(&self, entity: &mut EntityWorldMut, bundle: &dyn PartialReflect) {
(self.0.insert)(entity, bundle);
}

Expand All @@ -58,7 +58,7 @@ impl ReflectBundle {
pub fn apply(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn Reflect,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply)(entity, bundle, registry);
Expand All @@ -68,7 +68,7 @@ impl ReflectBundle {
pub fn apply_or_insert(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn Reflect,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(entity, bundle, registry);
Expand Down Expand Up @@ -170,17 +170,20 @@ impl<B: Bundle + Reflect + FromReflect> FromType<B> for ReflectBundle {
}
}

fn insert_field(entity: &mut EntityWorldMut, field: &dyn Reflect, registry: &TypeRegistry) {
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
reflect_component.apply(entity, field);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
reflect_bundle.apply(entity, field, registry);
fn insert_field(entity: &mut EntityWorldMut, field: &dyn PartialReflect, registry: &TypeRegistry) {
let Some(type_id) = field.try_as_reflect().map(|field| field.type_id()) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};

if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply(entity, field.as_partial_reflect());
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply(entity, field.as_partial_reflect(), registry);
} else {
let is_component = entity
.world()
.components()
.get_id(field.type_id())
.is_some();
let is_component = entity.world().components().get_id(type_id).is_some();

if is_component {
panic!(
Expand All @@ -198,19 +201,22 @@ fn insert_field(entity: &mut EntityWorldMut, field: &dyn Reflect, registry: &Typ

fn apply_or_insert_field(
entity: &mut EntityWorldMut,
field: &dyn Reflect,
field: &dyn PartialReflect,
registry: &TypeRegistry,
) {
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
let Some(type_id) = field.try_as_reflect().map(|field| field.type_id()) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};

if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply_or_insert(entity, field, registry);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply_or_insert(entity, field, registry);
} else {
let is_component = entity
.world()
.components()
.get_id(field.type_id())
.is_some();
let is_component = entity.world().components().get_id(type_id).is_some();

if is_component {
panic!(
Expand Down
22 changes: 13 additions & 9 deletions crates/bevy_ecs/src/reflect/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ use crate::{
entity::Entity,
world::{unsafe_world_cell::UnsafeEntityCell, EntityRef, EntityWorldMut, World},
};
use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypeRegistry};

/// A struct used to operate on reflected [`Component`] trait of a type.
///
Expand Down Expand Up @@ -96,11 +96,11 @@ pub struct ReflectComponent(ReflectComponentFns);
#[derive(Clone)]
pub struct ReflectComponentFns {
/// Function pointer implementing [`ReflectComponent::insert()`].
pub insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::apply()`].
pub apply: fn(&mut EntityWorldMut, &dyn Reflect),
pub apply: fn(&mut EntityWorldMut, &dyn PartialReflect),
/// Function pointer implementing [`ReflectComponent::apply_or_insert()`].
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::remove()`].
pub remove: fn(&mut EntityWorldMut),
/// Function pointer implementing [`ReflectComponent::contains()`].
Expand Down Expand Up @@ -134,7 +134,7 @@ impl ReflectComponent {
pub fn insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn Reflect,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, component, registry);
Expand All @@ -145,15 +145,15 @@ impl ReflectComponent {
/// # Panics
///
/// Panics if there is no [`Component`] of the given type.
pub fn apply(&self, entity: &mut EntityWorldMut, component: &dyn Reflect) {
pub fn apply(&self, entity: &mut EntityWorldMut, component: &dyn PartialReflect) {
(self.0.apply)(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.
pub fn apply_or_insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn Reflect,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(entity, component, registry);
Expand Down Expand Up @@ -258,7 +258,11 @@ 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_or_world::<C>(
reflected_component.as_partial_reflect(),
world,
registry,
)
});
entity.insert(component);
},
Expand All @@ -268,7 +272,7 @@ impl<C: Component + Reflect + FromReflect> FromType<C> for ReflectComponent {
},
apply_or_insert: |entity, reflected_component, registry| {
if let Some(mut component) = entity.get_mut::<C>() {
component.apply(reflected_component);
component.apply(reflected_component.as_partial_reflect());
} else {
let component = entity.world_scope(|world| {
from_reflect_or_world::<C>(reflected_component, world, registry)
Expand Down
28 changes: 14 additions & 14 deletions crates/bevy_ecs/src/reflect/entity_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::reflect::AppTypeRegistry;
use crate::system::{EntityCommands, Resource};
use crate::world::Command;
use crate::{entity::Entity, reflect::ReflectComponent, world::World};
use bevy_reflect::{Reflect, TypeRegistry};
use bevy_reflect::{PartialReflect, TypeRegistry};
use std::borrow::Cow;
use std::marker::PhantomData;

Expand All @@ -18,7 +18,7 @@ pub trait ReflectCommandExt {
///
/// - If the entity doesn't exist.
/// - If [`AppTypeRegistry`] does not have the reflection data for the given [`Component`](crate::component::Component).
/// - If the component data is invalid. See [`Reflect::apply`] for further details.
/// - If the component data is invalid. See [`PartialReflect::apply`] for further details.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
Expand Down Expand Up @@ -69,7 +69,7 @@ pub trait ReflectCommandExt {
/// }
///
/// ```
fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self;
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self;

/// Same as [`insert_reflect`](ReflectCommandExt::insert_reflect), but using the `T` resource as type registry instead of
/// `AppTypeRegistry`.
Expand All @@ -83,7 +83,7 @@ pub trait ReflectCommandExt {
/// - The given [`Resource`] is removed from the [`World`] before the command is applied.
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn Reflect>,
component: Box<dyn PartialReflect>,
) -> &mut Self;

/// Removes from the entity the component with the given type name registered in [`AppTypeRegistry`].
Expand Down Expand Up @@ -142,7 +142,7 @@ pub trait ReflectCommandExt {
}

impl ReflectCommandExt for EntityCommands<'_> {
fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self {
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
self.commands.add(InsertReflect {
entity: self.entity,
component,
Expand All @@ -152,7 +152,7 @@ impl ReflectCommandExt for EntityCommands<'_> {

fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn Reflect>,
component: Box<dyn PartialReflect>,
) -> &mut Self {
self.commands.add(InsertReflectWithRegistry::<T> {
entity: self.entity,
Expand Down Expand Up @@ -188,7 +188,7 @@ fn insert_reflect(
world: &mut World,
entity: Entity,
type_registry: &TypeRegistry,
component: Box<dyn Reflect>,
component: Box<dyn PartialReflect>,
) {
let type_info = component
.get_represented_type_info()
Expand All @@ -197,13 +197,13 @@ fn insert_reflect(
let Some(mut entity) = world.get_entity_mut(entity) else {
panic!("error[B0003]: Could not insert a reflected component (of type {type_path}) for entity {entity:?} because it doesn't exist in this World. See: https://bevyengine.org/learn/errors/#b0003");
};
let Some(type_registration) = type_registry.get_with_type_path(type_path) else {
let Some(type_registration) = type_registry.get(type_info.type_id()) else {
panic!("Could not get type registration (for component type {type_path}) because it doesn't exist in the TypeRegistry.");
};
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
panic!("Could not get ReflectComponent data (for component type {type_path}) because it doesn't exist in this TypeRegistration.");
};
reflect_component.insert(&mut entity, &*component, type_registry);
reflect_component.insert(&mut entity, component.as_partial_reflect(), type_registry);
}

/// A [`Command`] that adds the boxed reflect component to an entity using the data in
Expand All @@ -214,7 +214,7 @@ pub struct InsertReflect {
/// The entity on which the component will be inserted.
pub entity: Entity,
/// The reflect [`Component`](crate::component::Component) that will be added to the entity.
pub component: Box<dyn Reflect>,
pub component: Box<dyn PartialReflect>,
}

impl Command for InsertReflect {
Expand All @@ -233,7 +233,7 @@ pub struct InsertReflectWithRegistry<T: Resource + AsRef<TypeRegistry>> {
pub entity: Entity,
pub _t: PhantomData<T>,
/// The reflect [`Component`](crate::component::Component) that will be added to the entity.
pub component: Box<dyn Reflect>,
pub component: Box<dyn PartialReflect>,
}

impl<T: Resource + AsRef<TypeRegistry>> Command for InsertReflectWithRegistry<T> {
Expand Down Expand Up @@ -317,7 +317,7 @@ mod tests {
use crate::system::{Commands, SystemState};
use crate::{self as bevy_ecs, component::Component, world::World};
use bevy_ecs_macros::Resource;
use bevy_reflect::{Reflect, TypeRegistry};
use bevy_reflect::{PartialReflect, Reflect, TypeRegistry};

#[derive(Resource)]
struct TypeRegistryResource {
Expand Down Expand Up @@ -352,7 +352,7 @@ mod tests {
let entity = commands.spawn_empty().id();
let entity2 = commands.spawn_empty().id();

let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
let boxed_reflect_component_a_clone = boxed_reflect_component_a.clone_value();

commands
Expand Down Expand Up @@ -388,7 +388,7 @@ mod tests {

let entity = commands.spawn_empty().id();

let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;

commands
.entity(entity)
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_ecs/src/reflect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut};

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

mod bundle;
mod component;
Expand Down Expand Up @@ -42,7 +42,7 @@ impl DerefMut for AppTypeRegistry {
}
}

/// Creates a `T` from a `&dyn Reflect`.
/// Creates a `T` from a `&dyn PartialReflect`.
///
/// 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
Expand All @@ -51,7 +51,7 @@ impl DerefMut for AppTypeRegistry {
///
/// Panics if both approaches fail.
fn from_reflect_or_world<T: FromReflect>(
reflected: &dyn Reflect,
reflected: &dyn PartialReflect,
world: &mut World,
registry: &TypeRegistry,
) -> T {
Expand Down