Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: "Type data creation and registration changes"
pull_requests: [24518]
---

Type data definition and registration have been reworked to enable `on_insert` and `on_register` registration callbacks.

Type data is no longer automatically implemented on types implementing `Clone`.
Instead, it must be manually implemented or derived:

```rust
// BEFORE
#[derive(Clone)]
struct ReflectSomeTypeData;

// AFTER
#[derive(TypeData)]
struct ReflectSomeTypeData;

// or manually:
// impl TypeData for ReflectSomeTypeData {}
```

Additionally, type data can no longer be inserted directly onto a `&mut TypeRegistration`.
Instead, it must be inserted during construction, with an owned `TypeRegistration`.
This was done to ensure that registration callbacks weren't accidentally missed.

```rust
// BEFORE
let mut registration = TypeRegistration::of::<MyType>();
registration.register_type_data::<SomeTypeData, _>();

// AFTER
let registration = TypeRegistration::of::<MyType>()
.register_type_data::<SomeTypeData, _>();
});
```

Methods for registering type data on the `TypeRegistry` remain unchanged.
However, because of the new restrictions around inserting type data on `TypeRegistration`,
instances of `TypeRegistry::get_mut` can be replaced with the new `TypeRegistry::registration_scope`
in order to insert multiple type data without additional lookups.

```rust
// BEFORE
let registration = registry.get_mut(TypeId::of::<MyType>());
registration.register_type_data::<SomeTypeData, _>();

// AFTER
let registration = registry.registration_scope(TypeId::of::<MyType>(), |mut registration| {
registration.register_type_data::<SomeTypeData, _>();
});
```
6 changes: 3 additions & 3 deletions crates/bevy_asset/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use uuid::Uuid;
use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World};
use bevy_reflect::{
serde::{ReflectDeserializerProcessor, ReflectSerializerProcessor},
CreateTypeData, FromReflect, PartialReflect, Reflect, TypeRegistry,
CreateTypeData, FromReflect, PartialReflect, Reflect, TypeData, TypeRegistry,
};

use crate::{
Expand All @@ -23,7 +23,7 @@ use crate::{
/// until runtime.
///
/// [`ReflectAsset`] can be obtained via [`TypeRegistration::data`](bevy_reflect::TypeRegistration::data) if the asset was registered using [`register_asset_reflect`](crate::AssetApp::register_asset_reflect).
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectAsset {
handle_type_id: TypeId,
assets_resource_type_id: TypeId,
Expand Down Expand Up @@ -228,7 +228,7 @@ impl<A: Asset + FromReflect> CreateTypeData<A> for ReflectAsset {
/// println!("{value:?}");
/// }
/// ```
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectHandle {
asset_type_id: TypeId,
downcast_handle_untyped: fn(&dyn Any) -> Option<UntypedHandle>,
Expand Down
9 changes: 4 additions & 5 deletions crates/bevy_ecs/src/entity/clone_entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1476,7 +1476,7 @@ mod tests {
use super::*;
use crate::reflect::{AppTypeRegistry, ReflectComponent, ReflectFromWorld};
use alloc::vec;
use bevy_reflect::{std_traits::ReflectDefault, CreateTypeData, Reflect, ReflectFromPtr};
use bevy_reflect::{std_traits::ReflectDefault, Reflect, ReflectFromPtr};

#[test]
fn clone_entity_using_reflect() {
Expand Down Expand Up @@ -1614,10 +1614,9 @@ mod tests {
{
let mut registry = registry.write();
registry.register::<A>();
registry
.get_mut(TypeId::of::<A>())
.unwrap()
.insert(<ReflectFromPtr as CreateTypeData<B>>::create_type_data(()));
registry.registration_scope(TypeId::of::<A>(), |mut registration| {
registration.register_type_data::<ReflectFromPtr, B>();
});
}

let e = world.spawn(A).id();
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_ecs/src/reflect/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use crate::{
world::{EntityMut, EntityWorldMut},
};
use bevy_reflect::{
CreateTypeData, FromReflect, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry,
CreateTypeData, FromReflect, PartialReflect, Reflect, ReflectRef, TypeData, TypePath,
TypeRegistry,
};

use super::{from_reflect_with_fallback, ReflectComponent};
Expand All @@ -25,7 +26,7 @@ use super::{from_reflect_with_fallback, ReflectComponent};
///
/// A [`ReflectBundle`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectBundle(ReflectBundleFns);

/// The raw function pointers needed to make up a [`ReflectBundle`].
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_ecs/src/reflect/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ use crate::{
},
};
use alloc::boxed::Box;
use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, Reflect, TypePath, TypeRegistry};
use bevy_reflect::{
CreateTypeData, FromReflect, PartialReflect, Reflect, TypeData, TypePath, TypeRegistry,
};
use bevy_utils::prelude::DebugName;

/// A struct used to operate on reflected [`Component`] trait of a type.
///
/// A [`ReflectComponent`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectComponent(ReflectComponentFns);

/// The raw function pointers needed to make up a [`ReflectComponent`].
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_ecs/src/reflect/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ use crate::{
reflect::from_reflect_with_fallback,
world::{DeferredWorld, World},
};
use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, Reflect, TypePath, TypeRegistry};
use bevy_reflect::{
CreateTypeData, FromReflect, PartialReflect, Reflect, TypeData, TypePath, TypeRegistry,
};

/// A struct used to operate on reflected [`Event`] trait of a type.
///
/// A [`ReflectEvent`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectEvent(ReflectEventFns);

/// The raw function pointers needed to make up a [`ReflectEvent`].
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/reflect/from_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
//! Same as [`component`](`super::component`), but for [`FromWorld`].

use alloc::boxed::Box;
use bevy_reflect::{CreateTypeData, Reflect};
use bevy_reflect::{CreateTypeData, Reflect, TypeData};

use crate::world::{FromWorld, World};

/// A struct used to operate on the reflected [`FromWorld`] trait of a type.
///
/// A [`ReflectFromWorld`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectFromWorld(ReflectFromWorldFns);

/// The raw function pointers needed to make up a [`ReflectFromWorld`].
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/reflect/map_entities.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::entity::{EntityMapper, MapEntities};
use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect};
use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, TypeData};

/// For a specific type of value, this maps any fields with values of type [`Entity`] to a new world.
///
Expand All @@ -10,7 +10,7 @@ use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect};
///
/// [`Entity`]: crate::entity::Entity
/// [`EntityMapper`]: crate::entity::EntityMapper
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectMapEntities {
map_entities: fn(&mut dyn PartialReflect, &mut dyn EntityMapper),
}
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_ecs/src/reflect/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
//! Same as [`component`](`super::component`), but for messages.

use crate::{message::Message, reflect::from_reflect_with_fallback, world::World};
use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, Reflect, TypePath, TypeRegistry};
use bevy_reflect::{
CreateTypeData, FromReflect, PartialReflect, Reflect, TypeData, TypePath, TypeRegistry,
};

/// A struct used to operate on reflected [`Message`] trait of a type.
///
/// A [`ReflectMessage`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectMessage(ReflectMessageFns);

/// The raw function pointers needed to make up a [`ReflectMessage`].
Expand Down
10 changes: 6 additions & 4 deletions crates/bevy_ecs/src/reflect/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! See the module doc for [`reflect::component`](`crate::reflect::component`).

use crate::{reflect::ReflectComponent, resource::Resource};
use bevy_reflect::{CreateTypeData, FromReflect, TypePath, TypeRegistration};
use bevy_reflect::{CreateTypeData, FromReflect, OnInsertTypeData, TypeData, TypePath};

/// A struct that marks a reflected [`Resource`] of a type.
///
Expand All @@ -27,15 +27,17 @@ use bevy_reflect::{CreateTypeData, FromReflect, TypePath, TypeRegistration};
///
/// A [`ReflectResource`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
#[derive(Clone, TypeData)]
pub struct ReflectResource;

impl<R: Resource + FromReflect + TypePath> CreateTypeData<R> for ReflectResource {
fn create_type_data(_input: ()) -> Self {
ReflectResource
}

fn insert_dependencies(type_registration: &mut TypeRegistration) {
type_registration.register_type_data::<ReflectComponent, R>();
fn on_insert(_: &()) -> Option<OnInsertTypeData> {
Some(OnInsertTypeData::new(|mut registration| {
registration.register_type_data::<ReflectComponent, R>();
}))
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy_reflect::{CreateTypeData, Reflect};
use bevy_reflect::{CreateTypeData, Reflect, TypeData};
use core::marker::PhantomData;

#[derive(Clone)]
#[derive(TypeData)]
struct ReflectMyTrait;

impl<T> CreateTypeData<T> for ReflectMyTrait {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//@check-pass
use bevy_reflect::{CreateTypeData, Reflect};
use bevy_reflect::{CreateTypeData, Reflect, TypeData};
use core::marker::PhantomData;

#[derive(Clone)]
#[derive(TypeData)]
struct ReflectMyTrait;

impl<T> CreateTypeData<T> for ReflectMyTrait {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@no-rustfix
use bevy_reflect::{CreateTypeData, Reflect};
use bevy_reflect::{CreateTypeData, Reflect, TypeData};

#[derive(Clone)]
#[derive(TypeData)]
struct ReflectMyTrait;

impl<T> CreateTypeData<T, f32> for ReflectMyTrait {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@check-pass
use bevy_reflect::{CreateTypeData, Reflect};
use bevy_reflect::{CreateTypeData, Reflect, TypeData};

#[derive(Clone)]
#[derive(TypeData)]
struct ReflectMyTrait;

impl<T> CreateTypeData<T> for ReflectMyTrait {
Expand Down
15 changes: 15 additions & 0 deletions crates/bevy_reflect/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,21 @@ pub fn derive_type_path(input: TokenStream) -> TokenStream {
})
}

/// Derives the `TypeData` trait.
#[proc_macro_derive(TypeData)]
pub fn derive_type_data(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let ident = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let bevy_reflect_path = meta::get_bevy_reflect_path();

TokenStream::from(quote! {
const _: () = {
impl #impl_generics #bevy_reflect_path::TypeData for #ident #ty_generics #where_clause {}
};
})
}

/// A macro that automatically generates type data for traits, which their implementors can then register.
///
/// The output of this macro is a struct that takes reflected instances of the implementor's type
Expand Down
17 changes: 8 additions & 9 deletions crates/bevy_reflect/derive/src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ pub(crate) fn impl_get_type_registration<'a>(

let from_reflect_data = if meta.from_reflect().should_auto_derive() {
Some(quote! {
registration.insert(
.insert_data(
<#bevy_reflect_path::ReflectFromReflect as #bevy_reflect_path::CreateTypeData<Self>>::create_type_data(())
);
)
})
} else {
None
Expand All @@ -39,7 +39,7 @@ pub(crate) fn impl_get_type_registration<'a>(
let serialization_data = serialization_data.map(|data| {
let serialization_data = data.as_serialization_data(bevy_reflect_path);
quote! {
registration.insert::<#bevy_reflect_path::serde::SerializationData>(#serialization_data);
.insert_data::<#bevy_reflect_path::serde::SerializationData>(#serialization_data)
}
});

Expand All @@ -56,21 +56,20 @@ pub(crate) fn impl_get_type_registration<'a>(
};

quote! {
registration.register_type_data_with::<#reflect_ident, Self, _>(#args);
.register_type_data_with::<#reflect_ident, Self, _>(#args)
}
});

quote! {
impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_path #ty_generics #where_reflect_clause {
fn get_type_registration() -> #bevy_reflect_path::TypeRegistration {
let mut registration = #bevy_reflect_path::TypeRegistration::of::<Self>();
registration.insert(
<#bevy_reflect_path::ReflectFromPtr as #bevy_reflect_path::CreateTypeData::<Self>>::create_type_data(())
);
#bevy_reflect_path::TypeRegistration::of::<Self>()
.insert_data(
<#bevy_reflect_path::ReflectFromPtr as #bevy_reflect_path::CreateTypeData::<Self>>::create_type_data(())
)
#from_reflect_data
#serialization_data
#(#type_data)*
registration
}

#type_deps_fn
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_reflect/derive/src/trait_reflection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStr
}
}

impl #bevy_reflect_path::TypeData for #reflect_trait_ident {}

impl<T: #trait_ident + #bevy_reflect_path::Reflect> #bevy_reflect_path::CreateTypeData<T> for #reflect_trait_ident {
fn create_type_data(_input: ()) -> Self {
Self {
Expand Down
11 changes: 5 additions & 6 deletions crates/bevy_reflect/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use core::{any::TypeId, marker::PhantomData};

use bevy_utils::TypeIdMap;

use crate::{Reflect, TypePath};
use crate::{Reflect, TypeData, TypePath};

/// Provides a mechanism for converting values of one type to another.
///
Expand All @@ -32,7 +32,7 @@ use crate::{Reflect, TypePath};
/// .downcast::<String>()
/// .unwrap();
/// ```
#[derive(Default)]
#[derive(Default, TypeData)]
pub struct ReflectConvert {
/// A mapping from the type to be converted *from* to its associated
/// [`Converter`].
Expand Down Expand Up @@ -257,10 +257,9 @@ mod tests {
let mut registry = TypeRegistry::default();
registry.add_registration(i32::get_type_registration());
registry.add_registration(String::get_type_registration());
registry
.get_mut(TypeId::of::<i32>())
.unwrap()
.insert(ReflectConvert::default());
registry.registration_scope(TypeId::of::<i32>(), |mut registration| {
registration.insert_data(ReflectConvert::default());
});

let reflect_convert = registry
.get_type_data::<ReflectConvert>(TypeId::of::<i32>())
Expand Down
Loading
Loading