Skip to content

Commit 0f6316b

Browse files
soqbameknite
authored andcommitted
reflect: TypePath part 2 (bevyengine#8768)
# Objective - Followup to bevyengine#7184. - ~Deprecate `TypeUuid` and remove its internal references.~ No longer part of this PR. - Use `TypePath` for the type registry, and (de)serialisation instead of `std::any::type_name`. - Allow accessing type path information behind proxies. ## Solution - Introduce methods on `TypeInfo` and friends for dynamically querying type path. These methods supersede the old `type_name` methods. - Remove `Reflect::type_name` in favor of `DynamicTypePath::type_path` and `TypeInfo::type_path_table`. - Switch all uses of `std::any::type_name` in reflection, non-debugging contexts to use `TypePath`. --- ## Changelog - Added `TypePathTable` for dynamically accessing methods on `TypePath` through `TypeInfo` and the type registry. - Removed `type_name` from all `TypeInfo`-like structs. - Added `type_path` and `type_path_table` methods to all `TypeInfo`-like structs. - Removed `Reflect::type_name` in favor of `DynamicTypePath::reflect_type_path` and `TypeInfo::type_path`. - Changed the signature of all `DynamicTypePath` methods to return strings with a static lifetime. ## Migration Guide - Rely on `TypePath` instead of `std::any::type_name` for all stability guarantees and for use in all reflection contexts, this is used through with one of the following APIs: - `TypePath::type_path` if you have a concrete type and not a value. - `DynamicTypePath::reflect_type_path` if you have an `dyn Reflect` value without a concrete type. - `TypeInfo::type_path` for use through the registry or if you want to work with the represented type of a `DynamicFoo`. - Remove `type_name` from manual `Reflect` implementations. - Use `type_path` and `type_path_table` in place of `type_name` on `TypeInfo`-like structs. - Use `get_with_type_path(_mut)` over `get_with_type_name(_mut)`. ## Note to reviewers I think if anything we were a little overzealous in merging bevyengine#7184 and we should take that extra care here. In my mind, this is the "point of no return" for `TypePath` and while I think we all agree on the design, we should carefully consider if the finer details and current implementations are actually how we want them moving forward. For example [this incorrect `TypePath` implementation for `String`](https://github.com/soqb/bevy/blob/3fea3c6c0b5719dfbd3d4230f5282ec80d82556a/crates/bevy_reflect/src/impls/std.rs#L90) (note that `String` is in the default Rust prelude) snuck in completely under the radar.
1 parent a14c487 commit 0f6316b

36 files changed

+816
-787
lines changed

crates/bevy_app/src/app.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ impl App {
728728
/// See [`bevy_reflect::TypeRegistry::register_type_data`].
729729
#[cfg(feature = "bevy_reflect")]
730730
pub fn register_type_data<
731-
T: bevy_reflect::Reflect + 'static,
731+
T: bevy_reflect::Reflect + bevy_reflect::TypePath,
732732
D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
733733
>(
734734
&mut self,

crates/bevy_ecs/src/reflect/bundle.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ impl<B: Bundle + Reflect + FromWorld> FromType<B> for ReflectBundle {
146146
.for_each(|field| insert_field::<B>(entity, field, registry)),
147147
_ => panic!(
148148
"expected bundle `{}` to be named struct or tuple",
149-
std::any::type_name::<B>()
149+
// FIXME: once we have unique reflect, use `TypePath`.
150+
std::any::type_name::<B>(),
150151
),
151152
}
152153
},
@@ -163,7 +164,8 @@ impl<B: Bundle + Reflect + FromWorld> FromType<B> for ReflectBundle {
163164
.for_each(|field| apply_or_insert_field::<B>(entity, field, registry)),
164165
_ => panic!(
165166
"expected bundle `{}` to be named struct or tuple",
166-
std::any::type_name::<B>()
167+
// FIXME: once we have unique reflect, use `TypePath`.
168+
std::any::type_name::<B>(),
167169
),
168170
}
169171
},
@@ -188,14 +190,14 @@ fn insert_field<B: 'static>(
188190
if world.components().get_id(TypeId::of::<B>()).is_some() {
189191
panic!(
190192
"no `ReflectComponent` registration found for `{}`",
191-
field.type_name()
193+
field.reflect_type_path(),
192194
);
193195
};
194196
});
195197

196198
panic!(
197199
"no `ReflectBundle` registration found for `{}`",
198-
field.type_name()
200+
field.reflect_type_path(),
199201
)
200202
}
201203
}
@@ -214,14 +216,14 @@ fn apply_or_insert_field<B: 'static>(
214216
if world.components().get_id(TypeId::of::<B>()).is_some() {
215217
panic!(
216218
"no `ReflectComponent` registration found for `{}`",
217-
field.type_name()
219+
field.reflect_type_path(),
218220
);
219221
};
220222
});
221223

222224
panic!(
223225
"no `ReflectBundle` registration found for `{}`",
224-
field.type_name()
226+
field.reflect_type_path(),
225227
)
226228
}
227229
}

crates/bevy_ecs/src/reflect/entity_commands.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,10 @@ impl<'w, 's, 'a> ReflectCommandExt for EntityCommands<'w, 's, 'a> {
161161
self
162162
}
163163

164-
fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self {
164+
fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
165165
self.commands.add(RemoveReflect {
166166
entity: self.entity,
167-
component_type_name: component_type_name.into(),
167+
component_type_path: component_type_path.into(),
168168
});
169169
self
170170
}
@@ -189,15 +189,15 @@ fn insert_reflect(
189189
type_registry: &TypeRegistry,
190190
component: Box<dyn Reflect>,
191191
) {
192-
let type_info = component.type_name();
192+
let type_info = component.reflect_type_path();
193193
let Some(mut entity) = world.get_entity_mut(entity) else {
194-
panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {entity:?} because it doesn't exist in this World.", component.type_name());
194+
panic!("error[B0003]: Could not insert a reflected component (of type {}) for entity {entity:?} because it doesn't exist in this World.", component.reflect_type_path());
195195
};
196-
let Some(type_registration) = type_registry.get_with_name(type_info) else {
197-
panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.type_name());
196+
let Some(type_registration) = type_registry.get_with_type_path(type_info) else {
197+
panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.reflect_type_path());
198198
};
199199
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
200-
panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", component.type_name());
200+
panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", component.reflect_type_path());
201201
};
202202
reflect_component.insert(&mut entity, &*component);
203203
}
@@ -246,12 +246,12 @@ fn remove_reflect(
246246
world: &mut World,
247247
entity: Entity,
248248
type_registry: &TypeRegistry,
249-
component_type_name: Cow<'static, str>,
249+
component_type_path: Cow<'static, str>,
250250
) {
251251
let Some(mut entity) = world.get_entity_mut(entity) else {
252252
return;
253253
};
254-
let Some(type_registration) = type_registry.get_with_name(&component_type_name) else {
254+
let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
255255
return;
256256
};
257257
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
@@ -269,7 +269,7 @@ pub struct RemoveReflect {
269269
pub entity: Entity,
270270
/// The [`Component`](crate::component::Component) type name that will be used to remove a component
271271
/// of the same type from the entity.
272-
pub component_type_name: Cow<'static, str>,
272+
pub component_type_path: Cow<'static, str>,
273273
}
274274

275275
impl Command for RemoveReflect {
@@ -279,7 +279,7 @@ impl Command for RemoveReflect {
279279
world,
280280
self.entity,
281281
&registry.read(),
282-
self.component_type_name,
282+
self.component_type_path,
283283
);
284284
}
285285
}
@@ -413,7 +413,7 @@ mod tests {
413413

414414
commands
415415
.entity(entity)
416-
.remove_reflect(boxed_reflect_component_a.type_name().to_owned());
416+
.remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
417417
system_state.apply(&mut world);
418418

419419
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
@@ -443,7 +443,7 @@ mod tests {
443443
commands
444444
.entity(entity)
445445
.remove_reflect_with_registry::<TypeRegistryResource>(
446-
boxed_reflect_component_a.type_name().to_owned(),
446+
boxed_reflect_component_a.reflect_type_path().to_owned(),
447447
);
448448
system_state.apply(&mut world);
449449

crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ pub(crate) enum ReflectDerive<'a> {
3434
/// // traits
3535
/// // |----------------------------------------|
3636
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
37-
/// // type_name generics
37+
/// // type_path generics
3838
/// // |-------------------||----------|
3939
/// struct ThingThatImReflecting<T1, T2, T3> {/* ... */}
4040
/// ```
4141
pub(crate) struct ReflectMeta<'a> {
4242
/// The registered traits for this type.
4343
traits: ReflectTraits,
44-
/// The name of this type.
44+
/// The path to this type.
4545
type_path: ReflectTypePath<'a>,
4646
/// A cached instance of the path to the `bevy_reflect` crate.
4747
bevy_reflect_path: Path,
@@ -389,7 +389,7 @@ impl<'a> ReflectMeta<'a> {
389389
self.traits.from_reflect_attrs()
390390
}
391391

392-
/// The name of this struct.
392+
/// The path to this type.
393393
pub fn type_path(&self) -> &ReflectTypePath<'a> {
394394
&self.type_path
395395
}

crates/bevy_reflect/bevy_reflect_derive/src/from_reflect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
7373
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) {
7474
match #bevy_reflect_path::Enum::variant_name(#ref_value) {
7575
#(#variant_names => #fqoption::Some(#variant_constructors),)*
76-
name => panic!("variant with name `{}` does not exist on enum `{}`", name, ::core::any::type_name::<Self>()),
76+
name => panic!("variant with name `{}` does not exist on enum `{}`", name, <Self as #bevy_reflect_path::TypePath>::type_path()),
7777
}
7878
} else {
7979
#FQOption::None

crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,18 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
5858
}
5959
});
6060

61-
let string_name = enum_path.get_ident().unwrap().to_string();
62-
6361
#[cfg(feature = "documentation")]
6462
let info_generator = {
6563
let doc = reflect_enum.meta().doc();
6664
quote! {
67-
#bevy_reflect_path::EnumInfo::new::<Self>(#string_name, &variants).with_docs(#doc)
65+
#bevy_reflect_path::EnumInfo::new::<Self>(&variants).with_docs(#doc)
6866
}
6967
};
7068

7169
#[cfg(not(feature = "documentation"))]
7270
let info_generator = {
7371
quote! {
74-
#bevy_reflect_path::EnumInfo::new::<Self>(#string_name, &variants)
72+
#bevy_reflect_path::EnumInfo::new::<Self>(&variants)
7573
}
7674
};
7775

@@ -188,11 +186,6 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
188186
}
189187

190188
impl #impl_generics #bevy_reflect_path::Reflect for #enum_path #ty_generics #where_reflect_clause {
191-
#[inline]
192-
fn type_name(&self) -> &str {
193-
::core::any::type_name::<Self>()
194-
}
195-
196189
#[inline]
197190
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
198191
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
@@ -264,11 +257,11 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
264257
#(#variant_names => {
265258
*self = #variant_constructors
266259
})*
267-
name => panic!("variant with name `{}` does not exist on enum `{}`", name, ::core::any::type_name::<Self>()),
260+
name => panic!("variant with name `{}` does not exist on enum `{}`", name, <Self as #bevy_reflect_path::TypePath>::type_path()),
268261
}
269262
}
270263
} else {
271-
panic!("`{}` is not an enum", #bevy_reflect_path::Reflect::type_name(#ref_value));
264+
panic!("`{}` is not an enum", #bevy_reflect_path::DynamicTypePath::reflect_type_path(#ref_value));
272265
}
273266
}
274267

crates/bevy_reflect/bevy_reflect_derive/src/impls/structs.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,18 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
6363
}
6464
};
6565

66-
let string_name = struct_path.get_ident().unwrap().to_string();
67-
6866
#[cfg(feature = "documentation")]
6967
let info_generator = {
7068
let doc = reflect_struct.meta().doc();
7169
quote! {
72-
#bevy_reflect_path::StructInfo::new::<Self>(#string_name, &fields).with_docs(#doc)
70+
#bevy_reflect_path::StructInfo::new::<Self>(&fields).with_docs(#doc)
7371
}
7472
};
7573

7674
#[cfg(not(feature = "documentation"))]
7775
let info_generator = {
7876
quote! {
79-
#bevy_reflect_path::StructInfo::new::<Self>(#string_name, &fields)
77+
#bevy_reflect_path::StructInfo::new::<Self>(&fields)
8078
}
8179
};
8280

@@ -163,11 +161,6 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
163161
}
164162

165163
impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
166-
#[inline]
167-
fn type_name(&self) -> &str {
168-
::core::any::type_name::<Self>()
169-
}
170-
171164
#[inline]
172165
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
173166
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())

crates/bevy_reflect/bevy_reflect_derive/src/impls/tuple_structs.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,18 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
5757
}
5858
};
5959

60-
let string_name = struct_path.get_ident().unwrap().to_string();
61-
6260
#[cfg(feature = "documentation")]
6361
let info_generator = {
6462
let doc = reflect_struct.meta().doc();
6563
quote! {
66-
#bevy_reflect_path::TupleStructInfo::new::<Self>(#string_name, &fields).with_docs(#doc)
64+
#bevy_reflect_path::TupleStructInfo::new::<Self>(&fields).with_docs(#doc)
6765
}
6866
};
6967

7068
#[cfg(not(feature = "documentation"))]
7169
let info_generator = {
7270
quote! {
73-
#bevy_reflect_path::TupleStructInfo::new::<Self>(#string_name, &fields)
71+
#bevy_reflect_path::TupleStructInfo::new::<Self>(&fields)
7472
}
7573
};
7674

@@ -133,11 +131,6 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
133131
}
134132

135133
impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
136-
#[inline]
137-
fn type_name(&self) -> &str {
138-
::core::any::type_name::<Self>()
139-
}
140-
141134
#[inline]
142135
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
143136
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())

crates/bevy_reflect/bevy_reflect_derive/src/impls/values.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
4545
#typed_impl
4646

4747
impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {
48-
#[inline]
49-
fn type_name(&self) -> &str {
50-
::core::any::type_name::<Self>()
51-
}
52-
5348
#[inline]
5449
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
5550
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
@@ -96,7 +91,7 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
9691
if let #FQOption::Some(value) = <dyn #FQAny>::downcast_ref::<Self>(value) {
9792
*self = #FQClone::clone(value);
9893
} else {
99-
panic!("Value is not {}.", ::core::any::type_name::<Self>());
94+
panic!("Value is not {}.", <Self as #bevy_reflect_path::TypePath>::type_path());
10095
}
10196
}
10297

0 commit comments

Comments
 (0)