From 2a96eed898ef1cb8fa810d97049dba8c94c7d10b Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Mon, 11 Sep 2023 17:25:51 -0700 Subject: [PATCH] Modified TypeData logic --- crates/bevy_app/src/app.rs | 2 +- crates/bevy_asset/src/reflect.rs | 10 +- crates/bevy_ecs/src/change_detection.rs | 4 +- crates/bevy_ecs/src/reflect/bundle.rs | 10 +- crates/bevy_ecs/src/reflect/component.rs | 17 +- .../bevy_ecs/src/reflect/entity_commands.rs | 4 +- crates/bevy_ecs/src/reflect/map_entities.rs | 6 +- crates/bevy_ecs/src/reflect/resource.rs | 10 +- .../bevy_reflect_derive/src/lib.rs | 4 +- .../bevy_reflect_derive/src/registration.rs | 20 ++- .../src/trait_reflection.rs | 4 +- crates/bevy_reflect/src/from_reflect.rs | 6 +- crates/bevy_reflect/src/impls/smallvec.rs | 10 +- crates/bevy_reflect/src/impls/std.rs | 42 ++--- crates/bevy_reflect/src/lib.rs | 4 +- crates/bevy_reflect/src/std_traits.rs | 8 +- crates/bevy_reflect/src/type_data.rs | 166 ++++++++++++++++++ crates/bevy_reflect/src/type_registry.rs | 134 +++++++------- 18 files changed, 315 insertions(+), 146 deletions(-) create mode 100644 crates/bevy_reflect/src/type_data.rs diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 4773ad80a54db..a0a64695e1260 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -724,7 +724,7 @@ impl App { #[cfg(feature = "bevy_reflect")] pub fn register_type_data< T: bevy_reflect::Reflect + 'static, - D: bevy_reflect::TypeData + bevy_reflect::FromType, + D: bevy_reflect::BaseTypeData + bevy_reflect::TypeData, >( &mut self, ) -> &mut Self { diff --git a/crates/bevy_asset/src/reflect.rs b/crates/bevy_asset/src/reflect.rs index 6e00323826de1..54549c6b7835c 100644 --- a/crates/bevy_asset/src/reflect.rs +++ b/crates/bevy_asset/src/reflect.rs @@ -1,7 +1,7 @@ use std::any::{Any, TypeId}; use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World}; -use bevy_reflect::{FromReflect, FromType, Reflect}; +use bevy_reflect::{FromReflect, Reflect, TypeData}; use crate::{Asset, Assets, Handle, UntypedAssetId, UntypedHandle}; @@ -122,8 +122,8 @@ impl ReflectAsset { } } -impl FromType for ReflectAsset { - fn from_type() -> Self { +impl TypeData for ReflectAsset { + fn create_type_data() -> Self { ReflectAsset { handle_type_id: TypeId::of::>(), assets_resource_type_id: TypeId::of::>(), @@ -217,8 +217,8 @@ impl ReflectHandle { } } -impl FromType> for ReflectHandle { - fn from_type() -> Self { +impl TypeData> for ReflectHandle { + fn create_type_data() -> Self { ReflectHandle { asset_type_id: TypeId::of::(), downcast_handle_untyped: |handle: &dyn Any| { diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index a00a5cd6bb66b..b67fa870efa47 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -902,7 +902,7 @@ impl std::fmt::Debug for MutUntyped<'_> { mod tests { use bevy_ecs_macros::Resource; use bevy_ptr::PtrMut; - use bevy_reflect::{FromType, ReflectFromPtr}; + use bevy_reflect::{ReflectFromPtr, TypeData}; use crate::{ self as bevy_ecs, @@ -1160,7 +1160,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/reflect/bundle.rs b/crates/bevy_ecs/src/reflect/bundle.rs index 8b5f5e20843c8..c5b05b07155bc 100644 --- a/crates/bevy_ecs/src/reflect/bundle.rs +++ b/crates/bevy_ecs/src/reflect/bundle.rs @@ -9,7 +9,7 @@ use crate::{ prelude::Bundle, world::{EntityWorldMut, FromWorld, World}, }; -use bevy_reflect::{FromType, Reflect, ReflectRef, TypeRegistry}; +use bevy_reflect::{Reflect, ReflectRef, TypeData, TypeRegistry}; use super::ReflectComponent; @@ -39,12 +39,12 @@ pub struct ReflectBundleFns { impl ReflectBundleFns { /// Get the default set of [`ReflectBundleFns`] for a specific bundle type using its - /// [`FromType`] implementation. + /// [`TypeData`] 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 } } @@ -124,8 +124,8 @@ impl ReflectBundle { } } -impl FromType for ReflectBundle { - fn from_type() -> Self { +impl TypeData for ReflectBundle { + fn create_type_data() -> Self { ReflectBundle(ReflectBundleFns { from_world: |world| Box::new(B::from_world(world)), insert: |entity, reflected_bundle| { diff --git a/crates/bevy_ecs/src/reflect/component.rs b/crates/bevy_ecs/src/reflect/component.rs index f91ac8e900225..5d3392409f3af 100644 --- a/crates/bevy_ecs/src/reflect/component.rs +++ b/crates/bevy_ecs/src/reflect/component.rs @@ -14,17 +14,17 @@ //! [`get_type_registration`] method (see the relevant code[^1]). //! //! ```ignore -//! registration.insert::(FromType::::from_type()); +//! registration.register::(); //! ``` //! //! This line adds a `ReflectComponent` to the registration data for the type in question. //! 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` +//! The `.register::()` in the previous line calls the `TypeData` //! implementation of `ReflectComponent`. //! -//! The `FromType` impl creates a function per field of [`ReflectComponentFns`]. +//! The [`TypeData`] 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 @@ -45,6 +45,7 @@ //! [^1]: `crates/bevy_reflect/bevy_reflect_derive/src/registration.rs` //! //! [`get_type_registration`]: bevy_reflect::GetTypeRegistration::get_type_registration +//! [`TypeData`]: bevy_reflect::TypeData use crate::{ change_detection::Mut, @@ -52,7 +53,7 @@ use crate::{ entity::Entity, world::{unsafe_world_cell::UnsafeEntityCell, EntityRef, EntityWorldMut, FromWorld, World}, }; -use bevy_reflect::{FromType, Reflect}; +use bevy_reflect::{Reflect, TypeData}; /// A struct used to operate on reflected [`Component`] of a type. /// @@ -110,12 +111,12 @@ pub struct ReflectComponentFns { impl ReflectComponentFns { /// Get the default set of [`ReflectComponentFns`] for a specific component type using its - /// [`FromType`] implementation. + /// [`TypeData`] 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 } } @@ -236,8 +237,8 @@ impl ReflectComponent { } } -impl FromType for ReflectComponent { - fn from_type() -> Self { +impl TypeData for ReflectComponent { + fn create_type_data() -> Self { ReflectComponent(ReflectComponentFns { from_world: |world| Box::new(C::from_world(world)), insert: |entity, reflected_component| { diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index da9374bbf8a06..fd1d224c405ec 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -34,7 +34,7 @@ pub trait ReflectCommandExt { /// /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::reflect::ReflectCommandExt; - /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// # use bevy_reflect::{FromReflect, Reflect, TypeRegistry}; /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] /// struct Prefab{ @@ -104,7 +104,7 @@ pub trait ReflectCommandExt { /// /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::reflect::ReflectCommandExt; - /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry}; + /// # use bevy_reflect::{FromReflect, Reflect, TypeRegistry}; /// /// // A resource that can hold any component that implements reflect as a boxed reflect component /// #[derive(Resource)] diff --git a/crates/bevy_ecs/src/reflect/map_entities.rs b/crates/bevy_ecs/src/reflect/map_entities.rs index 7a5fe4257f0e5..dd2caa3082a06 100644 --- a/crates/bevy_ecs/src/reflect/map_entities.rs +++ b/crates/bevy_ecs/src/reflect/map_entities.rs @@ -3,7 +3,7 @@ use crate::{ entity::{Entity, EntityMapper, MapEntities}, world::World, }; -use bevy_reflect::FromType; +use bevy_reflect::TypeData; use bevy_utils::HashMap; /// For a specific type of component, this maps any fields with values of type [`Entity`] to a new world. @@ -49,8 +49,8 @@ impl ReflectMapEntities { } } -impl FromType for ReflectMapEntities { - fn from_type() -> Self { +impl TypeData for ReflectMapEntities { + fn create_type_data() -> Self { ReflectMapEntities { map_entities: |world, entity_mapper, entities| { for &entity in entities { diff --git a/crates/bevy_ecs/src/reflect/resource.rs b/crates/bevy_ecs/src/reflect/resource.rs index 924eb54b09c8e..783d3ee796d60 100644 --- a/crates/bevy_ecs/src/reflect/resource.rs +++ b/crates/bevy_ecs/src/reflect/resource.rs @@ -9,7 +9,7 @@ use crate::{ system::Resource, world::{unsafe_world_cell::UnsafeWorldCell, FromWorld, World}, }; -use bevy_reflect::{FromType, Reflect}; +use bevy_reflect::{Reflect, TypeData}; /// A struct used to operate on reflected [`Resource`] of a type. /// @@ -61,12 +61,12 @@ pub struct ReflectResourceFns { impl ReflectResourceFns { /// Get the default set of [`ReflectResourceFns`] for a specific resource type using its - /// [`FromType`] implementation. + /// [`TypeData`] 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 } } @@ -164,8 +164,8 @@ impl ReflectResource { } } -impl FromType for ReflectResource { - fn from_type() -> Self { +impl TypeData for ReflectResource { + fn create_type_data() -> Self { ReflectResource(ReflectResourceFns { insert: |world, reflected_resource| { let mut resource = C::from_world(world); diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 11c1b88801385..e6a957f2f0dfb 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -299,7 +299,7 @@ pub fn derive_type_uuid(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 `TypeData` 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). /// @@ -324,7 +324,7 @@ pub fn derive_type_uuid(input: TokenStream) -> TokenStream { /// } /// /// // We can create the type data manually if we wanted: -/// let my_trait: ReflectMyTrait = FromType::::from_type(); +/// let my_trait: ReflectMyTrait = TypeData::::create_type_data(); /// /// // Or we can simply get it from the registry: /// let mut registry = TypeRegistry::default(); diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/registration.rs b/crates/bevy_reflect/bevy_reflect_derive/src/registration.rs index 0b0a31e0a38fd..dfbfbd348cc20 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/registration.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/registration.rs @@ -1,6 +1,7 @@ //! Contains code related specifically to Bevy's type registration. use crate::derive_data::ReflectMeta; +use crate::fq_std::FQOption; use crate::utility::{extend_where_clause, WhereClauseOptions}; use bit_set::BitSet; use quote::quote; @@ -20,7 +21,7 @@ pub(crate) fn impl_get_type_registration( 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()); + .register::() }) } else { None @@ -29,8 +30,10 @@ pub(crate) fn impl_get_type_registration( let serialization_data = serialization_denylist.map(|denylist| { let denylist = denylist.into_iter(); quote! { - let ignored_indices = ::core::iter::IntoIterator::into_iter([#(#denylist),*]); - registration.insert::<#bevy_reflect_path::serde::SerializationData>(#bevy_reflect_path::serde::SerializationData::new(ignored_indices)); + .insert(#bevy_reflect_path::serde::SerializationData::new({ + let ignored_indices = ::core::iter::IntoIterator::into_iter([#(#denylist),*]); + ignored_indices + }), #FQOption::None) } }); @@ -38,12 +41,11 @@ pub(crate) fn impl_get_type_registration( #[allow(unused_mut)] 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()); - #from_reflect_data - #serialization_data - #(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::::from_type());)* - registration + #bevy_reflect_path::TypeRegistration::of::() + .register::() + #from_reflect_data + #serialization_data + #(.register::())* } } } diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs b/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs index 14bd9d6d40674..4618e31bb9f11 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/trait_reflection.rs @@ -75,8 +75,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::TypeData for #reflect_trait_ident { + fn create_type_data() -> Self { Self { get_func: |reflect_value| { ::downcast_ref::(reflect_value).map(|value| value as &dyn #trait_ident) diff --git a/crates/bevy_reflect/src/from_reflect.rs b/crates/bevy_reflect/src/from_reflect.rs index 861d0b1d063d1..80d542294551e 100644 --- a/crates/bevy_reflect/src/from_reflect.rs +++ b/crates/bevy_reflect/src/from_reflect.rs @@ -1,4 +1,4 @@ -use crate::{FromType, Reflect}; +use crate::{Reflect, TypeData}; /// A trait that enables types to be dynamically constructed from reflected data. /// @@ -111,8 +111,8 @@ impl ReflectFromReflect { } } -impl FromType for ReflectFromReflect { - fn from_type() -> Self { +impl TypeData for ReflectFromReflect { + fn create_type_data() -> 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/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 1f7bce2b8bcb4..6946e5cd4fd37 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -4,9 +4,9 @@ use std::any::Any; use crate::utility::GenericTypeInfoCell; use crate::{ - self as bevy_reflect, FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, - Reflect, ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, - TypeRegistration, Typed, + self as bevy_reflect, FromReflect, GetTypeRegistration, List, ListInfo, ListIter, Reflect, + ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypeRegistration, + Typed, }; impl List for SmallVec @@ -176,8 +176,6 @@ where T::Item: FromReflect, { fn get_type_registration() -> TypeRegistration { - let mut registration = TypeRegistration::of::>(); - registration.insert::(FromType::>::from_type()); - registration + TypeRegistration::of::>().register::() } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 0f594a7f81235..dcbe7753ee69b 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -2,10 +2,10 @@ use crate::std_traits::ReflectDefault; use crate::{self as bevy_reflect, ReflectFromPtr, ReflectFromReflect, ReflectOwned}; use crate::{ impl_type_path, map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum, - DynamicMap, Enum, EnumInfo, FromReflect, FromType, GetTypeRegistration, List, ListInfo, - ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, - ReflectSerialize, TupleVariantInfo, TypeInfo, TypePath, TypeRegistration, Typed, - UnitVariantInfo, UnnamedField, ValueInfo, VariantFieldIter, VariantInfo, VariantType, + DynamicMap, Enum, EnumInfo, FromReflect, GetTypeRegistration, List, ListInfo, ListIter, Map, + MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, ReflectSerialize, + TupleVariantInfo, TypeInfo, TypePath, TypeRegistration, Typed, UnitVariantInfo, UnnamedField, + ValueInfo, VariantFieldIter, VariantInfo, VariantType, }; use crate::utility::{ @@ -353,9 +353,7 @@ macro_rules! impl_reflect_for_veclike { impl GetTypeRegistration for $ty { fn get_type_registration() -> TypeRegistration { - let mut registration = TypeRegistration::of::<$ty>(); - registration.insert::(FromType::<$ty>::from_type()); - registration + TypeRegistration::of::<$ty>().register::() } } @@ -576,9 +574,7 @@ macro_rules! impl_reflect_for_hashmap { S: TypePath + BuildHasher + Send + Sync, { fn get_type_registration() -> TypeRegistration { - let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration + TypeRegistration::of::().register::() } } @@ -770,7 +766,7 @@ impl TypePath for [T; N] { } // TODO: -// `FromType::from_type` requires `Deserialize<'de>` to be implemented for `T`. +// `TypeData::create_type_data` requires `Deserialize<'de>` to be implemented for `T`. // Currently serde only supports `Deserialize<'de>` for arrays up to size 32. // This can be changed to use const generics once serde utilizes const generics for arrays. // Tracking issue: https://github.com/serde-rs/serde/issues/1937 @@ -1152,11 +1148,10 @@ impl TypePath 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 + TypeRegistration::of::>() + .register::() + .register::() + .register::() } } @@ -1444,9 +1439,7 @@ impl TypePath for &'static Path { impl GetTypeRegistration for &'static Path { fn get_type_registration() -> TypeRegistration { - let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); - registration + TypeRegistration::of::().register::() } } @@ -1560,12 +1553,11 @@ 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 + TypeRegistration::of::() + .register::() + .register::() + .register::() + .register::() } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 6977b0bb71e9e..c2dcb927a71c9 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -446,7 +446,7 @@ //! [`'static` lifetime]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound //! [derive macro documentation]: derive@crate::Reflect //! [deriving `Reflect`]: derive@crate::Reflect -//! [type data]: TypeData +//! [type data]: BaseTypeData //! [`ReflectDefault`]: std_traits::ReflectDefault //! [object-safe]: https://doc.rust-lang.org/reference/items/traits.html#object-safety //! [`serde`]: ::serde @@ -476,6 +476,7 @@ mod reflect; mod struct_trait; mod tuple; mod tuple_struct; +mod type_data; mod type_info; mod type_path; mod type_registry; @@ -530,6 +531,7 @@ pub use reflect::*; pub use struct_trait::*; pub use tuple::*; pub use tuple_struct::*; +pub use type_data::*; pub use type_info::*; pub use type_path::*; pub use type_registry::*; diff --git a/crates/bevy_reflect/src/std_traits.rs b/crates/bevy_reflect/src/std_traits.rs index 2f9b84735e758..5767ec1d5dc7d 100644 --- a/crates/bevy_reflect/src/std_traits.rs +++ b/crates/bevy_reflect/src/std_traits.rs @@ -1,8 +1,8 @@ -use crate::{FromType, Reflect}; +use crate::{Reflect, TypeData}; /// 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 [`TypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box, @@ -14,8 +14,8 @@ impl ReflectDefault { } } -impl FromType for ReflectDefault { - fn from_type() -> Self { +impl TypeData for ReflectDefault { + fn create_type_data() -> Self { ReflectDefault { default: || Box::::default(), } diff --git a/crates/bevy_reflect/src/type_data.rs b/crates/bevy_reflect/src/type_data.rs new file mode 100644 index 0000000000000..04097e7c4aeaa --- /dev/null +++ b/crates/bevy_reflect/src/type_data.rs @@ -0,0 +1,166 @@ +use crate::TypeRegistry; +use core::fmt::{Debug, Formatter}; +use downcast_rs::{impl_downcast, Downcast}; + +/// Type-erased [`TypeData`]. +/// +/// 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. +/// +/// [`TypeRegistration`]: crate::TypeRegistration +/// [crate-level documentation]: crate +pub trait BaseTypeData: Downcast + Send + Sync { + fn type_name(&self) -> &'static str; + fn clone_type_data(&self) -> Box; +} +impl_downcast!(BaseTypeData); + +impl BaseTypeData for T +where + T: Clone, +{ + fn type_name(&self) -> &'static str { + std::any::type_name::() + } + + fn clone_type_data(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Debug for dyn BaseTypeData { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.write_str(self.type_name()) + } +} + +/// Trait used for generating data for a type to be stored in a [`TypeRegistry`]. +/// +/// This is used to provide additional information about a type that can be used +/// dynamically at runtime. +/// Most often, this data is tied to a trait so that the trait may be used dynamically. +/// +/// # Naming Convention +/// +/// The [derive macro] requires that type data be prefixed with `Reflect`. +/// This is done so that the macro's registrations are less visually noisy. +/// For example, the type data for [`Default`] is called [`ReflectDefault`], +/// and would be registered via the derive macro like `#[reflect(Default)]`. +/// +/// # Example +/// +/// Let's say we have the following code and want to be able to use the trait dynamically: +/// +/// ``` +/// # use bevy_reflect::{Reflect}; +/// trait Animal { +/// fn speak(&self) -> &'static str; +/// } +/// +/// #[derive(Reflect)] +/// struct Dog(String); +/// +/// impl Animal for Dog { +/// fn speak(&self) -> &'static str { +/// "woof" +/// } +/// } +/// ``` +/// +/// To do this, we can create a type data struct that implements [`TypeData`]: +/// +/// ``` +/// # use bevy_reflect::{TypeData, Reflect, FromReflect}; +/// # trait Animal { +/// # fn speak(&self) -> &'static str; +/// # } +/// # +/// # #[derive(Reflect)] +/// # struct Dog(String); +/// # +/// # impl Animal for Dog { +/// # fn speak(&self) -> &'static str { +/// # "woof" +/// # } +/// # } +/// # +/// #[derive(Clone)] +/// struct ReflectAnimal { +/// speak: fn(&dyn Reflect) -> &'static str, +/// } +/// +/// impl ReflectAnimal { +/// pub fn speak(&self, animal: &dyn Reflect) -> &'static str { +/// (self.speak)(animal) +/// } +/// } +/// +/// impl TypeData for ReflectAnimal { +/// fn create_type_data() -> Self { +/// Self { +/// speak: |animal| { +/// T::from_reflect(animal).unwrap().speak() +/// } +/// } +/// } +/// } +/// +/// // Usage +/// let dog = Dog("Fido".to_string()); +/// let data = >::create_type_data(); +/// assert_eq!(data.speak(&dog), "woof"); +/// ``` +/// +/// Alternatively, we can use the [`reflect_trait`] macro to generate a type data struct for us. +/// Note that this only works with [object-safe] traits. +/// +/// ``` +/// # use bevy_reflect::{TypeData, Reflect, FromReflect}; +/// # use bevy_reflect_derive::reflect_trait; +/// #[reflect_trait] +/// trait Animal { +/// fn speak(&self) -> &'static str; +/// } +/// +/// # #[derive(Reflect)] +/// # struct Dog(String); +/// # +/// # impl Animal for Dog { +/// # fn speak(&self) -> &'static str { +/// # "woof" +/// # } +/// # } +/// # +/// // Usage +/// let dog = Dog("Fido".to_string()); +/// let data = >::create_type_data(); +/// assert_eq!(data.get(&dog).unwrap().speak(), "woof"); +/// ``` +/// +/// [derive macro]: bevy_reflect_derive::Reflect +/// [`ReflectDefault`]: crate::std_traits::ReflectDefault +/// [`reflect_trait`]: crate::reflect_trait +/// [object-safe]: https://doc.rust-lang.org/reference/items/traits.html#object-safety +pub trait TypeData: BaseTypeData + Clone { + /// Create a new instance of this type data. + fn create_type_data() -> Self; + + /// Callback for when the type data is fully registered. + /// + /// Type data becomes fully registered in one of the following ways: + /// * The containing [`TypeRegistration`] is inserted into a [`TypeRegistry`] + /// * This type data is inserted with [`TypeRegistry::register_type_data`] + /// + /// This can be used to register additional type data when this type data is registered. + /// For example, to register the same data for related types or to register it + /// for container types (e.g. `Vec`, `Option`, etc). + /// + /// [`TypeRegistration`]: crate::TypeRegistration + #[allow(unused_variables)] + fn on_register(registry: &mut TypeRegistry) {} +} diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index aeaba79a2f6d5..c2e0c47051812 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -1,7 +1,7 @@ +use crate::type_data::{BaseTypeData, TypeData}; use crate::{serde::Serializable, Reflect, TypeInfo, Typed}; use bevy_ptr::{Ptr, PtrMut}; use bevy_utils::{HashMap, HashSet}; -use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use serde::Deserialize; use std::{any::TypeId, fmt::Debug, sync::Arc}; @@ -123,8 +123,16 @@ impl TypeRegistry { } self.full_name_to_id .insert(registration.type_name().to_string(), registration.type_id()); - self.registrations - .insert(registration.type_id(), registration); + + let entry = self + .registrations + .entry(registration.type_id()) + .insert(registration); + + let register_queue = entry.get().register_queue.clone(); + for on_register in register_queue.iter().rev() { + on_register(self); + } } /// Registers the type data `D` for type `T`. @@ -143,15 +151,16 @@ impl TypeRegistry { /// type_registry.register_type_data::, ReflectSerialize>(); /// type_registry.register_type_data::, ReflectDeserialize>(); /// ``` - pub fn register_type_data>(&mut self) { - let data = self.get_mut(TypeId::of::()).unwrap_or_else(|| { + pub fn register_type_data>(&mut self) { + let registration = 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", T = std::any::type_name::(), D = std::any::type_name::(), ) }); - data.insert(D::from_type()); + registration.insert_internal(D::create_type_data()); + D::on_register(self); } /// Returns a reference to the [`TypeRegistration`] of the type with the @@ -220,7 +229,7 @@ impl TypeRegistry { .and_then(|id| self.registrations.get_mut(id)) } - /// Returns a reference to the [`TypeData`] of type `T` associated with the given [`TypeId`]. + /// Returns a reference to the [`BaseTypeData`] of type `T` associated with the given [`TypeId`]. /// /// The returned value may be used to downcast [`Reflect`] trait objects to /// trait objects of the trait used to generate `T`, provided that the @@ -229,16 +238,16 @@ impl TypeRegistry { /// /// If the specified type has not been registered, or if `T` is not present /// in its type registration, returns `None`. - pub fn get_type_data(&self, type_id: TypeId) -> Option<&T> { + pub fn get_type_data(&self, type_id: TypeId) -> Option<&T> { self.get(type_id) .and_then(|registration| registration.data::()) } - /// Returns a mutable reference to the [`TypeData`] of type `T` associated with the given [`TypeId`]. + /// Returns a mutable reference to the [`BaseTypeData`] of type `T` associated with the given [`TypeId`]. /// /// If the specified type has not been registered, or if `T` is not present /// in its type registration, returns `None`. - pub fn get_type_data_mut(&mut self, type_id: TypeId) -> Option<&mut T> { + pub fn get_type_data_mut(&mut self, type_id: TypeId) -> Option<&mut T> { self.get_mut(type_id) .and_then(|registration| registration.data_mut::()) } @@ -283,20 +292,20 @@ impl TypeRegistryArc { /// an implementation of the [`GetTypeRegistration`] trait. /// /// Along with the type's [`TypeInfo`] and [short name], -/// this struct also contains a type's registered [`TypeData`]. +/// this struct also contains a type's registered [`BaseTypeData`]. /// /// See the [crate-level documentation] for more information on type registration. /// /// # Example /// /// ``` -/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault, FromType}; -/// let mut registration = TypeRegistration::of::>(); +/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault}; +/// let registration = TypeRegistration::of::>(); /// /// assert_eq!("core::option::Option", registration.type_name()); /// assert_eq!("Option", registration.short_name()); /// -/// registration.insert::(FromType::>::from_type()); +/// let registration = registration.register::, ReflectDefault>(); /// assert!(registration.data::().is_some()) /// ``` /// @@ -304,8 +313,11 @@ impl TypeRegistryArc { /// [crate-level documentation]: crate pub struct TypeRegistration { short_name: String, - data: HashMap>, + data: HashMap>, type_info: &'static TypeInfo, + /// A queue of callbacks to dispatch whenever this registration is registered + /// into a [`TypeRegistry`]. + register_queue: Vec, } impl Debug for TypeRegistration { @@ -313,6 +325,7 @@ impl Debug for TypeRegistration { f.debug_struct("TypeRegistration") .field("short_name", &self.short_name) .field("type_info", &self.type_info) + .field("data", &self.data.values()) .finish() } } @@ -330,7 +343,7 @@ impl TypeRegistration { /// data. /// /// Returns `None` if no such value exists. - pub fn data(&self) -> Option<&T> { + pub fn data(&self) -> Option<&T> { self.data .get(&TypeId::of::()) .and_then(|value| value.downcast_ref()) @@ -340,7 +353,7 @@ impl TypeRegistration { /// registration's type data. /// /// Returns `None` if no such value exists. - pub fn data_mut(&mut self) -> Option<&mut T> { + pub fn data_mut(&mut self) -> Option<&mut T> { self.data .get_mut(&TypeId::of::()) .and_then(|value| value.downcast_mut()) @@ -351,11 +364,33 @@ impl TypeRegistration { self.type_info } - /// Inserts an instance of `T` into this registration's type data. + /// Inserts an instance of `D` into this registration's type data. /// - /// If another instance of `T` was previously inserted, it is replaced. - pub fn insert(&mut self, data: T) { - self.data.insert(TypeId::of::(), Box::new(data)); + /// If another instance of `D` was previously inserted, it is replaced. + pub fn register>(self) -> Self { + self.insert(D::create_type_data(), Some(D::on_register)) + } + + /// Inserts an instance of `T` into this registration's type data, + /// replacing any existing instance. + /// + /// This method should be used for dynamic type data that can't implement [`TypeData`]. + /// It's preferable to use [`TypeRegistration::register`] for all other `TypeData`. + /// + /// An optional callback can be provided to modify the [`TypeRegistry`] when + /// this registration is registered. + pub fn insert( + mut self, + data: T, + on_register: Option, + ) -> Self { + if let Some(on_register) = on_register { + self.register_queue.push(on_register); + } + + self.insert_internal(data); + + self } /// Creates type registration information for `T`. @@ -365,6 +400,7 @@ impl TypeRegistration { data: HashMap::default(), short_name: bevy_utils::get_short_name(type_name), type_info: T::type_info(), + register_queue: Vec::new(), } } @@ -381,6 +417,11 @@ impl TypeRegistration { pub fn type_name(&self) -> &'static str { self.type_info.type_name() } + + /// Inserts the given instance of `T` into this registration's type data. + fn insert_internal(&mut self, data: T) { + self.data.insert(TypeId::of::(), Box::new(data)); + } } impl Clone for TypeRegistration { @@ -394,54 +435,21 @@ impl Clone for TypeRegistration { data, short_name: self.short_name.clone(), type_info: self.type_info, + register_queue: self.register_queue.clone(), } } } -/// 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 { - 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 { - fn from_type() -> Self; -} - /// A struct used to serialize reflected instances of a type. /// -/// A `ReflectSerialize` for type `T` can be obtained via -/// [`FromType::from_type`]. +/// A `ReflectSerialize` for type `T` can be obtained via [`TypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectSerialize { get_serializable: for<'a> fn(value: &'a dyn Reflect) -> Serializable, } -impl FromType for ReflectSerialize { - fn from_type() -> Self { +impl TypeData for ReflectSerialize { + fn create_type_data() -> Self { ReflectSerialize { get_serializable: |value| { let value = value.downcast_ref::().unwrap_or_else(|| { @@ -463,7 +471,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`]. +/// [`TypeData::create_type_data`]. #[derive(Clone)] pub struct ReflectDeserialize { pub func: fn( @@ -487,8 +495,8 @@ impl ReflectDeserialize { } } -impl Deserialize<'a> + Reflect> FromType for ReflectDeserialize { - fn from_type() -> Self { +impl Deserialize<'a> + Reflect> TypeData for ReflectDeserialize { + fn create_type_data() -> Self { ReflectDeserialize { func: |deserializer| Ok(Box::new(T::deserialize(deserializer)?)), } @@ -555,8 +563,8 @@ impl ReflectFromPtr { } } -impl FromType for ReflectFromPtr { - fn from_type() -> Self { +impl TypeData for ReflectFromPtr { + fn create_type_data() -> Self { ReflectFromPtr { type_id: std::any::TypeId::of::(), to_reflect: |ptr| {