-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bevy_reflect: enforce that type data is only inserted for the correct type #4567
bevy_reflect: enforce that type data is only inserted for the correct type #4567
Conversation
Is isn't enough if we get a way to build a TypeRegistration for a type created at runtime without rust counterpart. For example for scripting. |
That's true, however the whole When/if that is eventually implemented, we can add a way to add type registration data that does not use |
self.data.insert(TypeId::of::<T>(), Box::new(data)); | ||
/// If another instance of `D` was previously inserted, it is replaced. | ||
pub fn insert<T: 'static, D: TypeData + FromType<T>>(&mut self) { | ||
if self.type_id != std::any::TypeId::of::<T>() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
if self.type_id != std::any::TypeId::of::<T>() { | |
if self.type_id != TypeId::of::<T>() { |
/// Inserts an instance of `D` into this registration's type data. | ||
/// The value is created using the [`FromType<T>`] impl for `D` | ||
/// and `T` must match the type that this [`TypeRegistration`] was created for. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe a Panics
section to make it absolutely clear to users that this method can and will panic if the wrong type is used?
if self.type_id != std::any::TypeId::of::<T>() { | ||
panic!( | ||
"called `TypeRegistration::insert` on a registration for `{}` with data for type `{}`", | ||
self.short_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe we use the full name here for clarity? There may be odd instances where a user is trying to insert for type my_crate::Foo
but is accidentally using lib_crate::Foo
(which would result in called 'TypeRegistration::insert' on a registration for 'Foo' with data for type 'lib_crate::Foo'
.
Admittedly, this isn't that bad already, but it could be a bit clearer imo.
(Would need to update the panicking test as well.)
Unless I'm misunderstanding something, these two statements seem contradictory. If you can only insert |
Oh, true. So while you can replace its value, there is only one valid value for you to replace it with... Anyways, I just thought of another way to let type_registration = ...;
let reflect_from_ptr = type_registration.data::<ReflectFromPtr>().unwrap();
assert_eq!(type_registration.type_id(), reflect_from_ptr.type_id());
...
// SAFE: the type id has been checked, `val` is valid
unsafe { reflect_from_ptr.as_reflect_ptr(&val as *const ()) }; That way bevy is sound and user has to make sure that nobody did weird things to the registration. EDIT: that doesn't help us in the case of |
Ping @jakobhellermann this branch likely has merge conflicts from #4712. To resolve, simply move your line of code in |
I thought about this some more and found a use case where the type data shouldn't just be I think this the design of this PR is too restrictive and we can solve the issue in #4475 without it. |
Objective
The
TypeRegistry
in bevy_reflect has aHashMap<TypeId, TypeRegistration>
where each type registration can contain arbitrary "TypeData", usually created for the typeT
from<TypeData as FromType<T>>::from_type())
.This is what
#[reflect(Deserialize, MyTrait, Component)]
expands to.The problem is that nobody enforces that the data inserted into the
TypeRegistration
of typeT
is actually created usingFromType
for the sameT
.You could currently do
or
This is unexpected and may lead to panics, but makes it impossible to do stuff like #4475 that depends on the correct type of the type data for soundness.
Solution
Change the
insert
method to be used likewhich panics when used with the wrong type.
Also remove the
data_mut
method, I don't know of any use case and if you want to overwrite it you can justinsert
it again to overwrite it.This does remove the ability to insert TypeData not created using
FromType
but as any arbitrary instance, but that's actually a feature IMO since the type data should not depend on any information other than the typeT
. And if there are use cases I'm not thinking of right now we can always add them later.