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

[Merged by Bors] - Enable Constructing ReflectComponent/Resource #6257

Closed
Closed
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
184 changes: 148 additions & 36 deletions crates/bevy_ecs/src/reflect.rs
Expand Up @@ -17,14 +17,55 @@ use bevy_reflect::{
/// A [`ReflectComponent`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectComponent {
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<Mut<dyn Reflect>>,
copy: fn(&World, &mut World, Entity, Entity),
pub struct ReflectComponent(ReflectComponentFns);

/// The raw function pointers needed to make up a [`ReflectComponent`].
///
/// This is used when creating custom implementations of [`ReflectComponent`] with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should link to / explain the simpler way here. Ditto for the resource equivalent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We should probably also include it in the docs for the constructors (e.g. ReflectComponent::new) as well, and indicate that this is almost certainly not needed unless you know what you're doing.

/// [`ReflectComponent::new()`].
///
/// > **Note:**
/// > Creating custom implementations of [`ReflectComponent`] is an advanced feature that most users
/// > will not need.
/// > Usually a [`ReflectComponent`] is created for a type by deriving [`Reflect`]
/// > and adding the `#[reflect(Component)]` attribute.
/// > After adding the component to the [`TypeRegistry`][bevy_reflect::TypeRegistry],
/// > it's [`ReflectComponent`] can then be retrieved when needed.
zicklag marked this conversation as resolved.
Show resolved Hide resolved
///
/// Creating a custom [`ReflectComponent`] may be useful if you need to create new component types
/// at runtime, for example, for scripting implementations.
///
/// By creating a custom [`ReflectComponent`] and inserting it into a type's
/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
/// you can modify the way that reflected components of that type will be inserted into the Bevy
/// world.
#[derive(Clone)]
pub struct ReflectComponentFns {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these structs have their own ReflectComponentFns::new<T: Component>() -> Self functions to fill in the entire struct, allowing individual modification if needed? Or does it not make sense to only override some but not all function pointers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's actually a good idea. I'm not 100% sure that there will be a use for overriding only some options, but it seems like it could happen.

/// Function pointer implementing [`ReflectComponent::insert()`].
pub insert: fn(&mut World, Entity, &dyn Reflect),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a doc comment for each of these (same for ReflectResourceFns)? I imagine the people who do need this could benefit from knowing what they actually do.

/// Function pointer implementing [`ReflectComponent::apply()`].
pub apply: fn(&mut World, Entity, &dyn Reflect),
/// Function pointer implementing [`ReflectComponent::apply_or_insert()`].
pub apply_or_insert: fn(&mut World, Entity, &dyn Reflect),
/// Function pointer implementing [`ReflectComponent::remove()`].
pub remove: fn(&mut World, Entity),
/// Function pointer implementing [`ReflectComponent::reflect()`].
pub reflect: fn(&World, Entity) -> Option<&dyn Reflect>,
/// Function pointer implementing [`ReflectComponent::reflect_mut()`].
pub reflect_mut: unsafe fn(&World, Entity) -> Option<Mut<dyn Reflect>>,
/// Function pointer implementing [`ReflectComponent::copy()`].
pub copy: fn(&World, &mut World, Entity, Entity),
}

impl ReflectComponentFns {
/// Get the default set of [`ReflectComponentFns`] for a specific component type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Component + Reflect + FromWorld>() -> Self {
<ReflectComponent as FromType<T>>::from_type().0
}
}

impl ReflectComponent {
Expand All @@ -34,7 +75,7 @@ impl ReflectComponent {
///
/// Panics if there is no such entity.
pub fn insert(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.insert)(world, entity, component);
(self.0.insert)(world, entity, component);
}

/// Uses reflection to set the value of this [`Component`] type in the entity to the given value.
Expand All @@ -43,7 +84,7 @@ impl ReflectComponent {
///
/// Panics if there is no [`Component`] of the given type or the `entity` does not exist.
pub fn apply(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.apply)(world, entity, component);
(self.0.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.
Expand All @@ -52,7 +93,7 @@ impl ReflectComponent {
///
/// 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);
(self.0.apply_or_insert)(world, entity, component);
}

/// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist.
Expand All @@ -61,12 +102,12 @@ impl ReflectComponent {
///
/// Panics if there is no [`Component`] of the given type or the `entity` does not exist.
pub fn remove(&self, world: &mut World, entity: Entity) {
(self.remove)(world, entity);
(self.0.remove)(world, entity);
}

/// Gets the value of this [`Component`] type from the entity as a reflected reference.
pub fn reflect<'a>(&self, world: &'a World, entity: Entity) -> Option<&'a dyn Reflect> {
(self.reflect)(world, entity)
(self.0.reflect)(world, entity)
}

/// Gets the value of this [`Component`] type from the entity as a mutable reflected reference.
Expand All @@ -76,7 +117,7 @@ impl ReflectComponent {
entity: Entity,
) -> Option<Mut<'a, dyn Reflect>> {
// SAFETY: unique world access
unsafe { (self.reflect_mut)(world, entity) }
unsafe { (self.0.reflect_mut)(world, entity) }
}

/// # Safety
Expand All @@ -90,7 +131,7 @@ impl ReflectComponent {
world: &'a World,
entity: Entity,
) -> Option<Mut<'a, dyn Reflect>> {
(self.reflect_mut)(world, entity)
(self.0.reflect_mut)(world, entity)
}

/// Gets the value of this [`Component`] type from entity from `source_world` and [applies](Self::apply()) it to the value of this [`Component`] type in entity in `destination_world`.
Expand All @@ -105,18 +146,33 @@ impl ReflectComponent {
source_entity: Entity,
destination_entity: Entity,
) {
(self.copy)(
(self.0.copy)(
source_world,
destination_world,
source_entity,
destination_entity,
);
}

/// Create a custom implementation of [`ReflectComponent`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Component)]` component
/// to generate a [`ReflectComponent`] implementation automatically.
///
/// See [`ReflectComponentFns`] for more information.
pub fn new(fns: ReflectComponentFns) -> Self {
Self(fns)
}
}

impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
fn from_type() -> Self {
ReflectComponent {
ReflectComponent(ReflectComponentFns {
insert: |world, entity, reflected_component| {
let mut component = C::from_world(world);
component.apply(reflected_component);
Expand Down Expand Up @@ -165,7 +221,7 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
})
}
},
}
})
}
}

Expand All @@ -174,20 +230,61 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
/// A [`ReflectResource`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
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<Mut<dyn Reflect>>,
copy: fn(&World, &mut World),
pub struct ReflectResource(ReflectResourceFns);

/// The raw function pointers needed to make up a [`ReflectResource`].
///
/// This is used when creating custom implementations of [`ReflectResource`] with
/// [`ReflectResource::new()`].
///
/// > **Note:**
/// > Creating custom implementations of [`ReflectResource`] is an advanced feature that most users
/// > will not need.
/// > Usually a [`ReflectResource`] is created for a type by deriving [`Reflect`]
/// > and adding the `#[reflect(Resource)]` attribute.
/// > After adding the component to the [`TypeRegistry`][bevy_reflect::TypeRegistry],
/// > it's [`ReflectResource`] can then be retrieved when needed.
zicklag marked this conversation as resolved.
Show resolved Hide resolved
///
/// Creating a custom [`ReflectResource`] may be useful if you need to create new resource types at
/// runtime, for example, for scripting implementations.
///
/// By creating a custom [`ReflectResource`] and inserting it into a type's
/// [`TypeRegistration`][bevy_reflect::TypeRegistration],
/// you can modify the way that reflected resources of that type will be inserted into the bevy
/// world.
#[derive(Clone)]
pub struct ReflectResourceFns {
/// Function pointer implementing [`ReflectResource::insert()`].
pub insert: fn(&mut World, &dyn Reflect),
/// Function pointer implementing [`ReflectResource::apply()`].
pub apply: fn(&mut World, &dyn Reflect),
/// Function pointer implementing [`ReflectResource::apply_or_insert()`].
pub apply_or_insert: fn(&mut World, &dyn Reflect),
/// Function pointer implementing [`ReflectResource::remove()`].
pub remove: fn(&mut World),
/// Function pointer implementing [`ReflectResource::reflect()`].
pub reflect: fn(&World) -> Option<&dyn Reflect>,
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
pub reflect_unchecked_mut: unsafe fn(&World) -> Option<Mut<dyn Reflect>>,
/// Function pointer implementing [`ReflectResource::copy()`].
pub copy: fn(&World, &mut World),
}

impl ReflectResourceFns {
/// Get the default set of [`ReflectResourceFns`] for a specific resource type using its
/// [`FromType`] implementation.
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Resource + Reflect + FromWorld>() -> Self {
<ReflectResource as FromType<T>>::from_type().0
}
}

impl ReflectResource {
/// Insert a reflected [`Resource`] into the world like [`insert()`](World::insert_resource).
pub fn insert(&self, world: &mut World, resource: &dyn Reflect) {
(self.insert)(world, resource);
(self.0.insert)(world, resource);
}

/// Uses reflection to set the value of this [`Resource`] type in the world to the given value.
Expand All @@ -196,28 +293,28 @@ impl ReflectResource {
///
/// Panics if there is no [`Resource`] of the given type.
pub fn apply(&self, world: &mut World, resource: &dyn Reflect) {
(self.apply)(world, resource);
(self.0.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);
(self.0.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);
(self.0.remove)(world);
}

/// Gets the value of this [`Resource`] type from the world as a reflected reference.
pub fn reflect<'a>(&self, world: &'a World) -> Option<&'a dyn Reflect> {
(self.reflect)(world)
(self.0.reflect)(world)
}

/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
pub fn reflect_mut<'a>(&self, world: &'a mut World) -> Option<Mut<'a, dyn Reflect>> {
// SAFETY: unique world access
unsafe { (self.reflect_unchecked_mut)(world) }
unsafe { (self.0.reflect_unchecked_mut)(world) }
}

/// # Safety
Expand All @@ -231,7 +328,7 @@ impl ReflectResource {
world: &'a World,
) -> Option<Mut<'a, dyn Reflect>> {
// SAFETY: caller promises to uphold uniqueness guarantees
(self.reflect_unchecked_mut)(world)
(self.0.reflect_unchecked_mut)(world)
}

/// Gets the value of this [`Resource`] type from `source_world` and [applies](Self::apply()) it to the value of this [`Resource`] type in `destination_world`.
Expand All @@ -240,13 +337,28 @@ impl ReflectResource {
///
/// Panics if there is no [`Resource`] of the given type.
pub fn copy(&self, source_world: &World, destination_world: &mut World) {
(self.copy)(source_world, destination_world);
(self.0.copy)(source_world, destination_world);
}

/// Create a custom implementation of [`ReflectResource`].
///
/// This is an advanced feature,
/// useful for scripting implementations,
/// that should not be used by most users
/// unless you know what you are doing.
///
/// Usually you should derive [`Reflect`] and add the `#[reflect(Resource)]` component
/// to generate a [`ReflectResource`] implementation automatically.
///
/// See [`ReflectResourceFns`] for more information.
pub fn new(&self, fns: ReflectResourceFns) -> Self {
Self(fns)
}
}

impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
fn from_type() -> Self {
ReflectResource {
ReflectResource(ReflectResourceFns {
insert: |world, reflected_resource| {
let mut resource = C::from_world(world);
resource.apply(reflected_resource);
Expand Down Expand Up @@ -285,7 +397,7 @@ impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
destination_resource.apply(source_resource);
destination_world.insert_resource(destination_resource);
},
}
})
}
}

Expand Down