diff --git a/_release-content/migration-guides/bevy_reflect_parameterized_type_data.md b/_release-content/migration-guides/bevy_reflect_parameterized_type_data.md new file mode 100644 index 0000000000000..5d929c4846bb1 --- /dev/null +++ b/_release-content/migration-guides/bevy_reflect_parameterized_type_data.md @@ -0,0 +1,36 @@ +--- +title: "`FromType` replaced by `CreateTypeData`" +pull_requests: [13723] +--- + +`FromType` has been replaced by `CreateTypeData`. +This was done to better communicate what the trait was for (i.e. creating type data), +as well as make it possible to pass in additional input when registering type data. + +Implementors of `FromType` will need to update their implementation: + +```rust +// BEFORE +impl FromType for ReflectMyTrait { + fn from_type() -> Self { + // ... + } +} + +// AFTER +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(input: ()) -> Self { + // ... + } +} +``` + +Additionally, any calls made to `FromType::from_type` will need to be updated as well: + +```rust +// BEFORE +>::from_type() + +// AFTER +>::create_type_data(()) +``` diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index b78fbedd1a241..80e7bd5ecb63a 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -23,7 +23,7 @@ use bevy_ecs::{ }; use bevy_platform::collections::HashMap; #[cfg(feature = "bevy_reflect")] -use bevy_reflect::{FromType, Reflect, TypeData, TypePath}; +use bevy_reflect::{CreateTypeData, Reflect, TypePath}; use core::{fmt::Debug, num::NonZero, panic::AssertUnwindSafe}; use log::debug; @@ -687,9 +687,7 @@ impl App { /// /// See [`bevy_reflect::TypeRegistry::register_type_data`]. #[cfg(feature = "bevy_reflect")] - pub fn register_type_data>( - &mut self, - ) -> &mut Self { + pub fn register_type_data>(&mut self) -> &mut Self { self.main_mut().register_type_data::(); self } diff --git a/crates/bevy_app/src/sub_app.rs b/crates/bevy_app/src/sub_app.rs index 1b20aab2ff5d3..795e0199c8d45 100644 --- a/crates/bevy_app/src/sub_app.rs +++ b/crates/bevy_app/src/sub_app.rs @@ -476,7 +476,7 @@ impl SubApp { #[cfg(feature = "bevy_reflect")] pub fn register_type_data< T: bevy_reflect::Reflect + bevy_reflect::TypePath, - D: bevy_reflect::TypeData + bevy_reflect::FromType, + D: bevy_reflect::CreateTypeData, >( &mut self, ) -> &mut Self { diff --git a/crates/bevy_asset/src/reflect.rs b/crates/bevy_asset/src/reflect.rs index a88b1b408b5a8..5a36c43e4ec08 100644 --- a/crates/bevy_asset/src/reflect.rs +++ b/crates/bevy_asset/src/reflect.rs @@ -8,7 +8,7 @@ use uuid::Uuid; use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World}; use bevy_reflect::{ serde::{ReflectDeserializerProcessor, ReflectSerializerProcessor}, - FromReflect, FromType, PartialReflect, Reflect, TypeRegistry, + CreateTypeData, FromReflect, PartialReflect, Reflect, TypeRegistry, }; use crate::{ @@ -156,8 +156,8 @@ impl ReflectAsset { } } -impl FromType for ReflectAsset { - fn from_type() -> Self { +impl CreateTypeData for ReflectAsset { + fn create_type_data(_input: ()) -> Self { ReflectAsset { handle_type_id: TypeId::of::>(), assets_resource_type_id: TypeId::of::>(), @@ -253,8 +253,8 @@ impl ReflectHandle { } } -impl FromType> for ReflectHandle { - fn from_type() -> Self { +impl CreateTypeData> for ReflectHandle { + fn create_type_data(_input: ()) -> Self { ReflectHandle { asset_type_id: TypeId::of::(), downcast_handle_untyped: |handle: &dyn Any| { diff --git a/crates/bevy_ecs/src/change_detection/mod.rs b/crates/bevy_ecs/src/change_detection/mod.rs index 0b8ce3a8f33ee..265b11e2d2981 100644 --- a/crates/bevy_ecs/src/change_detection/mod.rs +++ b/crates/bevy_ecs/src/change_detection/mod.rs @@ -29,7 +29,7 @@ pub const MAX_CHANGE_AGE: u32 = u32::MAX - (2 * CHECK_TICK_THRESHOLD - 1); mod tests { use bevy_ecs_macros::Resource; use bevy_ptr::PtrMut; - use bevy_reflect::{FromType, ReflectFromPtr}; + use bevy_reflect::{CreateTypeData, ReflectFromPtr}; use core::ops::{Deref, DerefMut}; use crate::{ @@ -341,7 +341,7 @@ mod tests { ticks, }; - let reflect_from_ptr = >::from_type(); + let reflect_from_ptr = >::create_type_data(()); let mut new = value.map_unchanged(|ptr| { // SAFETY: The underlying type of `ptr` matches `reflect_from_ptr`. diff --git a/crates/bevy_ecs/src/entity/clone_entities.rs b/crates/bevy_ecs/src/entity/clone_entities.rs index 2ff9d1ebd3e45..aa3bdd52237a4 100644 --- a/crates/bevy_ecs/src/entity/clone_entities.rs +++ b/crates/bevy_ecs/src/entity/clone_entities.rs @@ -1476,7 +1476,7 @@ mod tests { use super::*; use crate::reflect::{AppTypeRegistry, ReflectComponent, ReflectFromWorld}; use alloc::vec; - use bevy_reflect::{std_traits::ReflectDefault, FromType, Reflect, ReflectFromPtr}; + use bevy_reflect::{std_traits::ReflectDefault, CreateTypeData, Reflect, ReflectFromPtr}; #[test] fn clone_entity_using_reflect() { @@ -1617,7 +1617,7 @@ mod tests { registry .get_mut(TypeId::of::()) .unwrap() - .insert(>::from_type()); + .insert(>::create_type_data(())); } let e = world.spawn(A).id(); diff --git a/crates/bevy_ecs/src/reflect/bundle.rs b/crates/bevy_ecs/src/reflect/bundle.rs index 935f2aad300db..244da020a0cde 100644 --- a/crates/bevy_ecs/src/reflect/bundle.rs +++ b/crates/bevy_ecs/src/reflect/bundle.rs @@ -16,7 +16,7 @@ use crate::{ world::{EntityMut, EntityWorldMut}, }; use bevy_reflect::{ - FromReflect, FromType, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry, + CreateTypeData, FromReflect, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry, }; use super::{from_reflect_with_fallback, ReflectComponent}; @@ -53,12 +53,12 @@ pub struct ReflectBundleFns { impl ReflectBundleFns { /// Get the default set of [`ReflectBundleFns`] for a specific bundle type using its - /// [`FromType`] implementation. + /// [`CreateTypeData`] 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() -> Self { - >::from_type().0 + >::create_type_data(()).0 } } @@ -148,8 +148,8 @@ impl ReflectBundle { } } -impl FromType for ReflectBundle { - fn from_type() -> Self { +impl CreateTypeData for ReflectBundle { + fn create_type_data(_input: ()) -> Self { ReflectBundle(ReflectBundleFns { insert: |entity, reflected_bundle, registry| { let bundle = entity.world_scope(|world| { diff --git a/crates/bevy_ecs/src/reflect/component.rs b/crates/bevy_ecs/src/reflect/component.rs index ec564500c6daa..d237a8f61f91f 100644 --- a/crates/bevy_ecs/src/reflect/component.rs +++ b/crates/bevy_ecs/src/reflect/component.rs @@ -16,14 +16,14 @@ //! [`get_type_registration`] method (see the relevant code[^1]). //! //! ``` -//! # use bevy_reflect::{FromType, Reflect}; +//! # use bevy_reflect::{CreateTypeData, Reflect}; //! # use bevy_ecs::prelude::{ReflectComponent, Component}; //! # #[derive(Default, Reflect, Component)] //! # struct A; //! # impl A { //! # fn foo() { //! # let mut registration = bevy_reflect::TypeRegistration::of::(); -//! registration.insert::(FromType::::from_type()); +//! registration.insert::(CreateTypeData::::create_type_data(())); //! # } //! # } //! ``` @@ -32,10 +32,10 @@ //! The user can access the `ReflectComponent` for type `T` through the type registry, //! as per the `trait_reflection.rs` example. //! -//! The `FromType::::from_type()` in the previous line calls the `FromType` -//! implementation of `ReflectComponent`. +//! The `CreateTypeData::::create_type_data(())` in the previous line calls the +//! `CreateTypeData` implementation of `ReflectComponent`. //! -//! The `FromType` impl creates a function per field of [`ReflectComponentFns`]. +//! The `CreateTypeData` impl creates a function per field of [`ReflectComponentFns`]. //! In those functions, we call generic methods on [`World`] and [`EntityWorldMut`]. //! //! The result is a `ReflectComponent` completely independent of `C`, yet capable @@ -70,7 +70,7 @@ use crate::{ }, }; use alloc::boxed::Box; -use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; +use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, Reflect, TypePath, TypeRegistry}; use bevy_utils::prelude::DebugName; /// A struct used to operate on reflected [`Component`] trait of a type. @@ -139,12 +139,12 @@ pub struct ReflectComponentFns { impl ReflectComponentFns { /// Get the default set of [`ReflectComponentFns`] for a specific component type using its - /// [`FromType`] implementation. + /// [`CreateTypeData`] 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() -> Self { - >::from_type().0 + >::create_type_data(()).0 } } @@ -306,8 +306,8 @@ impl ReflectComponent { } } -impl FromType for ReflectComponent { - fn from_type() -> Self { +impl CreateTypeData for ReflectComponent { + fn create_type_data(_input: ()) -> Self { // TODO: Currently we panic if a component is immutable and you use // reflection to mutate it. Perhaps the mutation methods should be fallible? ReflectComponent(ReflectComponentFns { diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index c80c464635f25..0fd192110fbe7 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -37,7 +37,7 @@ pub trait ReflectCommandExt { /// /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle}; - /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// # use bevy_reflect::{FromReflect, CreateTypeData, Reflect, TypeRegistry}; /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] /// struct Prefab { @@ -125,7 +125,7 @@ pub trait ReflectCommandExt { /// /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle}; - /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// # use bevy_reflect::{FromReflect, CreateTypeData, Reflect, TypeRegistry}; /// /// // A resource that can hold any component or bundle that implements reflect as a boxed reflect /// #[derive(Resource)] diff --git a/crates/bevy_ecs/src/reflect/event.rs b/crates/bevy_ecs/src/reflect/event.rs index 417d717c7da75..b6c9d3f93915d 100644 --- a/crates/bevy_ecs/src/reflect/event.rs +++ b/crates/bevy_ecs/src/reflect/event.rs @@ -13,7 +13,7 @@ use crate::{ reflect::from_reflect_with_fallback, world::{DeferredWorld, World}, }; -use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; +use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, Reflect, TypePath, TypeRegistry}; /// A struct used to operate on reflected [`Event`] trait of a type. /// @@ -52,7 +52,7 @@ pub struct ReflectEventFns { impl ReflectEventFns { /// Get the default set of [`ReflectEventFns`] for a specific event type - /// using its [`FromType`] implementation. + /// using its [`CreateTypeData`] implementation. /// /// This is useful if you want to start with the default implementation /// before overriding some of the functions to create a custom implementation. @@ -60,7 +60,7 @@ impl ReflectEventFns { where T::Trigger<'a>: Default, { - >::from_type().0 + >::create_type_data(()).0 } } @@ -122,11 +122,11 @@ impl ReflectEvent { } } -impl<'a, E: Event + Reflect + TypePath> FromType for ReflectEvent +impl<'a, E: Event + Reflect + TypePath> CreateTypeData for ReflectEvent where ::Trigger<'a>: Default, { - fn from_type() -> Self { + fn create_type_data(_input: ()) -> Self { ReflectEvent(ReflectEventFns { trigger: |world, reflected_event, registry| { let event = from_reflect_with_fallback::(reflected_event, world, registry); diff --git a/crates/bevy_ecs/src/reflect/from_world.rs b/crates/bevy_ecs/src/reflect/from_world.rs index 62ab4438f9e68..d133c5eba15aa 100644 --- a/crates/bevy_ecs/src/reflect/from_world.rs +++ b/crates/bevy_ecs/src/reflect/from_world.rs @@ -7,7 +7,7 @@ //! Same as [`component`](`super::component`), but for [`FromWorld`]. use alloc::boxed::Box; -use bevy_reflect::{FromType, Reflect}; +use bevy_reflect::{CreateTypeData, Reflect}; use crate::world::{FromWorld, World}; @@ -27,12 +27,12 @@ pub struct ReflectFromWorldFns { impl ReflectFromWorldFns { /// Get the default set of [`ReflectFromWorldFns`] for a specific type using its - /// [`FromType`] implementation. + /// [`CreateTypeData`] 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() -> Self { - >::from_type().0 + >::create_type_data(()).0 } } @@ -78,8 +78,8 @@ impl ReflectFromWorld { } } -impl FromType for ReflectFromWorld { - fn from_type() -> Self { +impl CreateTypeData for ReflectFromWorld { + fn create_type_data(_input: ()) -> Self { ReflectFromWorld(ReflectFromWorldFns { from_world: |world| Box::new(B::from_world(world)), }) diff --git a/crates/bevy_ecs/src/reflect/map_entities.rs b/crates/bevy_ecs/src/reflect/map_entities.rs index 04fc25579906d..04b597ab9c953 100644 --- a/crates/bevy_ecs/src/reflect/map_entities.rs +++ b/crates/bevy_ecs/src/reflect/map_entities.rs @@ -1,5 +1,5 @@ use crate::entity::{EntityMapper, MapEntities}; -use bevy_reflect::{FromReflect, FromType, PartialReflect}; +use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect}; /// For a specific type of value, this maps any fields with values of type [`Entity`] to a new world. /// @@ -25,8 +25,8 @@ impl ReflectMapEntities { } } -impl FromType for ReflectMapEntities { - fn from_type() -> Self { +impl CreateTypeData for ReflectMapEntities { + fn create_type_data(_input: ()) -> Self { ReflectMapEntities { map_entities: |reflected, mut mapper| { let mut concrete = C::from_reflect(reflected).expect("reflected type should match"); diff --git a/crates/bevy_ecs/src/reflect/message.rs b/crates/bevy_ecs/src/reflect/message.rs index ba2c7b03556f5..fce5ab5245e11 100644 --- a/crates/bevy_ecs/src/reflect/message.rs +++ b/crates/bevy_ecs/src/reflect/message.rs @@ -6,7 +6,7 @@ //! Same as [`component`](`super::component`), but for messages. use crate::{message::Message, reflect::from_reflect_with_fallback, world::World}; -use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; +use bevy_reflect::{CreateTypeData, FromReflect, PartialReflect, Reflect, TypePath, TypeRegistry}; /// A struct used to operate on reflected [`Message`] trait of a type. /// @@ -41,12 +41,12 @@ pub struct ReflectMessageFns { impl ReflectMessageFns { /// Get the default set of [`ReflectMessageFns`] for a specific event type - /// using its [`FromType`] implementation. + /// using its [`CreateTypeData`] 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() -> Self { - >::from_type().0 + >::create_type_data(()).0 } } @@ -97,8 +97,8 @@ impl ReflectMessage { } } -impl FromType for ReflectMessage { - fn from_type() -> Self { +impl CreateTypeData for ReflectMessage { + fn create_type_data(_input: ()) -> Self { ReflectMessage(ReflectMessageFns { write_message: |world, reflected_message, registry| { let message = from_reflect_with_fallback::(reflected_message, world, registry); diff --git a/crates/bevy_ecs/src/reflect/resource.rs b/crates/bevy_ecs/src/reflect/resource.rs index a867680346ee3..74dc3a0e0306e 100644 --- a/crates/bevy_ecs/src/reflect/resource.rs +++ b/crates/bevy_ecs/src/reflect/resource.rs @@ -5,7 +5,7 @@ //! See the module doc for [`reflect::component`](`crate::reflect::component`). use crate::{reflect::ReflectComponent, resource::Resource}; -use bevy_reflect::{FromReflect, FromType, TypePath, TypeRegistration}; +use bevy_reflect::{CreateTypeData, FromReflect, TypePath, TypeRegistration}; /// A struct that marks a reflected [`Resource`] of a type. /// @@ -30,8 +30,8 @@ use bevy_reflect::{FromReflect, FromType, TypePath, TypeRegistration}; #[derive(Clone)] pub struct ReflectResource; -impl FromType for ReflectResource { - fn from_type() -> Self { +impl CreateTypeData for ReflectResource { + fn create_type_data(_input: ()) -> Self { ReflectResource } diff --git a/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_fail.rs b/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_fail.rs index 28370ca7555de..379ecd18b201a 100644 --- a/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_fail.rs +++ b/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_fail.rs @@ -1,11 +1,11 @@ -use bevy_reflect::{FromType, Reflect}; +use bevy_reflect::{CreateTypeData, Reflect}; use core::marker::PhantomData; #[derive(Clone)] struct ReflectMyTrait; -impl FromType for ReflectMyTrait { - fn from_type() -> Self { +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(_input: ()) -> Self { Self } } diff --git a/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_pass.rs b/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_pass.rs index 456afd35f5240..02e62f737d281 100644 --- a/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_pass.rs +++ b/crates/bevy_reflect/compile_fail/tests/reflect_derive/custom_where_pass.rs @@ -1,12 +1,12 @@ //@check-pass -use bevy_reflect::{FromType, Reflect}; +use bevy_reflect::{CreateTypeData, Reflect}; use core::marker::PhantomData; #[derive(Clone)] struct ReflectMyTrait; -impl FromType for ReflectMyTrait { - fn from_type() -> Self { +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(_input: ()) -> Self { Self } } diff --git a/crates/bevy_reflect/compile_fail/tests/reflect_derive/type_data_fail.rs b/crates/bevy_reflect/compile_fail/tests/reflect_derive/type_data_fail.rs new file mode 100644 index 0000000000000..dcad3bc56a84f --- /dev/null +++ b/crates/bevy_reflect/compile_fail/tests/reflect_derive/type_data_fail.rs @@ -0,0 +1,21 @@ +//@no-rustfix +use bevy_reflect::{CreateTypeData, Reflect}; + +#[derive(Clone)] +struct ReflectMyTrait; + +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(_: f32) -> Self { + todo!() + } +} + +#[derive(Reflect)] +#[reflect(MyTrait)] +//~^ ERROR: mismatched types +struct RequiredArgs; + +#[derive(Reflect)] +#[reflect(MyTrait(123))] +//~^ ERROR: mismatched types +struct WrongArgs; diff --git a/crates/bevy_reflect/compile_fail/tests/reflect_derive/type_data_pass.rs b/crates/bevy_reflect/compile_fail/tests/reflect_derive/type_data_pass.rs new file mode 100644 index 0000000000000..db2c8c67e3f53 --- /dev/null +++ b/crates/bevy_reflect/compile_fail/tests/reflect_derive/type_data_pass.rs @@ -0,0 +1,35 @@ +//@check-pass +use bevy_reflect::{CreateTypeData, Reflect}; + +#[derive(Clone)] +struct ReflectMyTrait; + +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(_: ()) -> Self { + todo!() + } +} + +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(_: i32) -> Self { + todo!() + } +} + +impl CreateTypeData for ReflectMyTrait { + fn create_type_data(_: (i32, i32)) -> Self { + todo!() + } +} + +#[derive(Reflect)] +#[reflect(MyTrait)] +struct NoArgs; + +#[derive(Reflect)] +#[reflect(MyTrait(1 + 2))] +struct OneArg; + +#[derive(Reflect)] +#[reflect(MyTrait(1 + 2, 3 + 4))] +struct TwoArgs; diff --git a/crates/bevy_reflect/derive/src/container_attributes.rs b/crates/bevy_reflect/derive/src/container_attributes.rs index f15d2d56e6b90..9d80f50da26b2 100644 --- a/crates/bevy_reflect/derive/src/container_attributes.rs +++ b/crates/bevy_reflect/derive/src/container_attributes.rs @@ -5,6 +5,7 @@ //! the derive helper attribute for `Reflect`, which looks like: //! `#[reflect(PartialEq, Default, ...)]`. +use crate::type_data::TypeDataRegistration; use crate::{custom_attributes::CustomAttributes, derive_data::ReflectTraitToImpl}; use bevy_macro_utils::{ fq_std::{FQAny, FQClone, FQOption, FQResult}, @@ -30,13 +31,6 @@ mod kw { syn::custom_keyword!(opaque); } -// The "special" trait idents that are used internally for reflection. -// Received via attributes like `#[reflect(PartialEq, Hash, ...)]` -const DEBUG_ATTR: &str = "Debug"; -const PARTIAL_EQ_ATTR: &str = "PartialEq"; -const PARTIAL_ORD_ATTR: &str = "PartialOrd"; -const HASH_ATTR: &str = "Hash"; - // The traits listed below are not considered "special" (i.e. they use the `ReflectMyTrait` syntax) // but useful to know exist nonetheless pub(crate) const REFLECT_DEFAULT: &str = "ReflectDefault"; @@ -191,7 +185,7 @@ pub(crate) struct ContainerAttributes { no_auto_register: bool, custom_attributes: CustomAttributes, is_opaque: bool, - idents: Vec, + type_data: Vec, } impl ContainerAttributes { @@ -256,33 +250,32 @@ impl ContainerAttributes { } else if lookahead.peek(kw::PartialEq) { self.parse_partial_eq(input) } else if lookahead.peek(Ident::peek_any) { - self.parse_ident(input) + self.parse_type_data(input) } else { Err(lookahead.error()) } } - /// Parse an ident (for registration). + /// Parse a type data registration. /// /// Examples: - /// - `#[reflect(MyTrait)]` (registers `ReflectMyTrait`) - fn parse_ident(&mut self, input: ParseStream) -> syn::Result<()> { - let ident = input.parse::()?; - - if input.peek(token::Paren) { - return Err(syn::Error::new(ident.span(), format!( - "only [{DEBUG_ATTR:?}, {PARTIAL_EQ_ATTR:?}, {PARTIAL_ORD_ATTR:?}, {HASH_ATTR:?}] may specify custom functions", - ))); + /// - `#[reflect(Default)]` + /// - `#[reflect(Hash(custom_hash_fn))]` + fn parse_type_data(&mut self, input: ParseStream) -> syn::Result<()> { + let type_data = input.parse::()?; + + if self + .type_data + .iter() + .any(|existing| existing.ident() == type_data.ident()) + { + return Err(syn::Error::new( + type_data.ident().span(), + CONFLICTING_TYPE_DATA_MESSAGE, + )); } - let ident_name = ident.to_string(); - - // Create the reflect ident - let mut reflect_ident = crate::ident::get_reflect_ident(&ident_name); - // We set the span to the old ident so any compile errors point to that ident instead - reflect_ident.set_span(ident.span()); - - add_unique_ident(&mut self.idents, reflect_ident)?; + self.type_data.push(type_data); Ok(()) } @@ -500,12 +493,14 @@ impl ContainerAttributes { /// Returns true if the given reflected trait name (i.e. `ReflectDefault` for `Default`) /// is registered for this type. pub fn contains(&self, name: &str) -> bool { - self.idents.iter().any(|ident| ident == name) + self.type_data + .iter() + .any(|data| data.reflect_ident() == name) } - /// The list of reflected traits by their reflected ident (i.e. `ReflectDefault` for `Default`). - pub fn idents(&self) -> &[Ident] { - &self.idents + /// The list of type data registrations. + pub fn type_data(&self) -> &[TypeDataRegistration] { + &self.type_data } /// The `FromReflect` configuration found within `#[reflect(...)]` attributes on this type. @@ -662,19 +657,6 @@ impl ContainerAttributes { } } -/// Adds an identifier to a vector of identifiers if it is not already present. -/// -/// Returns an error if the identifier already exists in the list. -fn add_unique_ident(idents: &mut Vec, ident: Ident) -> Result<(), syn::Error> { - let ident_name = ident.to_string(); - if idents.iter().any(|i| i == ident_name.as_str()) { - return Err(syn::Error::new(ident.span(), CONFLICTING_TYPE_DATA_MESSAGE)); - } - - idents.push(ident); - Ok(()) -} - /// Extract a boolean value from an expression. /// /// The mapper exists so that the caller can conditionally choose to use the given diff --git a/crates/bevy_reflect/derive/src/ident.rs b/crates/bevy_reflect/derive/src/ident.rs index 931b3e989a8c6..8f7385e8b472c 100644 --- a/crates/bevy_reflect/derive/src/ident.rs +++ b/crates/bevy_reflect/derive/src/ident.rs @@ -1,20 +1,20 @@ -use proc_macro2::{Ident, Span}; +use proc_macro2::Ident; /// Returns the "reflected" ident for a given string. /// /// # Example /// /// ``` -/// # use proc_macro2::Ident; +/// # use proc_macro2::{Ident, Span}; /// # // We can't import this method because of its visibility. -/// # fn get_reflect_ident(name: &str) -> Ident { -/// # let reflected = format!("Reflect{name}"); -/// # Ident::new(&reflected, proc_macro2::Span::call_site()) +/// # fn get_reflect_ident(base_ident: &Ident) -> Ident { +/// # let reflected = format!("Reflect{base_ident}"); +/// # Ident::new(&reflected, base_ident.span()) /// # } -/// let reflected: Ident = get_reflect_ident("Hash"); +/// let reflected: Ident = get_reflect_ident(&Ident::new("Hash", Span::call_site())); /// assert_eq!("ReflectHash", reflected.to_string()); /// ``` -pub(crate) fn get_reflect_ident(name: &str) -> Ident { - let reflected = format!("Reflect{name}"); - Ident::new(&reflected, Span::call_site()) +pub(crate) fn get_reflect_ident(base_ident: &Ident) -> Ident { + let reflected = format!("Reflect{base_ident}"); + Ident::new(&reflected, base_ident.span()) } diff --git a/crates/bevy_reflect/derive/src/lib.rs b/crates/bevy_reflect/derive/src/lib.rs index a19f8834ee15f..b2e07a3bc9bc2 100644 --- a/crates/bevy_reflect/derive/src/lib.rs +++ b/crates/bevy_reflect/derive/src/lib.rs @@ -35,6 +35,7 @@ mod serialization; mod string_expr; mod struct_utility; mod trait_reflection; +mod type_data; mod type_path; mod where_clause_options; @@ -145,6 +146,18 @@ fn match_reflect_impls(ast: DeriveInput, source: ReflectImplSource) -> TokenStre /// This is often used with traits that have been marked by the [`#[reflect_trait]`](macro@reflect_trait) /// macro in order to register the type's implementation of that trait. /// +/// ### Type Data Input +/// +/// If the type data's implementation allows for input, +/// that input can be specified using a function-call-like syntax. +/// For example, `#[reflect(Foo(42))]` would pass the value `42` +/// as the input to the `ReflectFoo` type data. +/// +/// Some type data accept a tuple of values. +/// The macro will automatically convert the input to a tuple if given >=2 parameters. +/// For example, `#[reflect(Foo(42, "hello"))]` would pass the tuple `(42, "hello")` +/// as the input to the `ReflectFoo` type data. +/// /// ### Default Registrations /// /// The following types are automatically registered when deriving `Reflect`: @@ -506,7 +519,7 @@ pub fn derive_type_path(input: TokenStream) -> TokenStream { /// Because of this, **it can only be used on [object-safe] traits.** /// /// For a trait named `MyTrait`, this will generate the struct `ReflectMyTrait`. -/// The generated struct can be created using `FromType` with any type that implements the trait. +/// The generated struct can be created using `CreateTypeData` with any type that implements the trait. /// The creation and registration of this generated struct as type data can be automatically handled /// by [`#[derive(Reflect)]`](Reflect). /// @@ -531,7 +544,7 @@ pub fn derive_type_path(input: TokenStream) -> TokenStream { /// } /// /// // We can create the type data manually if we wanted: -/// let my_trait: ReflectMyTrait = FromType::::from_type(); +/// let my_trait: ReflectMyTrait = CreateTypeData::::create_type_data(()); /// /// // Or we can simply get it from the registry: /// let mut registry = TypeRegistry::default(); diff --git a/crates/bevy_reflect/derive/src/registration.rs b/crates/bevy_reflect/derive/src/registration.rs index d3ec6e0ad68a7..8ff6471f4e015 100644 --- a/crates/bevy_reflect/derive/src/registration.rs +++ b/crates/bevy_reflect/derive/src/registration.rs @@ -1,7 +1,7 @@ //! Contains code related specifically to Bevy's type registration. use crate::{serialization::SerializationDataDef, where_clause_options::WhereClauseOptions}; -use quote::quote; +use quote::{quote, quote_spanned}; use syn::Type; /// Creates the `GetTypeRegistration` impl for the given type data. @@ -13,7 +13,6 @@ pub(crate) fn impl_get_type_registration<'a>( let meta = where_clause_options.meta(); let type_path = meta.type_path(); let bevy_reflect_path = meta.bevy_reflect_path(); - let registration_data = meta.attrs().idents(); let type_deps_fn = type_dependencies.map(|deps| { quote! { @@ -29,7 +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::<#bevy_reflect_path::ReflectFromReflect>(#bevy_reflect_path::FromType::::from_type()); + registration.insert( + <#bevy_reflect_path::ReflectFromReflect as #bevy_reflect_path::CreateTypeData>::create_type_data(()) + ); }) } else { None @@ -42,14 +43,33 @@ pub(crate) fn impl_get_type_registration<'a>( } }); + let type_data = meta.attrs().type_data().iter().map(|data| { + let reflect_ident = data.reflect_ident(); + let args = data.args(); + + let args = if args.is_empty() { + // Set the span so that we get pointed to the correct identifier even when there are no type data arguments + let span = reflect_ident.span(); + quote_spanned!(span => ()) + } else { + quote!((#args)) + }; + + quote! { + registration.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::(); - registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::::from_type()); + registration.insert( + <#bevy_reflect_path::ReflectFromPtr as #bevy_reflect_path::CreateTypeData::>::create_type_data(()) + ); #from_reflect_data #serialization_data - #(registration.register_type_data::<#registration_data, Self>();)* + #(#type_data)* registration } diff --git a/crates/bevy_reflect/derive/src/trait_reflection.rs b/crates/bevy_reflect/derive/src/trait_reflection.rs index 8df40e47a5fd0..ce7f26a9b87f2 100644 --- a/crates/bevy_reflect/derive/src/trait_reflection.rs +++ b/crates/bevy_reflect/derive/src/trait_reflection.rs @@ -30,7 +30,7 @@ pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStr let item_trait = &trait_info.item_trait; let trait_ident = &item_trait.ident; let trait_vis = &item_trait.vis; - let reflect_trait_ident = crate::ident::get_reflect_ident(&item_trait.ident.to_string()); + let reflect_trait_ident = crate::ident::get_reflect_ident(&item_trait.ident); let bevy_reflect_path = crate::meta::get_bevy_reflect_path(); let struct_doc = format!( @@ -74,8 +74,8 @@ pub(crate) fn reflect_trait(_args: &TokenStream, input: TokenStream) -> TokenStr } } - impl #bevy_reflect_path::FromType for #reflect_trait_ident { - fn from_type() -> Self { + impl #bevy_reflect_path::CreateTypeData for #reflect_trait_ident { + fn create_type_data(_input: ()) -> Self { Self { get_func: |reflect_value| { ::downcast_ref::(reflect_value).map(|value| value as &dyn #trait_ident) diff --git a/crates/bevy_reflect/derive/src/type_data.rs b/crates/bevy_reflect/derive/src/type_data.rs new file mode 100644 index 0000000000000..0ca145f865477 --- /dev/null +++ b/crates/bevy_reflect/derive/src/type_data.rs @@ -0,0 +1,57 @@ +use proc_macro2::Ident; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::{parenthesized, token, Expr, Token}; + +/// A `TypeData` registration. +/// +/// This would be the `Default` and `Hash(custom_hash_fn)` in +/// `#[reflect(Default, Hash(custom_hash_fn))]`. +#[derive(Clone)] +pub(crate) struct TypeDataRegistration { + ident: Ident, + reflect_ident: Ident, + args: Punctuated, +} + +impl TypeDataRegistration { + /// The shortened ident of the registration. + /// + /// This would be `Default` in `#[reflect(Default)]`. + pub fn ident(&self) -> &Ident { + &self.ident + } + + /// The full reflection ident of the registration. + /// + /// This would be `ReflectDefault` in `#[reflect(Default)]`. + pub fn reflect_ident(&self) -> &Ident { + &self.reflect_ident + } + + /// The optional arguments of the type data. + pub fn args(&self) -> &Punctuated { + &self.args + } +} + +impl Parse for TypeDataRegistration { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse::()?; + let reflect_ident = crate::ident::get_reflect_ident(&ident); + + let args = if input.peek(token::Paren) { + let content; + parenthesized!(content in input); + content.parse_terminated(Expr::parse, Token![,])? + } else { + Default::default() + }; + + Ok(Self { + ident, + reflect_ident, + args, + }) + } +} diff --git a/crates/bevy_reflect/src/convert.rs b/crates/bevy_reflect/src/convert.rs index 5fd9bcfdaa1ca..4bc03ec616390 100644 --- a/crates/bevy_reflect/src/convert.rs +++ b/crates/bevy_reflect/src/convert.rs @@ -10,7 +10,7 @@ use crate::{Reflect, TypePath}; /// Provides a mechanism for converting values of one type to another. /// -/// This [`crate::type_registry::TypeData`] is associated with the type to be +/// This [`crate::type_data::TypeData`] is associated with the type to be /// converted *into*, not the type to be converted *from*. To convert a value, /// use code like the following: /// diff --git a/crates/bevy_reflect/src/from_reflect.rs b/crates/bevy_reflect/src/from_reflect.rs index d1c55a26305a6..534a07a3565c9 100644 --- a/crates/bevy_reflect/src/from_reflect.rs +++ b/crates/bevy_reflect/src/from_reflect.rs @@ -1,4 +1,4 @@ -use crate::{FromType, PartialReflect, Reflect}; +use crate::{CreateTypeData, PartialReflect, Reflect}; use alloc::boxed::Box; /// A trait that enables types to be dynamically constructed from reflected data. @@ -117,8 +117,8 @@ impl ReflectFromReflect { } } -impl FromType for ReflectFromReflect { - fn from_type() -> Self { +impl CreateTypeData for ReflectFromReflect { + fn create_type_data(_input: ()) -> Self { Self { from_reflect: |reflect_value| { T::from_reflect(reflect_value).map(|value| Box::new(value) as Box) diff --git a/crates/bevy_reflect/src/impls/alloc/borrow.rs b/crates/bevy_reflect/src/impls/alloc/borrow.rs index 625e65f0a450f..0d77bc71c73bb 100644 --- a/crates/bevy_reflect/src/impls/alloc/borrow.rs +++ b/crates/bevy_reflect/src/impls/alloc/borrow.rs @@ -6,7 +6,7 @@ use crate::{ reflect::{impl_full_reflect, ApplyError}, type_info::{MaybeTyped, OpaqueInfo, TypeInfo, Typed}, type_registry::{ - FromType, GetTypeRegistration, ReflectDeserialize, ReflectFromPtr, ReflectSerialize, + GetTypeRegistration, ReflectDeserialize, ReflectFromPtr, ReflectSerialize, TypeRegistration, TypeRegistry, }, utility::{reflect_hasher, GenericTypeInfoCell, NonGenericTypeInfoCell}, @@ -124,10 +124,10 @@ impl Typed for Cow<'static, str> { impl GetTypeRegistration for Cow<'static, str> { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::>(); - registration.insert::(FromType::>::from_type()); - registration.insert::(FromType::>::from_type()); - registration.insert::(FromType::>::from_type()); - registration.insert::(FromType::>::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); + registration.register_type_data::(); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/impls/alloc/collections/btree/map.rs b/crates/bevy_reflect/src/impls/alloc/collections/btree/map.rs index 1d62e7479fd1b..241befc9705c2 100644 --- a/crates/bevy_reflect/src/impls/alloc/collections/btree/map.rs +++ b/crates/bevy_reflect/src/impls/alloc/collections/btree/map.rs @@ -6,7 +6,7 @@ use crate::{ prelude::*, reflect::{impl_full_reflect, ApplyError}, type_info::{MaybeTyped, TypeInfo, Typed}, - type_registry::{FromType, GetTypeRegistration, ReflectFromPtr, TypeRegistration}, + type_registry::{GetTypeRegistration, ReflectFromPtr, TypeRegistration}, utility::GenericTypeInfoCell, }; use alloc::vec::Vec; @@ -200,8 +200,8 @@ where { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/impls/core/panic.rs b/crates/bevy_reflect/src/impls/core/panic.rs index 1dd07d758cc68..8ba67c8c4e98f 100644 --- a/crates/bevy_reflect/src/impls/core/panic.rs +++ b/crates/bevy_reflect/src/impls/core/panic.rs @@ -5,7 +5,7 @@ use crate::{ reflect::ApplyError, type_info::{OpaqueInfo, TypeInfo, Typed}, type_path::DynamicTypePath, - type_registry::{FromType, GetTypeRegistration, ReflectFromPtr, TypeRegistration}, + type_registry::{GetTypeRegistration, ReflectFromPtr, TypeRegistration}, utility::{reflect_hasher, NonGenericTypeInfoCell}, }; use bevy_platform::prelude::*; @@ -150,8 +150,8 @@ impl Typed for &'static Location<'static> { impl GetTypeRegistration for &'static Location<'static> { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/impls/core/primitives.rs b/crates/bevy_reflect/src/impls/core/primitives.rs index b63bf40926004..6dfe41214a390 100644 --- a/crates/bevy_reflect/src/impls/core/primitives.rs +++ b/crates/bevy_reflect/src/impls/core/primitives.rs @@ -6,7 +6,7 @@ use crate::{ reflect::ApplyError, type_info::{MaybeTyped, OpaqueInfo, TypeInfo, Typed}, type_registry::{ - FromType, GetTypeRegistration, ReflectDeserialize, ReflectFromPtr, ReflectSerialize, + GetTypeRegistration, ReflectDeserialize, ReflectFromPtr, ReflectSerialize, TypeRegistration, TypeRegistry, }, utility::{reflect_hasher, GenericTypeInfoCell, GenericTypePathCell, NonGenericTypeInfoCell}, @@ -444,9 +444,9 @@ impl Typed for &'static str { impl GetTypeRegistration for &'static str { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/impls/core/sync.rs b/crates/bevy_reflect/src/impls/core/sync.rs index 5cd46e7dc431d..a1d0b07b03410 100644 --- a/crates/bevy_reflect/src/impls/core/sync.rs +++ b/crates/bevy_reflect/src/impls/core/sync.rs @@ -5,7 +5,7 @@ use crate::{ reflect::{impl_full_reflect, ApplyError}, type_info::{OpaqueInfo, TypeInfo, Typed}, type_path::DynamicTypePath, - type_registry::{FromType, GetTypeRegistration, ReflectFromPtr, TypeRegistration}, + type_registry::{GetTypeRegistration, ReflectFromPtr, TypeRegistration}, utility::NonGenericTypeInfoCell, }; use bevy_platform::prelude::*; @@ -23,15 +23,15 @@ macro_rules! impl_reflect_for_atomic { impl GetTypeRegistration for $ty { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); + registration.register_type_data::(); // Serde only supports atomic types when the "std" feature is enabled #[cfg(feature = "std")] { - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); } registration diff --git a/crates/bevy_reflect/src/impls/indexmap.rs b/crates/bevy_reflect/src/impls/indexmap.rs index d7e4ea21d5638..fa406f0642ff8 100644 --- a/crates/bevy_reflect/src/impls/indexmap.rs +++ b/crates/bevy_reflect/src/impls/indexmap.rs @@ -1,9 +1,9 @@ use crate::{ set::{Set, SetInfo}, utility::GenericTypeInfoCell, - FromReflect, FromType, Generics, GetTypeRegistration, PartialReflect, Reflect, - ReflectCloneError, ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, - TypeParamInfo, TypePath, TypeRegistration, + FromReflect, Generics, GetTypeRegistration, PartialReflect, Reflect, ReflectCloneError, + ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeParamInfo, TypePath, + TypeRegistration, }; use bevy_platform::prelude::{Box, Vec}; use bevy_reflect::{ @@ -266,8 +266,8 @@ where { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); registration } @@ -491,7 +491,7 @@ where { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/impls/macros/list.rs b/crates/bevy_reflect/src/impls/macros/list.rs index 41c9c752454f9..a628baf647c45 100644 --- a/crates/bevy_reflect/src/impls/macros/list.rs +++ b/crates/bevy_reflect/src/impls/macros/list.rs @@ -159,8 +159,8 @@ macro_rules! impl_reflect_for_veclike { { fn get_type_registration() -> $crate::type_registry::TypeRegistration { let mut registration = $crate::type_registry::TypeRegistration::of::<$ty>(); - registration.insert::<$crate::type_registry::ReflectFromPtr>($crate::type_registry::FromType::<$ty>::from_type()); - registration.insert::<$crate::from_reflect::ReflectFromReflect>($crate::type_registry::FromType::<$ty>::from_type()); + registration.register_type_data::<$crate::type_registry::ReflectFromPtr, $ty>(); + registration.register_type_data::<$crate::from_reflect::ReflectFromReflect, $ty>(); registration } diff --git a/crates/bevy_reflect/src/impls/macros/map.rs b/crates/bevy_reflect/src/impls/macros/map.rs index 5ac779f3a747d..baa7b5f499c3f 100644 --- a/crates/bevy_reflect/src/impls/macros/map.rs +++ b/crates/bevy_reflect/src/impls/macros/map.rs @@ -202,8 +202,8 @@ macro_rules! impl_reflect_for_hashmap { { fn get_type_registration() -> $crate::type_registry::TypeRegistration { let mut registration = $crate::type_registry::TypeRegistration::of::(); - registration.insert::<$crate::type_registry::ReflectFromPtr>($crate::type_registry::FromType::::from_type()); - registration.insert::<$crate::from_reflect::ReflectFromReflect>($crate::type_registry::FromType::::from_type()); + registration.register_type_data::<$crate::type_registry::ReflectFromPtr, Self>(); + registration.register_type_data::<$crate::from_reflect::ReflectFromReflect, Self>(); registration } diff --git a/crates/bevy_reflect/src/impls/macros/set.rs b/crates/bevy_reflect/src/impls/macros/set.rs index 69506a88e4549..0859998810d67 100644 --- a/crates/bevy_reflect/src/impls/macros/set.rs +++ b/crates/bevy_reflect/src/impls/macros/set.rs @@ -165,8 +165,8 @@ macro_rules! impl_reflect_for_hashset { { fn get_type_registration() -> $crate::type_registry::TypeRegistration { let mut registration = $crate::type_registry::TypeRegistration::of::(); - registration.insert::<$crate::type_registry::ReflectFromPtr>($crate::type_registry::FromType::::from_type()); - registration.insert::<$crate::from_reflect::ReflectFromReflect>($crate::type_registry::FromType::::from_type()); + registration.register_type_data::<$crate::type_registry::ReflectFromPtr, Self>(); + registration.register_type_data::<$crate::from_reflect::ReflectFromReflect, Self>(); registration } diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 799992dbf374a..da430a381b3ea 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,9 +1,9 @@ use crate::{ list::{List, ListInfo, ListIter}, utility::GenericTypeInfoCell, - ApplyError, FromReflect, FromType, Generics, GetTypeRegistration, MaybeTyped, PartialReflect, - Reflect, ReflectFromPtr, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, - TypeParamInfo, TypePath, TypeRegistration, Typed, + ApplyError, FromReflect, Generics, GetTypeRegistration, MaybeTyped, PartialReflect, Reflect, + ReflectFromPtr, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeParamInfo, + TypePath, TypeRegistration, Typed, }; use alloc::{boxed::Box, vec::Vec}; use bevy_reflect::ReflectCloneError; @@ -230,7 +230,7 @@ where { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::>(); - registration.insert::(FromType::>::from_type()); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/impls/std/path.rs b/crates/bevy_reflect/src/impls/std/path.rs index ea113951d8818..fa376a084af7f 100644 --- a/crates/bevy_reflect/src/impls/std/path.rs +++ b/crates/bevy_reflect/src/impls/std/path.rs @@ -6,8 +6,7 @@ use crate::{ type_info::{OpaqueInfo, TypeInfo, Typed}, type_path::DynamicTypePath, type_registry::{ - FromType, GetTypeRegistration, ReflectDeserialize, ReflectFromPtr, ReflectSerialize, - TypeRegistration, + GetTypeRegistration, ReflectDeserialize, ReflectFromPtr, ReflectSerialize, TypeRegistration, }, utility::{reflect_hasher, NonGenericTypeInfoCell}, }; @@ -157,8 +156,8 @@ impl Typed for &'static Path { impl GetTypeRegistration for &'static Path { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); registration } } @@ -308,10 +307,10 @@ impl FromReflect for Cow<'static, Path> { impl GetTypeRegistration for Cow<'static, Path> { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); - registration.insert::(FromType::::from_type()); + registration.register_type_data::(); + registration.register_type_data::(); + registration.register_type_data::(); + registration.register_type_data::(); registration } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index dc0d0843caf1c..70c7781fbffb1 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -613,6 +613,7 @@ pub mod set; pub mod structs; pub mod tuple; pub mod tuple_struct; +mod type_data; mod type_info; mod type_path; mod type_registry; @@ -683,6 +684,7 @@ pub use path::*; pub use reflect::*; pub use reflectable::*; pub use remote::*; +pub use type_data::*; pub use type_info::*; pub use type_path::*; pub use type_registry::*; @@ -4118,8 +4120,8 @@ bevy_reflect::tests::Test { #[derive(Clone)] struct ReflectA; - impl FromType for ReflectA { - fn from_type() -> Self { + impl CreateTypeData for ReflectA { + fn create_type_data(_input: ()) -> Self { ReflectA } diff --git a/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs b/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs index 8a216f87b9031..b6643bf3592f2 100644 --- a/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs +++ b/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs @@ -1,5 +1,5 @@ use crate::serde::de::error_utils::make_custom_error; -use crate::{FromType, PartialReflect, TypeRegistry}; +use crate::{CreateTypeData, PartialReflect, TypeRegistry}; use alloc::boxed::Box; use serde::Deserializer; @@ -74,10 +74,10 @@ impl ReflectDeserializeWithRegistry { } } -impl DeserializeWithRegistry<'de>> FromType +impl DeserializeWithRegistry<'de>> CreateTypeData for ReflectDeserializeWithRegistry { - fn from_type() -> Self { + fn create_type_data(_input: ()) -> Self { Self { deserialize: |deserializer, registry| { Ok(Box::new(T::deserialize(deserializer, registry)?)) diff --git a/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs b/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs index f9e6370799f31..6d05ea5ab4e7f 100644 --- a/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs +++ b/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs @@ -1,4 +1,4 @@ -use crate::{FromType, Reflect, TypeRegistry}; +use crate::{CreateTypeData, Reflect, TypeRegistry}; use alloc::boxed::Box; use serde::{Serialize, Serializer}; @@ -72,8 +72,8 @@ impl ReflectSerializeWithRegistry { } } -impl FromType for ReflectSerializeWithRegistry { - fn from_type() -> Self { +impl CreateTypeData for ReflectSerializeWithRegistry { + fn create_type_data(_input: ()) -> Self { Self { serialize: |value: &dyn Reflect, registry| { let value = value.downcast_ref::().unwrap_or_else(|| { diff --git a/crates/bevy_reflect/src/std_traits.rs b/crates/bevy_reflect/src/std_traits.rs index 9d3b6ee567ae4..f151b6a5a1a7a 100644 --- a/crates/bevy_reflect/src/std_traits.rs +++ b/crates/bevy_reflect/src/std_traits.rs @@ -3,11 +3,11 @@ use alloc::boxed::Box; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign}; -use crate::{FromType, PartialReflect, Reflect}; +use crate::{CreateTypeData, PartialReflect, Reflect}; /// A struct used to provide the default value of a type. /// -/// A [`ReflectDefault`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectDefault`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box, @@ -20,8 +20,8 @@ impl ReflectDefault { } } -impl FromType for ReflectDefault { - fn from_type() -> Self { +impl CreateTypeData for ReflectDefault { + fn create_type_data(_input: ()) -> Self { ReflectDefault { default: || Box::::default(), } @@ -30,7 +30,7 @@ impl FromType for ReflectDefault { /// A struct used to perform addition on reflected values. /// -/// A [`ReflectAdd`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectAdd`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectAdd { /// Function pointer implementing [`ReflectAdd::add()`]. @@ -56,8 +56,8 @@ impl ReflectAdd { } } -impl> FromType for ReflectAdd { - fn from_type() -> Self { +impl> CreateTypeData for ReflectAdd { + fn create_type_data(_input: ()) -> Self { ReflectAdd { add: |a: Box, b: Box| { let (a, b) = match (a.try_downcast::(), b.try_downcast::()) { @@ -80,7 +80,7 @@ impl> FromType for ReflectAdd { /// A struct used to perform subtraction on reflected values. /// -/// A [`ReflectSub`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectSub`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectSub { /// Function pointer implementing [`ReflectSub::sub()`]. @@ -106,8 +106,8 @@ impl ReflectSub { } } -impl> FromType for ReflectSub { - fn from_type() -> Self { +impl> CreateTypeData for ReflectSub { + fn create_type_data(_input: ()) -> Self { ReflectSub { sub: |a: Box, b: Box| { let (a, b) = match (a.try_downcast::(), b.try_downcast::()) { @@ -130,7 +130,7 @@ impl> FromType for ReflectSub { /// A struct used to perform multiplication on reflected values. /// -/// A [`ReflectMul`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectMul`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectMul { /// Function pointer implementing [`ReflectMul::mul()`]. @@ -156,8 +156,8 @@ impl ReflectMul { } } -impl> FromType for ReflectMul { - fn from_type() -> Self { +impl> CreateTypeData for ReflectMul { + fn create_type_data(_input: ()) -> Self { ReflectMul { mul: |a: Box, b: Box| { let (a, b) = match (a.try_downcast::(), b.try_downcast::()) { @@ -180,7 +180,7 @@ impl> FromType for ReflectMul { /// A struct used to perform division on reflected values. /// -/// A [`ReflectDiv`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectDiv`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectDiv { /// Function pointer implementing [`ReflectDiv::div()`]. @@ -206,8 +206,8 @@ impl ReflectDiv { } } -impl> FromType for ReflectDiv { - fn from_type() -> Self { +impl> CreateTypeData for ReflectDiv { + fn create_type_data(_input: ()) -> Self { ReflectDiv { div: |a: Box, b: Box| { let (a, b) = match (a.try_downcast::(), b.try_downcast::()) { @@ -230,7 +230,7 @@ impl> FromType for ReflectDiv { /// A struct used to perform remainder on reflected values. /// -/// A [`ReflectRem`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectRem`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectRem { /// Function pointer implementing [`ReflectRem::rem()`]. @@ -257,8 +257,8 @@ impl ReflectRem { } } -impl> FromType for ReflectRem { - fn from_type() -> Self { +impl> CreateTypeData for ReflectRem { + fn create_type_data(_input: ()) -> Self { ReflectRem { rem: |a: Box, b: Box| { let (a, b) = match (a.try_downcast::(), b.try_downcast::()) { @@ -281,7 +281,7 @@ impl> FromType for ReflectRem { /// A struct used to perform addition assignment on reflected values. /// -/// A [`ReflectAddAssign`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectAddAssign`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectAddAssign { /// Function pointer implementing [`ReflectAddAssign::add_assign()`]. @@ -307,8 +307,8 @@ impl ReflectAddAssign { } } -impl FromType for ReflectAddAssign { - fn from_type() -> Self { +impl CreateTypeData for ReflectAddAssign { + fn create_type_data(_input: ()) -> Self { ReflectAddAssign { add_assign: |a: &mut dyn Reflect, b: Box| { let Some(a) = a.downcast_mut::() else { @@ -327,7 +327,7 @@ impl FromType for ReflectAddAssign { /// A struct used to perform subtraction assignment on reflected values. /// -/// A [`ReflectSubAssign`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectSubAssign`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectSubAssign { /// Function pointer implementing [`ReflectSubAssign::sub_assign()`]. @@ -353,8 +353,8 @@ impl ReflectSubAssign { } } -impl FromType for ReflectSubAssign { - fn from_type() -> Self { +impl CreateTypeData for ReflectSubAssign { + fn create_type_data(_input: ()) -> Self { ReflectSubAssign { sub_assign: |a: &mut dyn Reflect, b: Box| { let Some(a) = a.downcast_mut::() else { @@ -373,7 +373,7 @@ impl FromType for ReflectSubAssign { /// A struct used to perform multiplication assignment on reflected values. /// -/// A [`ReflectMulAssign`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectMulAssign`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectMulAssign { /// Function pointer implementing [`ReflectMulAssign::mul_assign()`]. @@ -399,8 +399,8 @@ impl ReflectMulAssign { } } -impl FromType for ReflectMulAssign { - fn from_type() -> Self { +impl CreateTypeData for ReflectMulAssign { + fn create_type_data(_input: ()) -> Self { ReflectMulAssign { mul_assign: |a: &mut dyn Reflect, b: Box| { let Some(a) = a.downcast_mut::() else { @@ -419,7 +419,7 @@ impl FromType for ReflectMulAssign { /// A struct used to perform division assignment on reflected values. /// -/// A [`ReflectDivAssign`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectDivAssign`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectDivAssign { /// Function pointer implementing [`ReflectDivAssign::div_assign()`]. @@ -445,8 +445,8 @@ impl ReflectDivAssign { } } -impl FromType for ReflectDivAssign { - fn from_type() -> Self { +impl CreateTypeData for ReflectDivAssign { + fn create_type_data(_input: ()) -> Self { ReflectDivAssign { div_assign: |a: &mut dyn Reflect, b: Box| { let Some(a) = a.downcast_mut::() else { @@ -465,7 +465,7 @@ impl FromType for ReflectDivAssign { /// A struct used to perform remainder assignment on reflected values. /// -/// A [`ReflectRemAssign`] for type `T` can be obtained via [`FromType::from_type`]. +/// A [`ReflectRemAssign`] for type `T` can be obtained via [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectRemAssign { /// Function pointer implementing [`ReflectRemAssign::rem_assign()`]. @@ -491,8 +491,8 @@ impl ReflectRemAssign { } } -impl FromType for ReflectRemAssign { - fn from_type() -> Self { +impl CreateTypeData for ReflectRemAssign { + fn create_type_data(_input: ()) -> Self { ReflectRemAssign { rem_assign: |a: &mut dyn Reflect, b: Box| { let Some(a) = a.downcast_mut::() else { diff --git a/crates/bevy_reflect/src/type_data.rs b/crates/bevy_reflect/src/type_data.rs new file mode 100644 index 0000000000000..7f9d03ba3ed9c --- /dev/null +++ b/crates/bevy_reflect/src/type_data.rs @@ -0,0 +1,144 @@ +use ::alloc::boxed::Box; +use bevy_reflect::TypeRegistration; +use downcast_rs::{impl_downcast, Downcast}; + +/// A trait for representing type metadata. +/// +/// Type data can be registered to the [`TypeRegistry`] and stored on a type's [`TypeRegistration`]. +/// +/// While type data is often generated using the [`#[reflect_trait]`](crate::reflect_trait) macro, +/// almost any type that implements [`Clone`] can be considered "type data". +/// This is because it has a blanket implementation over all `T` where `T: Clone + Send + Sync + 'static`. +/// +/// For creating your own type data, see the [`CreateTypeData`] trait. +/// +/// See the [crate-level documentation] for more information on type data and type registration. +/// +/// [`TypeRegistry`]: crate::TypeRegistry +/// [`TypeRegistration`]: crate::TypeRegistration +/// [crate-level documentation]: crate +pub trait TypeData: Downcast + Send + Sync { + /// Creates a type-erased clone of `self`. + fn clone_type_data(&self) -> Box; +} +impl_downcast!(TypeData); + +impl TypeData for T +where + T: Clone, +{ + fn clone_type_data(&self) -> Box { + Box::new(self.clone()) + } +} + +/// A trait for creating [`TypeData`]. +/// +/// Normally any type that is `Clone + Send + Sync + 'static` can be used as type data +/// and inserted into a [`TypeRegistration`] using [`TypeRegistration::insert`] +/// However, only types that implement this trait may be registered using [`TypeRegistry::register_type_data`], +/// [`TypeRegistry::register_type_data_with`], or via the `#[reflect(MyTrait)]` attribute with the [`Reflect` derive macro]. +/// +/// Note that in order to work with the `#[reflect(MyTrait)]` attribute, +/// implementors must be named with the `Reflect` prefix (e.g. `ReflectMyTrait`). +/// +/// # Input +/// +/// By default, this trait expects no input for creating the type data +/// (the `Input` type parameter defaults to `()`). +/// +/// However, implementors may choose to implement this trait with other input types. +/// As long as the implementations don't conflict, multiple different input types can be specified. +/// +/// # Example +/// +/// ``` +/// # use bevy_reflect::{CreateTypeData, Reflect}; +/// trait Combine { +/// fn combine(a: f32, b: f32) -> f32; +/// } +/// +/// #[derive(Clone)] +/// struct ReflectCombine { +/// multiplier: f32, +/// additional: f32, +/// combine: fn(f32, f32) -> f32, +/// } +/// +/// impl ReflectCombine { +/// pub fn combine(&self, a: f32, b: f32) -> f32 { +/// let combined = (self.combine)(a, b); +/// let multiplied = self.multiplier * combined; +/// multiplied + self.additional +/// } +/// } +/// +/// // A default implementation for when no input is given +/// impl CreateTypeData for ReflectCombine { +/// fn create_type_data(_: ()) -> Self { +/// Self { +/// multiplier: 1.0, +/// additional: 0.0, +/// combine: T::combine, +/// } +/// } +/// } +/// +/// // A custom implementation for when a multiplier is given +/// impl CreateTypeData for ReflectCombine { +/// fn create_type_data(input: (f32, f32)) -> Self { +/// Self { +/// multiplier: input.0, +/// additional: input.1, +/// combine: T::combine, +/// } +/// } +/// } +/// +/// #[derive(Reflect)] +/// // We can have the `Reflect` derive automatically register `ReflectCombine`: +/// #[reflect(Combine)] +/// struct WithoutMultiplier; +/// +/// impl Combine for WithoutMultiplier { +/// fn combine(a: f32, b: f32) -> f32 { +/// a + b +/// } +/// } +/// +/// #[derive(Reflect)] +/// // We can also given it some input: +/// #[reflect(Combine(2.0, 4.0))] +/// struct WithMultiplier; +/// +/// impl Combine for WithMultiplier { +/// fn combine(a: f32, b: f32) -> f32 { +/// a + b +/// } +/// } +/// +/// // Or we can simply create the data manually: +/// let without_multiplier = >::create_type_data(()); +/// let with_multiplier = >::create_type_data((2.0, 4.0)); +/// +/// assert_eq!(without_multiplier.combine(1.0, 2.0), 3.0); +/// assert_eq!(with_multiplier.combine(1.0, 2.0), 10.0); +/// ``` +/// +/// [`TypeRegistration`]: crate::TypeRegistration +/// [`TypeRegistry::register_type_data`]: crate::TypeRegistry::register_type_data +/// [`TypeRegistry::register_type_data_with`]: crate::TypeRegistry::register_type_data_with +/// [`Reflect` derive macro]: derive@crate::Reflect +pub trait CreateTypeData: TypeData { + /// Create this type data using the given input. + fn create_type_data(input: Input) -> Self; + + /// Inserts [`TypeData`] dependencies of this [`TypeData`]. + /// This is especially useful for trait [`TypeData`] that has a supertrait (ex: `A: B`). + /// When the [`TypeData`] for `A` is inserted, the `B` [`TypeData`] will also be inserted. + #[expect( + unused_variables, + reason = "default implementation does not have any dependencies" + )] + fn insert_dependencies(type_registration: &mut TypeRegistration) {} +} diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index ada6ad722845b..45be0f653af4d 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -1,5 +1,6 @@ use crate::{ - convert::ReflectConvert, serde::Serializable, FromReflect, Reflect, TypeInfo, TypePath, Typed, + convert::ReflectConvert, serde::Serializable, FromReflect, Reflect, TypeData, TypeInfo, + TypePath, Typed, }; use alloc::{boxed::Box, string::String}; use bevy_platform::{ @@ -7,13 +8,13 @@ use bevy_platform::{ sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}, }; use bevy_ptr::{Ptr, PtrMut}; +use bevy_reflect::CreateTypeData; use bevy_utils::TypeIdMap; use core::{ any::TypeId, fmt::Debug, ops::{Deref, DerefMut}, }; -use downcast_rs::{impl_downcast, Downcast}; use serde::{Deserialize, Serialize}; /// A registry of [reflected] types. @@ -328,7 +329,7 @@ impl TypeRegistry { /// /// Most of the time [`TypeRegistry::register`] can be used instead to register a type you derived [`Reflect`] for. /// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive, - /// or where the type is generic and cannot register e.g. [`ReflectSerialize`] unconditionally without knowing the specific type parameters, + /// or where the type is generic and cannot register the type data unconditionally without knowing the specific type parameters, /// this method can be used to insert additional type data. /// /// # Example @@ -340,7 +341,7 @@ impl TypeRegistry { /// type_registry.register_type_data::, ReflectSerialize>(); /// type_registry.register_type_data::, ReflectDeserialize>(); /// ``` - pub fn register_type_data>(&mut self) { + pub fn register_type_data>(&mut self) { let data = self.get_mut(TypeId::of::()).unwrap_or_else(|| { panic!( "attempted to call `TypeRegistry::register_type_data` for type `{T}` with data `{D}` without registering `{T}` first", @@ -348,7 +349,31 @@ impl TypeRegistry { D = core::any::type_name::(), ) }); - data.insert(D::from_type()); + data.insert(D::create_type_data(())); + } + + /// Registers the type data `D` with parameter `P` for type `T`. + /// + /// Most of the time [`TypeRegistry::register`] can be used instead to register a type you derived [`Reflect`] for. + /// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive, + /// or where the type is generic and cannot register the type data unconditionally without knowing the specific type parameters, + /// this method can be used to insert additional type data. + /// + /// If no parameters are needed for the type data or the type data does not accept parameters, + /// then [`TypeRegistry::register_type_data`] may be used instead. + pub fn register_type_data_with, P>( + &mut self, + params: P, + ) { + let data = self.get_mut(TypeId::of::()).unwrap_or_else(|| { + panic!( + "attempted to call `TypeRegistry::register_type_data_with` for type `{T}` with data `{D}` and params `{P}` without registering `{T}` first", + T = T::type_path(), + D = ::core::any::type_name::(), + P = ::core::any::type_name::

(), + ) + }); + data.insert(D::create_type_data(params)); } /// Registers a fallible conversion from type T to U with the reflection @@ -592,13 +617,13 @@ impl TypeRegistryArc { /// # Example /// /// ``` -/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault, FromType}; +/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault, CreateTypeData}; /// let mut registration = TypeRegistration::of::>(); /// /// assert_eq!("core::option::Option", registration.type_info().type_path()); /// assert_eq!("Option", registration.type_info().type_path_table().short_path()); /// -/// registration.insert::(FromType::>::from_type()); +/// registration.insert::(CreateTypeData::>::create_type_data(())); /// assert!(registration.data::().is_some()) /// ``` /// @@ -640,6 +665,10 @@ impl TypeRegistration { /// /// If another instance of `T` was previously inserted, it is replaced. /// + /// Note that unlike [`TypeRegistration::register_type_data`], this will not + /// automatically insert any type data dependencies for `T`. + /// That will need to be done manually using [`CreateTypeData::insert_dependencies`]. + /// /// [type data]: TypeData pub fn insert(&mut self, data: T) { self.data.insert(TypeId::of::(), Box::new(data)); @@ -659,9 +688,23 @@ impl TypeRegistration { /// Inserts the [`TypeData`] instance of `T` created for `V`, and inserts any /// [`TypeData`] dependencies for that combination of `T` and `V`. + /// + /// To register [`TypeData`] that requires input (i.e. it doesn't take `()` as its input), + /// see [`TypeRegistration::register_type_data_with`]. #[inline] - pub fn register_type_data, V>(&mut self) { - self.insert(T::from_type()); + pub fn register_type_data, V>(&mut self) { + self.insert(T::create_type_data(())); + T::insert_dependencies(self); + } + + /// Inserts the [`TypeData`] instance of `T` created for `V` with some input `I`, + /// and inserts any [`TypeData`] dependencies for that combination of `T`, `V`, and `I`. + /// + /// To register [`TypeData`] that doesn't require input (i.e. it expects `()`), + /// see [`TypeRegistration::register_type_data`]. + #[inline] + pub fn register_type_data_with, V, I>(&mut self, input: I) { + self.insert(T::create_type_data(input)); T::insert_dependencies(self); } @@ -790,57 +833,17 @@ impl Clone for TypeRegistration { } } -/// A trait used to type-erase type metadata. -/// -/// Type data can be registered to the [`TypeRegistry`] and stored on a type's [`TypeRegistration`]. -/// -/// While type data is often generated using the [`#[reflect_trait]`](crate::reflect_trait) macro, -/// almost any type that implements [`Clone`] can be considered "type data". -/// This is because it has a blanket implementation over all `T` where `T: Clone + Send + Sync + 'static`. -/// -/// See the [crate-level documentation] for more information on type data and type registration. -/// -/// [crate-level documentation]: crate -pub trait TypeData: Downcast + Send + Sync { - /// Creates a type-erased clone of this value. - fn clone_type_data(&self) -> Box; -} - -impl_downcast!(TypeData); - -impl TypeData for T -where - T: Clone, -{ - fn clone_type_data(&self) -> Box { - Box::new(self.clone()) - } -} - -/// Trait used to generate [`TypeData`] for trait reflection. -/// -/// This is used by the `#[derive(Reflect)]` macro to generate an implementation -/// of [`TypeData`] to pass to [`TypeRegistration::insert`]. -pub trait FromType { - /// Creates an instance of `Self` for type `T`. - fn from_type() -> Self; - /// Inserts [`TypeData`] dependencies of this [`TypeData`]. - /// This is especially useful for trait [`TypeData`] that has a supertrait (ex: `A: B`). - /// When the [`TypeData`] for `A` is inserted, the `B` [`TypeData`] will also be inserted. - fn insert_dependencies(_type_registration: &mut TypeRegistration) {} -} - /// A struct used to serialize reflected instances of a type. /// /// A `ReflectSerialize` for type `T` can be obtained via -/// [`FromType::from_type`]. +/// [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectSerialize { get_serializable: fn(value: &dyn Reflect) -> Serializable, } -impl FromType for ReflectSerialize { - fn from_type() -> Self { +impl CreateTypeData for ReflectSerialize { + fn create_type_data(_input: ()) -> Self { ReflectSerialize { get_serializable: |value| { value @@ -876,7 +879,7 @@ impl ReflectSerialize { /// A struct used to deserialize reflected instances of a type. /// /// A `ReflectDeserialize` for type `T` can be obtained via -/// [`FromType::from_type`]. +/// [`CreateTypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectDeserialize { /// Function used by [`ReflectDeserialize::deserialize`] to @@ -902,8 +905,8 @@ impl ReflectDeserialize { } } -impl Deserialize<'a> + Reflect> FromType for ReflectDeserialize { - fn from_type() -> Self { +impl Deserialize<'a> + Reflect> CreateTypeData for ReflectDeserialize { + fn create_type_data(_input: ()) -> Self { ReflectDeserialize { func: |deserializer| Ok(Box::new(T::deserialize(deserializer)?)), } @@ -1006,8 +1009,8 @@ impl ReflectFromPtr { unsafe_code, reason = "We must interact with pointers here, which are inherently unsafe." )] -impl FromType for ReflectFromPtr { - fn from_type() -> Self { +impl CreateTypeData for ReflectFromPtr { + fn create_type_data(_input: ()) -> Self { ReflectFromPtr { type_id: TypeId::of::(), from_ptr: |ptr| { diff --git a/crates/bevy_remote/src/schemas/json_schema.rs b/crates/bevy_remote/src/schemas/json_schema.rs index 9324f26c09537..0519c220ad045 100644 --- a/crates/bevy_remote/src/schemas/json_schema.rs +++ b/crates/bevy_remote/src/schemas/json_schema.rs @@ -601,8 +601,8 @@ mod tests { #[derive(Clone)] pub struct ReflectCustomData; - impl bevy_reflect::FromType for ReflectCustomData { - fn from_type() -> Self { + impl bevy_reflect::CreateTypeData for ReflectCustomData { + fn create_type_data(_input: ()) -> Self { ReflectCustomData } } diff --git a/crates/bevy_settings/src/lib.rs b/crates/bevy_settings/src/lib.rs index 4b9c4eff84fae..8bfa67d44502b 100644 --- a/crates/bevy_settings/src/lib.rs +++ b/crates/bevy_settings/src/lib.rs @@ -30,7 +30,7 @@ use bevy_log::warn; use bevy_reflect::{ prelude::ReflectDefault, serde::{TypedReflectDeserializer, TypedReflectSerializer}, - FromReflect, FromType, PartialReflect, ReflectMut, TypeInfo, TypePath, TypeRegistration, + CreateTypeData, FromReflect, PartialReflect, ReflectMut, TypeInfo, TypePath, TypeRegistration, TypeRegistry, }; @@ -172,8 +172,8 @@ pub struct ReflectSettingsGroup { settings_source: Option<&'static str>, } -impl FromType for ReflectSettingsGroup { - fn from_type() -> Self { +impl CreateTypeData for ReflectSettingsGroup { + fn create_type_data(_input: ()) -> Self { ReflectSettingsGroup { settings_group_name: T::settings_group_name(), settings_key_name: T::settings_key_name(), diff --git a/crates/bevy_state/src/reflect.rs b/crates/bevy_state/src/reflect.rs index 1a2ffbfe0938e..e1e4bec643de3 100644 --- a/crates/bevy_state/src/reflect.rs +++ b/crates/bevy_state/src/reflect.rs @@ -1,7 +1,7 @@ use crate::state::{FreelyMutableState, NextState, State, States}; use bevy_ecs::{reflect::from_reflect_with_fallback, world::World}; -use bevy_reflect::{FromType, Reflect, TypePath, TypeRegistry}; +use bevy_reflect::{CreateTypeData, Reflect, TypePath, TypeRegistry}; /// A struct used to operate on the reflected [`States`] trait of a type. /// @@ -19,12 +19,12 @@ pub struct ReflectStateFns { impl ReflectStateFns { /// Get the default set of [`ReflectStateFns`] for a specific component type using its - /// [`FromType`] implementation. + /// [`CreateTypeData`] 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() -> Self { - >::from_type().0 + >::create_type_data(()).0 } } @@ -35,8 +35,8 @@ impl ReflectState { } } -impl FromType for ReflectState { - fn from_type() -> Self { +impl CreateTypeData for ReflectState { + fn create_type_data(_input: ()) -> Self { ReflectState(ReflectStateFns { reflect: |world| { world @@ -65,12 +65,12 @@ pub struct ReflectFreelyMutableStateFns { impl ReflectFreelyMutableStateFns { /// Get the default set of [`ReflectFreelyMutableStateFns`] for a specific component type using its - /// [`FromType`] implementation. + /// [`CreateTypeData`] 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() -> Self { - >::from_type().0 + >::create_type_data(()).0 } } @@ -90,8 +90,8 @@ impl ReflectFreelyMutableState { } } -impl FromType for ReflectFreelyMutableState { - fn from_type() -> Self { +impl CreateTypeData for ReflectFreelyMutableState { + fn create_type_data(_input: ()) -> Self { ReflectFreelyMutableState(ReflectFreelyMutableStateFns { set_next_state: |world, reflected_state, registry| { let new_state: S = from_reflect_with_fallback( diff --git a/examples/reflection/type_data.rs b/examples/reflection/type_data.rs index 56dafa8522d6e..ecc2f51ee8613 100644 --- a/examples/reflection/type_data.rs +++ b/examples/reflection/type_data.rs @@ -2,24 +2,24 @@ use bevy::{ prelude::*, - reflect::{FromType, TypeRegistry}, + reflect::{CreateTypeData, TypeRegistry}, }; // It's recommended to read this example from top to bottom. // Comments are provided to explain the code and its purpose as you go along. fn main() { trait Damageable { - type Health; + type Health: Sized + core::ops::Mul; fn damage(&mut self, damage: Self::Health); } #[derive(Reflect, PartialEq, Debug)] struct Zombie { - health: u32, + health: i32, } impl Damageable for Zombie { - type Health = u32; + type Health = i32; fn damage(&mut self, damage: Self::Health) { self.health -= damage; } @@ -49,21 +49,23 @@ fn main() { // Just remember that we're working with `Reflect` data, // so we can't use `Self`, generics, or associated types. // In those cases, we'll have to use `dyn Reflect` trait objects. - damage: fn(&mut dyn Reflect, damage: Box), + damage: fn(&mut dyn Reflect, damage: Box, multiplier: i32), + multiplier: i32, } - // Now, we can create a blanket implementation of the `FromType` trait to construct our type data + // Now, we can create a blanket implementation of the `CreateTypeData` trait to construct our type data // for any type that implements `Reflect` and `Damageable`. - impl> FromType for ReflectDamageable { - fn from_type() -> Self { + impl> CreateTypeData for ReflectDamageable { + fn create_type_data(_input: ()) -> Self { Self { - damage: |reflect, damage| { + damage: |reflect, damage, multiplier| { // This requires that `reflect` is `T` and not a dynamic representation like `DynamicStruct`. // We could have the function pointer return a `Result`, but we'll just `unwrap` for simplicity. let damageable = reflect.downcast_mut::().unwrap(); - let damage = damage.take::().unwrap(); + let damage = damage.take::().unwrap() * multiplier; damageable.damage(damage); }, + multiplier: 1, } } } @@ -71,7 +73,7 @@ fn main() { // It's also common to provide convenience methods for calling the type-specific operations. impl ReflectDamageable { pub fn damage(&self, reflect: &mut dyn Reflect, damage: Box) { - (self.damage)(reflect, damage); + (self.damage)(reflect, damage, self.multiplier); } } @@ -88,7 +90,7 @@ fn main() { .unwrap(); // And call our method: - reflect_damageable.damage(value.as_reflect_mut(), Box::new(25u32)); + reflect_damageable.damage(value.as_reflect_mut(), Box::new(25i32)); assert_eq!(value.take::().unwrap(), Zombie { health: 75 }); // This is a simple example, but type data can be used for much more complex operations. @@ -102,11 +104,11 @@ fn main() { // the derive macro will automatically look for a type named `ReflectDamageable` in the current scope. #[reflect(Damageable)] struct Skeleton { - health: u32, + health: i32, } impl Damageable for Skeleton { - type Health = u32; + type Health = i32; fn damage(&mut self, damage: Self::Health) { self.health -= damage; } @@ -115,15 +117,66 @@ fn main() { // This will now register `Skeleton` along with its `ReflectDamageable` type data. registry.register::(); + // Additionally, type data can accept arbitrary input. + // You might have already noticed that the default input is simply `()`, + // but we can configure this with a new impl with the relevant data. + // + // Let's add the ability to define a damage multiplier by accepting an input of type `i32`. + impl> CreateTypeData for ReflectDamageable { + fn create_type_data(input: i32) -> Self { + Self { + damage: move |reflect, damage, multiplier| { + // This requires that `reflect` is `T` and not a dynamic representation like `DynamicStruct`. + // We could have the function pointer return a `Result`, but we'll just `unwrap` for simplicity. + let damageable = reflect.downcast_mut::().unwrap(); + let damage = damage.take::().unwrap() * multiplier; + damageable.damage(damage); + }, + multiplier: input, + } + } + } + + #[derive(Reflect)] + // Now we can pass our `i32` input into our type data: + #[reflect(Damageable(2))] + // Note that this accepts any expression. The derive macro will copy it verbatim into the impl. + // This means you could also write: + // - #[reflect(Damageable(1 + 1))] + // - #[reflect(Damageable(4 / 2))] + // - #[reflect(Damageable({let v = vec![0, 1, 2]; v.into_iter().fold(1, |acc, x| acc * x)}))] + // - etc. + struct Beast { + health: i32, + } + + impl Damageable for Beast { + type Health = i32; + fn damage(&mut self, damage: Self::Health) { + self.health -= damage; + } + } + + // Now when we register `Beast` it will automatically register with a `ReflectDamageable` with a multiplier of `2`. + registry.register::(); + + let data = registry + .get_type_data::(core::any::TypeId::of::()) + .unwrap(); + assert_eq!(data.multiplier, 2); + + // We can also choose to define the input when manually registering type data. + registry.register_type_data_with::(5); + // And for object-safe traits (see https://doc.rust-lang.org/reference/items/traits.html#object-safety), // Bevy provides a convenience macro for generating type data that converts `dyn Reflect` into `dyn MyTrait`. #[reflect_trait] trait Health { - fn health(&self) -> u32; + fn health(&self) -> i32; } impl Health for Skeleton { - fn health(&self) -> u32 { + fn health(&self) -> i32 { self.health } } @@ -148,11 +201,16 @@ fn main() { // - `ReflectDefault` for types that implement `Default` // - `ReflectFromWorld` for types that implement `FromWorld` // - `ReflectComponent` for types that implement `Component` + // - `ReflectBundle` for types that implement `Bundle` // - `ReflectResource` for types that implement `Resource` + // - `ReflectAsset` for types that implement `Asset` + // - `ReflectEvent` for types that implement `Event` + // - `ReflectMessage` for types that implement `Message` // - `ReflectSerialize` for types that implement `Serialize` // - `ReflectDeserialize` for types that implement `Deserialize` + // - And more! // - // And here are some that are automatically registered by the `Reflect` derive macro: + // There are also some that are automatically registered by the `Reflect` derive macro: // - `ReflectFromPtr` // - `ReflectFromReflect` (if not `#[reflect(from_reflect = false)]`) }