From 707a6323794a105b2df98c2a0a260c47bd396f45 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sat, 23 Apr 2022 12:13:24 +0200 Subject: [PATCH] bevy_reflect: enforce that type data is only inserted for the correct type --- .../bevy_reflect_derive/src/lib.rs | 2 +- crates/bevy_reflect/src/impls/std.rs | 11 ++-- crates/bevy_reflect/src/type_registry.rs | 60 +++++++++++++------ 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 8128b292b8559..ae923caac2c5c 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -719,7 +719,7 @@ fn impl_get_type_registration( impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_name #ty_generics #where_clause { fn get_type_registration() -> #bevy_reflect_path::TypeRegistration { let mut registration = #bevy_reflect_path::TypeRegistration::of::<#type_name #ty_generics>(); - #(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());)* + #(registration.insert::();)* registration } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 0b1d4097e1e11..0e6624632e912 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,8 +1,7 @@ use crate as bevy_reflect; use crate::{ - map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, - List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, - TypeRegistration, + map_partial_eq, serde::Serializable, DynamicMap, FromReflect, GetTypeRegistration, List, + ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeRegistration, }; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; @@ -147,7 +146,7 @@ unsafe impl Reflect for Vec { impl Deserialize<'de>> GetTypeRegistration for Vec { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::>(); - registration.insert::(FromType::>::from_type()); + registration.insert::(); registration } } @@ -269,7 +268,7 @@ where { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::(); - registration.insert::(FromType::::from_type()); + registration.insert::(); registration } } @@ -354,7 +353,7 @@ unsafe impl Reflect 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::(); registration } } diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index a6aa64f487305..ab84abc199a58 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -182,27 +182,30 @@ impl TypeRegistration { /// data. /// /// Returns `None` if no such value exists. + /// + /// The value is guaranteed to be a value of `T` generated using [`FromType`] of the type that this + /// registration is used for. pub fn data(&self) -> Option<&T> { self.data .get(&TypeId::of::()) .and_then(|value| value.downcast_ref()) } - /// Returns a mutable reference to the value of type `T` in this - /// registration's type data. + /// Inserts an instance of `D` into this registration's type data. + /// The value is created using the [`FromType`] impl for `D` + /// and `T` must match the type that this [`TypeRegistration`] was created for. /// - /// Returns `None` if no such value exists. - pub fn data_mut(&mut self) -> Option<&mut T> { - self.data - .get_mut(&TypeId::of::()) - .and_then(|value| value.downcast_mut()) - } - - /// Inserts an instance of `T` 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 insert>(&mut self) { + if self.type_id != std::any::TypeId::of::() { + panic!( + "called `TypeRegistration::insert` on a registration for `{}` with data for type `{}`", + self.short_name, + std::any::type_name::() + ); + } + let data = >::from_type(); + self.data.insert(TypeId::of::(), Box::new(data)); } /// Creates type registration information for `T`. @@ -308,8 +311,8 @@ where /// 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`]. +/// This is used by [`TypeRegistration::insert`] to generate an implementation +/// of [`TypeData`] for the type `T`. pub trait FromType { fn from_type() -> Self; } @@ -352,7 +355,7 @@ impl Deserialize<'a> + Reflect> FromType for ReflectDeserialize { #[cfg(test)] mod test { - use crate::TypeRegistration; + use crate::{FromType, TypeRegistration}; use bevy_utils::HashMap; #[test] @@ -423,4 +426,27 @@ mod test { "Option, (String, Option)>>" ); } + + #[derive(Clone)] + struct SomeTypeData; + impl FromType for SomeTypeData { + fn from_type() -> Self { + SomeTypeData + } + } + + #[test] + fn test_type_registration_insert() { + let mut registration = TypeRegistration::of::(); + registration.insert::(); + + assert!(registration.data::().is_some()); + } + + #[test] + #[should_panic = "for `f64` with data for type `f32`"] + fn test_type_registration_wrong_type() { + let mut registration = TypeRegistration::of::(); + registration.insert::(); + } }