mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
reflect: TypePath
part 2 (#8768)
# Objective
- Followup to #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 #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`](3fea3c6c0b/crates/bevy_reflect/src/impls/std.rs (L90)
)
(note that `String` is in the default Rust prelude) snuck in completely
under the radar.
This commit is contained in:
parent
92294de08d
commit
262846e702
36 changed files with 816 additions and 787 deletions
|
@ -728,7 +728,7 @@ impl App {
|
|||
/// See [`bevy_reflect::TypeRegistry::register_type_data`].
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
pub fn register_type_data<
|
||||
T: bevy_reflect::Reflect + 'static,
|
||||
T: bevy_reflect::Reflect + bevy_reflect::TypePath,
|
||||
D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
|
||||
>(
|
||||
&mut self,
|
||||
|
|
|
@ -146,7 +146,8 @@ impl<B: Bundle + Reflect + FromWorld> FromType<B> for ReflectBundle {
|
|||
.for_each(|field| insert_field::<B>(entity, field, registry)),
|
||||
_ => panic!(
|
||||
"expected bundle `{}` to be named struct or tuple",
|
||||
std::any::type_name::<B>()
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
std::any::type_name::<B>(),
|
||||
),
|
||||
}
|
||||
},
|
||||
|
@ -163,7 +164,8 @@ impl<B: Bundle + Reflect + FromWorld> FromType<B> for ReflectBundle {
|
|||
.for_each(|field| apply_or_insert_field::<B>(entity, field, registry)),
|
||||
_ => panic!(
|
||||
"expected bundle `{}` to be named struct or tuple",
|
||||
std::any::type_name::<B>()
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
std::any::type_name::<B>(),
|
||||
),
|
||||
}
|
||||
},
|
||||
|
@ -188,14 +190,14 @@ fn insert_field<B: 'static>(
|
|||
if world.components().get_id(TypeId::of::<B>()).is_some() {
|
||||
panic!(
|
||||
"no `ReflectComponent` registration found for `{}`",
|
||||
field.type_name()
|
||||
field.reflect_type_path(),
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
panic!(
|
||||
"no `ReflectBundle` registration found for `{}`",
|
||||
field.type_name()
|
||||
field.reflect_type_path(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -214,14 +216,14 @@ fn apply_or_insert_field<B: 'static>(
|
|||
if world.components().get_id(TypeId::of::<B>()).is_some() {
|
||||
panic!(
|
||||
"no `ReflectComponent` registration found for `{}`",
|
||||
field.type_name()
|
||||
field.reflect_type_path(),
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
panic!(
|
||||
"no `ReflectBundle` registration found for `{}`",
|
||||
field.type_name()
|
||||
field.reflect_type_path(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,10 +161,10 @@ impl<'w, 's, 'a> ReflectCommandExt for EntityCommands<'w, 's, 'a> {
|
|||
self
|
||||
}
|
||||
|
||||
fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self {
|
||||
fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
|
||||
self.commands.add(RemoveReflect {
|
||||
entity: self.entity,
|
||||
component_type_name: component_type_name.into(),
|
||||
component_type_path: component_type_path.into(),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
@ -189,15 +189,15 @@ fn insert_reflect(
|
|||
type_registry: &TypeRegistry,
|
||||
component: Box<dyn Reflect>,
|
||||
) {
|
||||
let type_info = component.type_name();
|
||||
let type_info = component.reflect_type_path();
|
||||
let Some(mut entity) = world.get_entity_mut(entity) else {
|
||||
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());
|
||||
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());
|
||||
};
|
||||
let Some(type_registration) = type_registry.get_with_name(type_info) else {
|
||||
panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.type_name());
|
||||
let Some(type_registration) = type_registry.get_with_type_path(type_info) else {
|
||||
panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.reflect_type_path());
|
||||
};
|
||||
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
|
||||
panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", component.type_name());
|
||||
panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", component.reflect_type_path());
|
||||
};
|
||||
reflect_component.insert(&mut entity, &*component);
|
||||
}
|
||||
|
@ -246,12 +246,12 @@ fn remove_reflect(
|
|||
world: &mut World,
|
||||
entity: Entity,
|
||||
type_registry: &TypeRegistry,
|
||||
component_type_name: Cow<'static, str>,
|
||||
component_type_path: Cow<'static, str>,
|
||||
) {
|
||||
let Some(mut entity) = world.get_entity_mut(entity) else {
|
||||
return;
|
||||
};
|
||||
let Some(type_registration) = type_registry.get_with_name(&component_type_name) else {
|
||||
let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
|
||||
return;
|
||||
};
|
||||
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
|
||||
|
@ -269,7 +269,7 @@ pub struct RemoveReflect {
|
|||
pub entity: Entity,
|
||||
/// The [`Component`](crate::component::Component) type name that will be used to remove a component
|
||||
/// of the same type from the entity.
|
||||
pub component_type_name: Cow<'static, str>,
|
||||
pub component_type_path: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl Command for RemoveReflect {
|
||||
|
@ -279,7 +279,7 @@ impl Command for RemoveReflect {
|
|||
world,
|
||||
self.entity,
|
||||
®istry.read(),
|
||||
self.component_type_name,
|
||||
self.component_type_path,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -413,7 +413,7 @@ mod tests {
|
|||
|
||||
commands
|
||||
.entity(entity)
|
||||
.remove_reflect(boxed_reflect_component_a.type_name().to_owned());
|
||||
.remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
|
||||
system_state.apply(&mut world);
|
||||
|
||||
assert_eq!(world.entity(entity).get::<ComponentA>(), None);
|
||||
|
@ -443,7 +443,7 @@ mod tests {
|
|||
commands
|
||||
.entity(entity)
|
||||
.remove_reflect_with_registry::<TypeRegistryResource>(
|
||||
boxed_reflect_component_a.type_name().to_owned(),
|
||||
boxed_reflect_component_a.reflect_type_path().to_owned(),
|
||||
);
|
||||
system_state.apply(&mut world);
|
||||
|
||||
|
|
|
@ -34,14 +34,14 @@ pub(crate) enum ReflectDerive<'a> {
|
|||
/// // traits
|
||||
/// // |----------------------------------------|
|
||||
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
|
||||
/// // type_name generics
|
||||
/// // type_path generics
|
||||
/// // |-------------------||----------|
|
||||
/// struct ThingThatImReflecting<T1, T2, T3> {/* ... */}
|
||||
/// ```
|
||||
pub(crate) struct ReflectMeta<'a> {
|
||||
/// The registered traits for this type.
|
||||
traits: ReflectTraits,
|
||||
/// The name of this type.
|
||||
/// The path to this type.
|
||||
type_path: ReflectTypePath<'a>,
|
||||
/// A cached instance of the path to the `bevy_reflect` crate.
|
||||
bevy_reflect_path: Path,
|
||||
|
@ -389,7 +389,7 @@ impl<'a> ReflectMeta<'a> {
|
|||
self.traits.from_reflect_attrs()
|
||||
}
|
||||
|
||||
/// The name of this struct.
|
||||
/// The path to this type.
|
||||
pub fn type_path(&self) -> &ReflectTypePath<'a> {
|
||||
&self.type_path
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
|
|||
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) {
|
||||
match #bevy_reflect_path::Enum::variant_name(#ref_value) {
|
||||
#(#variant_names => #fqoption::Some(#variant_constructors),)*
|
||||
name => panic!("variant with name `{}` does not exist on enum `{}`", name, ::core::any::type_name::<Self>()),
|
||||
name => panic!("variant with name `{}` does not exist on enum `{}`", name, <Self as #bevy_reflect_path::TypePath>::type_path()),
|
||||
}
|
||||
} else {
|
||||
#FQOption::None
|
||||
|
|
|
@ -58,20 +58,18 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
|
|||
}
|
||||
});
|
||||
|
||||
let string_name = enum_path.get_ident().unwrap().to_string();
|
||||
|
||||
#[cfg(feature = "documentation")]
|
||||
let info_generator = {
|
||||
let doc = reflect_enum.meta().doc();
|
||||
quote! {
|
||||
#bevy_reflect_path::EnumInfo::new::<Self>(#string_name, &variants).with_docs(#doc)
|
||||
#bevy_reflect_path::EnumInfo::new::<Self>(&variants).with_docs(#doc)
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "documentation"))]
|
||||
let info_generator = {
|
||||
quote! {
|
||||
#bevy_reflect_path::EnumInfo::new::<Self>(#string_name, &variants)
|
||||
#bevy_reflect_path::EnumInfo::new::<Self>(&variants)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -188,11 +186,6 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
|
|||
}
|
||||
|
||||
impl #impl_generics #bevy_reflect_path::Reflect for #enum_path #ty_generics #where_reflect_clause {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
::core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
|
||||
#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
|
|||
#(#variant_names => {
|
||||
*self = #variant_constructors
|
||||
})*
|
||||
name => panic!("variant with name `{}` does not exist on enum `{}`", name, ::core::any::type_name::<Self>()),
|
||||
name => panic!("variant with name `{}` does not exist on enum `{}`", name, <Self as #bevy_reflect_path::TypePath>::type_path()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("`{}` is not an enum", #bevy_reflect_path::Reflect::type_name(#ref_value));
|
||||
panic!("`{}` is not an enum", #bevy_reflect_path::DynamicTypePath::reflect_type_path(#ref_value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,20 +63,18 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
|
|||
}
|
||||
};
|
||||
|
||||
let string_name = struct_path.get_ident().unwrap().to_string();
|
||||
|
||||
#[cfg(feature = "documentation")]
|
||||
let info_generator = {
|
||||
let doc = reflect_struct.meta().doc();
|
||||
quote! {
|
||||
#bevy_reflect_path::StructInfo::new::<Self>(#string_name, &fields).with_docs(#doc)
|
||||
#bevy_reflect_path::StructInfo::new::<Self>(&fields).with_docs(#doc)
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "documentation"))]
|
||||
let info_generator = {
|
||||
quote! {
|
||||
#bevy_reflect_path::StructInfo::new::<Self>(#string_name, &fields)
|
||||
#bevy_reflect_path::StructInfo::new::<Self>(&fields)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -163,11 +161,6 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
|
|||
}
|
||||
|
||||
impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
::core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
|
||||
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
|
||||
|
|
|
@ -57,20 +57,18 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
|
|||
}
|
||||
};
|
||||
|
||||
let string_name = struct_path.get_ident().unwrap().to_string();
|
||||
|
||||
#[cfg(feature = "documentation")]
|
||||
let info_generator = {
|
||||
let doc = reflect_struct.meta().doc();
|
||||
quote! {
|
||||
#bevy_reflect_path::TupleStructInfo::new::<Self>(#string_name, &fields).with_docs(#doc)
|
||||
#bevy_reflect_path::TupleStructInfo::new::<Self>(&fields).with_docs(#doc)
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "documentation"))]
|
||||
let info_generator = {
|
||||
quote! {
|
||||
#bevy_reflect_path::TupleStructInfo::new::<Self>(#string_name, &fields)
|
||||
#bevy_reflect_path::TupleStructInfo::new::<Self>(&fields)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -133,11 +131,6 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
|
|||
}
|
||||
|
||||
impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
::core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
|
||||
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
|
||||
|
|
|
@ -45,11 +45,6 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
|
|||
#typed_impl
|
||||
|
||||
impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
::core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
|
||||
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
|
||||
|
@ -96,7 +91,7 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
|
|||
if let #FQOption::Some(value) = <dyn #FQAny>::downcast_ref::<Self>(value) {
|
||||
*self = #FQClone::clone(value);
|
||||
} else {
|
||||
panic!("Value is not {}.", ::core::any::type_name::<Self>());
|
||||
panic!("Value is not {}.", <Self as #bevy_reflect_path::TypePath>::type_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
self as bevy_reflect, utility::reflect_hasher, Reflect, ReflectMut, ReflectOwned, ReflectRef,
|
||||
TypeInfo,
|
||||
TypeInfo, TypePath, TypePathTable,
|
||||
};
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
use std::{
|
||||
|
@ -77,9 +77,9 @@ pub trait Array: Reflect {
|
|||
/// A container for compile-time array info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArrayInfo {
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
item_type_name: &'static str,
|
||||
item_type_path: TypePathTable,
|
||||
item_type_id: TypeId,
|
||||
capacity: usize,
|
||||
#[cfg(feature = "documentation")]
|
||||
|
@ -93,11 +93,11 @@ impl ArrayInfo {
|
|||
///
|
||||
/// * `capacity`: The maximum capacity of the underlying array.
|
||||
///
|
||||
pub fn new<TArray: Array, TItem: Reflect>(capacity: usize) -> Self {
|
||||
pub fn new<TArray: Array + TypePath, TItem: Reflect + TypePath>(capacity: usize) -> Self {
|
||||
Self {
|
||||
type_name: std::any::type_name::<TArray>(),
|
||||
type_path: TypePathTable::of::<TArray>(),
|
||||
type_id: TypeId::of::<TArray>(),
|
||||
item_type_name: std::any::type_name::<TItem>(),
|
||||
item_type_path: TypePathTable::of::<TItem>(),
|
||||
item_type_id: TypeId::of::<TItem>(),
|
||||
capacity,
|
||||
#[cfg(feature = "documentation")]
|
||||
|
@ -116,11 +116,21 @@ impl ArrayInfo {
|
|||
self.capacity
|
||||
}
|
||||
|
||||
/// The [type name] of the array.
|
||||
/// A representation of the type path of the array.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the array.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the array.
|
||||
|
@ -133,11 +143,11 @@ impl ArrayInfo {
|
|||
TypeId::of::<T>() == self.type_id
|
||||
}
|
||||
|
||||
/// The [type name] of the array item.
|
||||
/// A representation of the type path of the array item.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn item_type_name(&self) -> &'static str {
|
||||
self.item_type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn item_type_path_table(&self) -> &TypePathTable {
|
||||
&self.item_type_path
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the array item.
|
||||
|
@ -213,13 +223,6 @@ impl DynamicArray {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicArray {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_else(|| std::any::type_name::<Self>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
|
|
@ -288,13 +288,6 @@ impl Enum for DynamicEnum {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicEnum {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
@ -376,7 +369,7 @@ impl Reflect for DynamicEnum {
|
|||
self.set_variant(value.variant_name(), dyn_variant);
|
||||
}
|
||||
} else {
|
||||
panic!("`{}` is not an enum", value.type_name());
|
||||
panic!("`{}` is not an enum", value.reflect_type_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{DynamicEnum, Reflect, VariantInfo, VariantType};
|
||||
use crate::{DynamicEnum, Reflect, TypePath, TypePathTable, VariantInfo, VariantType};
|
||||
use bevy_utils::HashMap;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::slice::Iter;
|
||||
|
@ -126,15 +126,14 @@ pub trait Enum: Reflect {
|
|||
}
|
||||
/// Returns the full path to the current variant.
|
||||
fn variant_path(&self) -> String {
|
||||
format!("{}::{}", self.type_name(), self.variant_name())
|
||||
format!("{}::{}", self.reflect_type_path(), self.variant_name())
|
||||
}
|
||||
}
|
||||
|
||||
/// A container for compile-time enum info, used by [`TypeInfo`](crate::TypeInfo).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EnumInfo {
|
||||
name: &'static str,
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
variants: Box<[VariantInfo]>,
|
||||
variant_names: Box<[&'static str]>,
|
||||
|
@ -148,10 +147,9 @@ impl EnumInfo {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name`: The name of this enum (_without_ generics or lifetimes)
|
||||
/// * `variants`: The variants of this enum in the order they are defined
|
||||
///
|
||||
pub fn new<TEnum: Enum>(name: &'static str, variants: &[VariantInfo]) -> Self {
|
||||
pub fn new<TEnum: Enum + TypePath>(variants: &[VariantInfo]) -> Self {
|
||||
let variant_indices = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
@ -161,8 +159,7 @@ impl EnumInfo {
|
|||
let variant_names = variants.iter().map(|variant| variant.name()).collect();
|
||||
|
||||
Self {
|
||||
name,
|
||||
type_name: std::any::type_name::<TEnum>(),
|
||||
type_path: TypePathTable::of::<TEnum>(),
|
||||
type_id: TypeId::of::<TEnum>(),
|
||||
variants: variants.to_vec().into_boxed_slice(),
|
||||
variant_names,
|
||||
|
@ -204,7 +201,7 @@ impl EnumInfo {
|
|||
///
|
||||
/// This does _not_ check if the given variant exists.
|
||||
pub fn variant_path(&self, name: &str) -> String {
|
||||
format!("{}::{name}", self.type_name())
|
||||
format!("{}::{name}", self.type_path())
|
||||
}
|
||||
|
||||
/// Checks if a variant with the given name exists within this enum.
|
||||
|
@ -222,20 +219,21 @@ impl EnumInfo {
|
|||
self.variants.len()
|
||||
}
|
||||
|
||||
/// The name of the enum.
|
||||
/// A representation of the type path of the value.
|
||||
///
|
||||
/// This does _not_ include any generics or lifetimes.
|
||||
///
|
||||
/// For example, `foo::bar::Baz<'a, T>` would simply be `Baz`.
|
||||
pub fn name(&self) -> &'static str {
|
||||
self.name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [type name] of the enum.
|
||||
/// The [stable, full type path] of the value.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the enum.
|
||||
|
|
|
@ -25,7 +25,15 @@ mod tests {
|
|||
let info = MyEnum::type_info();
|
||||
if let TypeInfo::Enum(info) = info {
|
||||
assert!(info.is::<MyEnum>(), "expected type to be `MyEnum`");
|
||||
assert_eq!(std::any::type_name::<MyEnum>(), info.type_name());
|
||||
assert_eq!(MyEnum::type_path(), info.type_path());
|
||||
assert_eq!(MyEnum::type_path(), info.type_path_table().path());
|
||||
assert_eq!(MyEnum::type_ident(), info.type_path_table().ident());
|
||||
assert_eq!(MyEnum::module_path(), info.type_path_table().module_path());
|
||||
assert_eq!(MyEnum::crate_name(), info.type_path_table().crate_name());
|
||||
assert_eq!(
|
||||
MyEnum::short_type_path(),
|
||||
info.type_path_table().short_path()
|
||||
);
|
||||
|
||||
// === MyEnum::A === //
|
||||
assert_eq!("A", info.variant_at(0).unwrap().name());
|
||||
|
@ -275,7 +283,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "`((usize, i32))` is not an enum")]
|
||||
#[should_panic(expected = "`bevy_reflect::DynamicTuple` is not an enum")]
|
||||
fn applying_non_enum_should_panic() {
|
||||
let mut value = MyEnum::B(0, 0);
|
||||
let mut dyn_tuple = DynamicTuple::default();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Reflect;
|
||||
use crate::{Reflect, TypePath, TypePathTable};
|
||||
use std::any::{Any, TypeId};
|
||||
|
||||
/// The named field of a reflected struct.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NamedField {
|
||||
name: &'static str,
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: Option<&'static str>,
|
||||
|
@ -13,10 +13,10 @@ pub struct NamedField {
|
|||
|
||||
impl NamedField {
|
||||
/// Create a new [`NamedField`].
|
||||
pub fn new<T: Reflect>(name: &'static str) -> Self {
|
||||
pub fn new<T: Reflect + TypePath>(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
type_name: std::any::type_name::<T>(),
|
||||
type_path: TypePathTable::of::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: None,
|
||||
|
@ -34,11 +34,21 @@ impl NamedField {
|
|||
self.name
|
||||
}
|
||||
|
||||
/// The [type name] of the field.
|
||||
/// A representation of the type path of the field.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the field.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the field.
|
||||
|
@ -62,17 +72,17 @@ impl NamedField {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct UnnamedField {
|
||||
index: usize,
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl UnnamedField {
|
||||
pub fn new<T: Reflect>(index: usize) -> Self {
|
||||
pub fn new<T: Reflect + TypePath>(index: usize) -> Self {
|
||||
Self {
|
||||
index,
|
||||
type_name: std::any::type_name::<T>(),
|
||||
type_path: TypePathTable::of::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: None,
|
||||
|
@ -90,11 +100,21 @@ impl UnnamedField {
|
|||
self.index
|
||||
}
|
||||
|
||||
/// The [type name] of the field.
|
||||
/// A representation of the type path of the field.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the field.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the field.
|
||||
|
|
|
@ -75,7 +75,7 @@ pub trait FromReflect: Reflect + Sized {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_reflect::{DynamicTupleStruct, Reflect, ReflectFromReflect, Typed, TypeRegistry};
|
||||
/// # use bevy_reflect::{DynamicTupleStruct, Reflect, ReflectFromReflect, Typed, TypeRegistry, TypePath};
|
||||
/// # #[derive(Reflect, PartialEq, Eq, Debug)]
|
||||
/// # struct Foo(#[reflect(default = "default_value")] usize);
|
||||
/// # fn default_value() -> usize { 123 }
|
||||
|
@ -85,7 +85,7 @@ pub trait FromReflect: Reflect + Sized {
|
|||
/// let mut reflected = DynamicTupleStruct::default();
|
||||
/// reflected.set_represented_type(Some(<Foo as Typed>::type_info()));
|
||||
///
|
||||
/// let registration = registry.get_with_name(reflected.type_name()).unwrap();
|
||||
/// let registration = registry.get_with_type_path(<Foo as TypePath>::type_path()).unwrap();
|
||||
/// let rfr = registration.data::<ReflectFromReflect>().unwrap();
|
||||
///
|
||||
/// let concrete: Box<dyn Reflect> = rfr.from_reflect(&reflected).unwrap();
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
|
||||
impl<T: smallvec::Array + TypePath + Send + Sync> List for SmallVec<T>
|
||||
where
|
||||
T::Item: FromReflect,
|
||||
T::Item: FromReflect + TypePath,
|
||||
{
|
||||
fn get(&self, index: usize) -> Option<&dyn Reflect> {
|
||||
if index < SmallVec::len(self) {
|
||||
|
@ -34,7 +34,7 @@ where
|
|||
<T as smallvec::Array>::Item::from_reflect(&*value).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Attempted to insert invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
})
|
||||
});
|
||||
|
@ -50,7 +50,7 @@ where
|
|||
<T as smallvec::Array>::Item::from_reflect(&*value).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Attempted to push invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
})
|
||||
});
|
||||
|
@ -78,12 +78,8 @@ where
|
|||
|
||||
impl<T: smallvec::Array + TypePath + Send + Sync> Reflect for SmallVec<T>
|
||||
where
|
||||
T::Item: FromReflect,
|
||||
T::Item: FromReflect + TypePath,
|
||||
{
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -144,7 +140,7 @@ where
|
|||
|
||||
impl<T: smallvec::Array + TypePath + Send + Sync + 'static> Typed for SmallVec<T>
|
||||
where
|
||||
T::Item: FromReflect,
|
||||
T::Item: FromReflect + TypePath,
|
||||
{
|
||||
fn type_info() -> &'static TypeInfo {
|
||||
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
|
@ -152,11 +148,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl_type_path!(::smallvec::SmallVec<T: smallvec::Array + TypePath + Send + Sync>);
|
||||
impl_type_path!(::smallvec::SmallVec<T: smallvec::Array>);
|
||||
|
||||
impl<T: smallvec::Array + TypePath + Send + Sync> FromReflect for SmallVec<T>
|
||||
where
|
||||
T::Item: FromReflect,
|
||||
T::Item: FromReflect + TypePath,
|
||||
{
|
||||
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
|
||||
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
|
||||
|
@ -173,7 +169,7 @@ where
|
|||
|
||||
impl<T: smallvec::Array + TypePath + Send + Sync> GetTypeRegistration for SmallVec<T>
|
||||
where
|
||||
T::Item: FromReflect,
|
||||
T::Item: FromReflect + TypePath,
|
||||
{
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
let mut registration = TypeRegistration::of::<SmallVec<T>>();
|
||||
|
|
|
@ -79,7 +79,8 @@ impl_reflect_value!(isize(
|
|||
));
|
||||
impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||
impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||
impl_reflect_value!(String(
|
||||
impl_type_path!(str);
|
||||
impl_reflect_value!(::alloc::string::String(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
|
@ -232,7 +233,7 @@ macro_rules! impl_reflect_for_veclike {
|
|||
T::from_reflect(&*value).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Attempted to insert invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
})
|
||||
});
|
||||
|
@ -247,7 +248,7 @@ macro_rules! impl_reflect_for_veclike {
|
|||
let value = T::take_from_reflect(value).unwrap_or_else(|value| {
|
||||
panic!(
|
||||
"Attempted to push invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
});
|
||||
$push(self, value);
|
||||
|
@ -276,10 +277,6 @@ macro_rules! impl_reflect_for_veclike {
|
|||
}
|
||||
|
||||
impl<T: FromReflect + TypePath> Reflect for $ty {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -349,7 +346,7 @@ macro_rules! impl_reflect_for_veclike {
|
|||
}
|
||||
}
|
||||
|
||||
impl_type_path!($ty where T: FromReflect);
|
||||
impl_type_path!($ty);
|
||||
|
||||
impl<T: FromReflect + TypePath> GetTypeRegistration for $ty {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
|
@ -448,7 +445,10 @@ macro_rules! impl_reflect_for_hashmap {
|
|||
dynamic_map.set_represented_type(self.get_represented_type_info());
|
||||
for (k, v) in self {
|
||||
let key = K::from_reflect(k).unwrap_or_else(|| {
|
||||
panic!("Attempted to clone invalid key of type {}.", k.type_name())
|
||||
panic!(
|
||||
"Attempted to clone invalid key of type {}.",
|
||||
k.reflect_type_path()
|
||||
)
|
||||
});
|
||||
dynamic_map.insert_boxed(Box::new(key), v.clone_value());
|
||||
}
|
||||
|
@ -463,13 +463,13 @@ macro_rules! impl_reflect_for_hashmap {
|
|||
let key = K::take_from_reflect(key).unwrap_or_else(|key| {
|
||||
panic!(
|
||||
"Attempted to insert invalid key of type {}.",
|
||||
key.type_name()
|
||||
key.reflect_type_path()
|
||||
)
|
||||
});
|
||||
let value = V::take_from_reflect(value).unwrap_or_else(|value| {
|
||||
panic!(
|
||||
"Attempted to insert invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
});
|
||||
self.insert(key, value)
|
||||
|
@ -494,10 +494,6 @@ macro_rules! impl_reflect_for_hashmap {
|
|||
V: FromReflect + TypePath,
|
||||
S: TypePath + BuildHasher + Send + Sync,
|
||||
{
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -607,23 +603,11 @@ macro_rules! impl_reflect_for_hashmap {
|
|||
|
||||
impl_reflect_for_hashmap!(::std::collections::HashMap<K, V, S>);
|
||||
impl_type_path!(::std::collections::hash_map::RandomState);
|
||||
impl_type_path!(
|
||||
::std::collections::HashMap<K, V, S>
|
||||
where
|
||||
K: FromReflect + Eq + Hash + ?Sized,
|
||||
V: FromReflect + ?Sized,
|
||||
S: BuildHasher + Send + Sync + 'static,
|
||||
);
|
||||
impl_type_path!(::std::collections::HashMap<K, V, S>);
|
||||
|
||||
impl_reflect_for_hashmap!(bevy_utils::hashbrown::HashMap<K, V, S>);
|
||||
impl_type_path!(::bevy_utils::hashbrown::hash_map::DefaultHashBuilder);
|
||||
impl_type_path!(
|
||||
::bevy_utils::hashbrown::HashMap<K, V, S>
|
||||
where
|
||||
K: FromReflect + Eq + Hash + ?Sized,
|
||||
V: FromReflect + ?Sized,
|
||||
S: BuildHasher + Send + Sync + 'static,
|
||||
);
|
||||
impl_type_path!(::bevy_utils::hashbrown::HashMap<K, V, S>);
|
||||
|
||||
impl<T: Reflect + TypePath, const N: usize> Array for [T; N] {
|
||||
#[inline]
|
||||
|
@ -655,11 +639,6 @@ impl<T: Reflect + TypePath, const N: usize> Array for [T; N] {
|
|||
}
|
||||
|
||||
impl<T: Reflect + TypePath, const N: usize> Reflect for [T; N] {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -757,7 +736,7 @@ impl<T: Reflect + TypePath, const N: usize> Typed for [T; N] {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Reflect + TypePath, const N: usize> TypePath for [T; N] {
|
||||
impl<T: TypePath, const N: usize> TypePath for [T; N] {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| format!("[{t}; {N}]", t = T::type_path()))
|
||||
|
@ -871,11 +850,6 @@ impl<T: FromReflect + TypePath> Enum for Option<T> {
|
|||
}
|
||||
|
||||
impl<T: FromReflect + TypePath> Reflect for Option<T> {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
|
@ -929,7 +903,7 @@ impl<T: FromReflect + TypePath> Reflect for Option<T> {
|
|||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Field in `Some` variant of {} should exist",
|
||||
std::any::type_name::<Option<T>>()
|
||||
Self::type_path()
|
||||
)
|
||||
})
|
||||
.clone_value(),
|
||||
|
@ -937,8 +911,8 @@ impl<T: FromReflect + TypePath> Reflect for Option<T> {
|
|||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Field in `Some` variant of {} should be of type {}",
|
||||
std::any::type_name::<Option<T>>(),
|
||||
std::any::type_name::<T>()
|
||||
Self::type_path(),
|
||||
T::type_path()
|
||||
)
|
||||
});
|
||||
*self = Some(field);
|
||||
|
@ -946,7 +920,7 @@ impl<T: FromReflect + TypePath> Reflect for Option<T> {
|
|||
"None" => {
|
||||
*self = None;
|
||||
}
|
||||
_ => panic!("Enum is not a {}.", std::any::type_name::<Self>()),
|
||||
_ => panic!("Enum is not a {}.", Self::type_path()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -995,7 +969,7 @@ impl<T: FromReflect + TypePath> FromReflect for Option<T> {
|
|||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Field in `Some` variant of {} should exist",
|
||||
std::any::type_name::<Option<T>>()
|
||||
Option::<T>::type_path()
|
||||
)
|
||||
})
|
||||
.clone_value(),
|
||||
|
@ -1003,8 +977,8 @@ impl<T: FromReflect + TypePath> FromReflect for Option<T> {
|
|||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Field in `Some` variant of {} should be of type {}",
|
||||
std::any::type_name::<Option<T>>(),
|
||||
std::any::type_name::<T>()
|
||||
Option::<T>::type_path(),
|
||||
T::type_path()
|
||||
)
|
||||
});
|
||||
Some(Some(field))
|
||||
|
@ -1013,7 +987,7 @@ impl<T: FromReflect + TypePath> FromReflect for Option<T> {
|
|||
name => panic!(
|
||||
"variant with name `{}` does not exist on enum `{}`",
|
||||
name,
|
||||
std::any::type_name::<Self>()
|
||||
Self::type_path()
|
||||
),
|
||||
}
|
||||
} else {
|
||||
|
@ -1029,21 +1003,38 @@ impl<T: FromReflect + TypePath> Typed for Option<T> {
|
|||
let none_variant = VariantInfo::Unit(UnitVariantInfo::new("None"));
|
||||
let some_variant =
|
||||
VariantInfo::Tuple(TupleVariantInfo::new("Some", &[UnnamedField::new::<T>(0)]));
|
||||
TypeInfo::Enum(EnumInfo::new::<Self>(
|
||||
"Option",
|
||||
&[none_variant, some_variant],
|
||||
))
|
||||
TypeInfo::Enum(EnumInfo::new::<Self>(&[none_variant, some_variant]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!(::core::option::Option<T: FromReflect + TypePath>);
|
||||
impl_type_path!(::core::option::Option<T>);
|
||||
|
||||
impl Reflect for Cow<'static, str> {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
impl<T: TypePath + ?Sized> TypePath for &'static T {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| format!("&{}", T::type_path()))
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| format!("&{}", T::short_type_path()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TypePath + ?Sized> TypePath for &'static mut T {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| format!("&mut {}", T::type_path()))
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| format!("&mut {}", T::short_type_path()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Reflect for Cow<'static, str> {
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -1077,7 +1068,7 @@ impl Reflect for Cow<'static, str> {
|
|||
if let Some(value) = value.downcast_ref::<Self>() {
|
||||
*self = value.clone();
|
||||
} else {
|
||||
panic!("Value is not a {}.", std::any::type_name::<Self>());
|
||||
panic!("Value is not a {}.", Self::type_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1126,30 +1117,6 @@ impl Typed for Cow<'static, str> {
|
|||
}
|
||||
}
|
||||
|
||||
impl TypePath for Cow<'static, str> {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| "std::borrow::Cow::<str>".to_owned())
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| "Cow<str>".to_owned())
|
||||
}
|
||||
|
||||
fn type_ident() -> Option<&'static str> {
|
||||
Some("Cow")
|
||||
}
|
||||
|
||||
fn crate_name() -> Option<&'static str> {
|
||||
Some("std")
|
||||
}
|
||||
|
||||
fn module_path() -> Option<&'static str> {
|
||||
Some("std::borrow")
|
||||
}
|
||||
}
|
||||
|
||||
impl GetTypeRegistration for Cow<'static, str> {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
let mut registration = TypeRegistration::of::<Cow<'static, str>>();
|
||||
|
@ -1171,8 +1138,6 @@ impl FromReflect for Cow<'static, str> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: PathOnly> PathOnly for [T] where [T]: ToOwned {}
|
||||
|
||||
impl<T: TypePath> TypePath for [T]
|
||||
where
|
||||
[T]: ToOwned,
|
||||
|
@ -1188,8 +1153,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ToOwned> PathOnly for T {}
|
||||
|
||||
impl<T: FromReflect + Clone + TypePath> List for Cow<'static, [T]> {
|
||||
fn get(&self, index: usize) -> Option<&dyn Reflect> {
|
||||
self.as_ref().get(index).map(|x| x as &dyn Reflect)
|
||||
|
@ -1221,7 +1184,7 @@ impl<T: FromReflect + Clone + TypePath> List for Cow<'static, [T]> {
|
|||
T::from_reflect(&*value).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Attempted to insert invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
})
|
||||
});
|
||||
|
@ -1236,7 +1199,7 @@ impl<T: FromReflect + Clone + TypePath> List for Cow<'static, [T]> {
|
|||
let value = T::take_from_reflect(value).unwrap_or_else(|value| {
|
||||
panic!(
|
||||
"Attempted to push invalid value of type {}.",
|
||||
value.type_name()
|
||||
value.reflect_type_path()
|
||||
)
|
||||
});
|
||||
self.to_mut().push(value);
|
||||
|
@ -1250,10 +1213,6 @@ impl<T: FromReflect + Clone + TypePath> List for Cow<'static, [T]> {
|
|||
}
|
||||
|
||||
impl<T: FromReflect + Clone + TypePath> Reflect for Cow<'static, [T]> {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
|
@ -1344,10 +1303,6 @@ impl<T: FromReflect + Clone + TypePath> FromReflect for Cow<'static, [T]> {
|
|||
}
|
||||
|
||||
impl Reflect for &'static Path {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -1381,7 +1336,7 @@ impl Reflect for &'static Path {
|
|||
if let Some(&value) = value.downcast_ref::<Self>() {
|
||||
*self = value;
|
||||
} else {
|
||||
panic!("Value is not a {}.", std::any::type_name::<Self>());
|
||||
panic!("Value is not a {}.", Self::type_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1430,18 +1385,6 @@ impl Typed for &'static Path {
|
|||
}
|
||||
}
|
||||
|
||||
impl TypePath for &'static Path {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| "&std::path::Path".to_owned())
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| "&Path".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl GetTypeRegistration for &'static Path {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
let mut registration = TypeRegistration::of::<Self>();
|
||||
|
@ -1457,10 +1400,6 @@ impl FromReflect for &'static Path {
|
|||
}
|
||||
|
||||
impl Reflect for Cow<'static, Path> {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -1494,7 +1433,7 @@ impl Reflect for Cow<'static, Path> {
|
|||
if let Some(value) = value.downcast_ref::<Self>() {
|
||||
*self = value.clone();
|
||||
} else {
|
||||
panic!("Value is not a {}.", std::any::type_name::<Self>());
|
||||
panic!("Value is not a {}.", Self::type_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1547,10 +1486,8 @@ impl Typed for Cow<'static, Path> {
|
|||
}
|
||||
}
|
||||
|
||||
trait PathOnly: ToOwned {}
|
||||
impl PathOnly for Path {}
|
||||
impl_type_path!(::alloc::borrow::Cow<'a: 'static, T: PathOnly + ?Sized>);
|
||||
impl_type_path!(::std::path::Path);
|
||||
impl_type_path!(::alloc::borrow::Cow<'a: 'static, T: ToOwned + ?Sized>);
|
||||
|
||||
impl FromReflect for Cow<'static, Path> {
|
||||
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
|
||||
|
|
|
@ -335,7 +335,7 @@
|
|||
//! The general entry point are the "untyped" versions of these structs.
|
||||
//! These will automatically extract the type information and pass them into their respective "typed" version.
|
||||
//!
|
||||
//! The output of the `ReflectSerializer` will be a map, where the key is the [type name]
|
||||
//! The output of the `ReflectSerializer` will be a map, where the key is the [type path]
|
||||
//! and the value is the serialized data.
|
||||
//! The `TypedReflectSerializer` will simply output the serialized data.
|
||||
//!
|
||||
|
@ -456,7 +456,7 @@
|
|||
//! [`TypedReflectDeserializer`]: serde::TypedReflectDeserializer
|
||||
//! [registry]: TypeRegistry
|
||||
//! [type information]: TypeInfo
|
||||
//! [type name]: Reflect::type_name
|
||||
//! [type path]: TypePath
|
||||
//! [type registry]: TypeRegistry
|
||||
//! [`bevy_math`]: https://docs.rs/bevy_math/latest/bevy_math/
|
||||
//! [`glam`]: https://docs.rs/glam/latest/glam/
|
||||
|
@ -1131,28 +1131,28 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn dynamic_names() {
|
||||
fn not_dynamic_names() {
|
||||
let list = Vec::<usize>::new();
|
||||
let dyn_list = list.clone_dynamic();
|
||||
assert_eq!(dyn_list.type_name(), std::any::type_name::<Vec<usize>>());
|
||||
assert_ne!(dyn_list.reflect_type_path(), Vec::<usize>::type_path());
|
||||
|
||||
let array = [b'0'; 4];
|
||||
let dyn_array = array.clone_dynamic();
|
||||
assert_eq!(dyn_array.type_name(), std::any::type_name::<[u8; 4]>());
|
||||
assert_ne!(dyn_array.reflect_type_path(), <[u8; 4]>::type_path());
|
||||
|
||||
let map = HashMap::<usize, String>::default();
|
||||
let dyn_map = map.clone_dynamic();
|
||||
assert_eq!(
|
||||
dyn_map.type_name(),
|
||||
std::any::type_name::<HashMap<usize, String>>()
|
||||
assert_ne!(
|
||||
dyn_map.reflect_type_path(),
|
||||
HashMap::<usize, String>::type_path()
|
||||
);
|
||||
|
||||
let tuple = (0usize, "1".to_string(), 2.0f32);
|
||||
let mut dyn_tuple = tuple.clone_dynamic();
|
||||
dyn_tuple.insert::<usize>(3);
|
||||
assert_eq!(
|
||||
dyn_tuple.type_name(),
|
||||
std::any::type_name::<(usize, String, f32, usize)>()
|
||||
assert_ne!(
|
||||
dyn_tuple.reflect_type_path(),
|
||||
<(usize, String, f32, usize)>::type_path()
|
||||
);
|
||||
|
||||
#[derive(Reflect)]
|
||||
|
@ -1161,18 +1161,27 @@ mod tests {
|
|||
}
|
||||
let struct_ = TestStruct { a: 0 };
|
||||
let dyn_struct = struct_.clone_dynamic();
|
||||
assert_eq!(dyn_struct.type_name(), std::any::type_name::<TestStruct>());
|
||||
assert_ne!(dyn_struct.reflect_type_path(), TestStruct::type_path());
|
||||
|
||||
#[derive(Reflect)]
|
||||
struct TestTupleStruct(usize);
|
||||
let tuple_struct = TestTupleStruct(0);
|
||||
let dyn_tuple_struct = tuple_struct.clone_dynamic();
|
||||
assert_eq!(
|
||||
dyn_tuple_struct.type_name(),
|
||||
std::any::type_name::<TestTupleStruct>()
|
||||
assert_ne!(
|
||||
dyn_tuple_struct.reflect_type_path(),
|
||||
TestTupleStruct::type_path()
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! assert_type_paths {
|
||||
($($ty:ty => $long:literal, $short:literal,)*) => {
|
||||
$(
|
||||
assert_eq!(<$ty as TypePath>::type_path(), $long);
|
||||
assert_eq!(<$ty as TypePath>::short_type_path(), $short);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reflect_type_path() {
|
||||
#[derive(TypePath)]
|
||||
|
@ -1214,62 +1223,57 @@ mod tests {
|
|||
struct MacroNameG<T>(PhantomData<T>);
|
||||
impl_type_path!((in my_alias as MyMacroNameG) MacroNameG<T>);
|
||||
|
||||
assert_eq!(Derive::type_path(), "bevy_reflect::tests::Derive");
|
||||
assert_eq!(DerivePath::type_path(), "my_alias::DerivePath");
|
||||
assert_eq!(DerivePathName::type_path(), "my_alias::MyDerivePathName");
|
||||
assert_type_paths! {
|
||||
Derive => "bevy_reflect::tests::Derive", "Derive",
|
||||
DerivePath => "my_alias::DerivePath", "DerivePath",
|
||||
DerivePathName => "my_alias::MyDerivePathName", "MyDerivePathName",
|
||||
DeriveG<Param> => "bevy_reflect::tests::DeriveG<bevy_reflect::tests::Param>", "DeriveG<Param>",
|
||||
DerivePathG<Param, 10> => "my_alias::DerivePathG<bevy_reflect::tests::Param, 10>", "DerivePathG<Param, 10>",
|
||||
DerivePathNameG<Param> => "my_alias::MyDerivePathNameG<bevy_reflect::tests::Param>", "MyDerivePathNameG<Param>",
|
||||
Macro => "my_alias::Macro", "Macro",
|
||||
MacroName => "my_alias::MyMacroName", "MyMacroName",
|
||||
MacroG<Param, 10> => "my_alias::MacroG<bevy_reflect::tests::Param, 10>", "MacroG<Param, 10>",
|
||||
MacroNameG<Param> => "my_alias::MyMacroNameG<bevy_reflect::tests::Param>", "MyMacroNameG<Param>",
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
DeriveG::<Param>::type_path(),
|
||||
"bevy_reflect::tests::DeriveG<bevy_reflect::tests::Param>"
|
||||
);
|
||||
assert_eq!(
|
||||
DerivePathG::<Param, 10>::type_path(),
|
||||
"my_alias::DerivePathG<bevy_reflect::tests::Param, 10>"
|
||||
);
|
||||
assert_eq!(
|
||||
DerivePathNameG::<Param>::type_path(),
|
||||
"my_alias::MyDerivePathNameG<bevy_reflect::tests::Param>"
|
||||
);
|
||||
#[test]
|
||||
fn std_type_paths() {
|
||||
#[derive(Clone)]
|
||||
struct Type;
|
||||
|
||||
assert_eq!(Macro::type_path(), "my_alias::Macro");
|
||||
assert_eq!(MacroName::type_path(), "my_alias::MyMacroName");
|
||||
assert_eq!(
|
||||
MacroG::<Param, 10>::type_path(),
|
||||
"my_alias::MacroG<bevy_reflect::tests::Param, 10>"
|
||||
);
|
||||
assert_eq!(
|
||||
MacroNameG::<Param>::type_path(),
|
||||
"my_alias::MyMacroNameG<bevy_reflect::tests::Param>"
|
||||
);
|
||||
impl TypePath for Type {
|
||||
fn type_path() -> &'static str {
|
||||
// for brevity in tests
|
||||
"Long"
|
||||
}
|
||||
|
||||
assert_eq!(Derive::short_type_path(), "Derive");
|
||||
assert_eq!(DerivePath::short_type_path(), "DerivePath");
|
||||
assert_eq!(DerivePathName::short_type_path(), "MyDerivePathName");
|
||||
fn short_type_path() -> &'static str {
|
||||
"Short"
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(DeriveG::<Param>::short_type_path(), "DeriveG<Param>");
|
||||
assert_eq!(
|
||||
DerivePathG::<Param, 10>::short_type_path(),
|
||||
"DerivePathG<Param, 10>"
|
||||
);
|
||||
assert_eq!(
|
||||
DerivePathNameG::<Param>::short_type_path(),
|
||||
"MyDerivePathNameG<Param>"
|
||||
);
|
||||
|
||||
assert_eq!(Macro::short_type_path(), "Macro");
|
||||
assert_eq!(MacroName::short_type_path(), "MyMacroName");
|
||||
assert_eq!(MacroG::<Param, 10>::short_type_path(), "MacroG<Param, 10>");
|
||||
assert_eq!(
|
||||
MacroNameG::<Param>::short_type_path(),
|
||||
"MyMacroNameG<Param>"
|
||||
);
|
||||
assert_type_paths! {
|
||||
u8 => "u8", "u8",
|
||||
Type => "Long", "Short",
|
||||
&Type => "&Long", "&Short",
|
||||
[Type] => "[Long]", "[Short]",
|
||||
&[Type] => "&[Long]", "&[Short]",
|
||||
[Type; 0] => "[Long; 0]", "[Short; 0]",
|
||||
[Type; 100] => "[Long; 100]", "[Short; 100]",
|
||||
() => "()", "()",
|
||||
(Type,) => "(Long,)", "(Short,)",
|
||||
(Type, Type) => "(Long, Long)", "(Short, Short)",
|
||||
(Type, Type, Type) => "(Long, Long, Long)", "(Short, Short, Short)",
|
||||
Cow<'static, Type> => "alloc::borrow::Cow<Long>", "Cow<Short>",
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reflect_type_info() {
|
||||
// TypeInfo
|
||||
let info = i32::type_info();
|
||||
assert_eq!(std::any::type_name::<i32>(), info.type_name());
|
||||
assert_eq!(i32::type_path(), info.type_path());
|
||||
assert_eq!(std::any::TypeId::of::<i32>(), info.type_id());
|
||||
|
||||
// TypeInfo (unsized)
|
||||
|
@ -1293,21 +1297,15 @@ mod tests {
|
|||
let info = MyStruct::type_info();
|
||||
if let TypeInfo::Struct(info) = info {
|
||||
assert!(info.is::<MyStruct>());
|
||||
assert_eq!(std::any::type_name::<MyStruct>(), info.type_name());
|
||||
assert_eq!(
|
||||
std::any::type_name::<i32>(),
|
||||
info.field("foo").unwrap().type_name()
|
||||
);
|
||||
assert_eq!(MyStruct::type_path(), info.type_path());
|
||||
assert_eq!(i32::type_path(), info.field("foo").unwrap().type_path());
|
||||
assert_eq!(
|
||||
std::any::TypeId::of::<i32>(),
|
||||
info.field("foo").unwrap().type_id()
|
||||
);
|
||||
assert!(info.field("foo").unwrap().is::<i32>());
|
||||
assert_eq!("foo", info.field("foo").unwrap().name());
|
||||
assert_eq!(
|
||||
std::any::type_name::<usize>(),
|
||||
info.field_at(1).unwrap().type_name()
|
||||
);
|
||||
assert_eq!(usize::type_path(), info.field_at(1).unwrap().type_path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Struct`");
|
||||
}
|
||||
|
@ -1326,19 +1324,10 @@ mod tests {
|
|||
let info = <MyGenericStruct<i32>>::type_info();
|
||||
if let TypeInfo::Struct(info) = info {
|
||||
assert!(info.is::<MyGenericStruct<i32>>());
|
||||
assert_eq!(
|
||||
std::any::type_name::<MyGenericStruct<i32>>(),
|
||||
info.type_name()
|
||||
);
|
||||
assert_eq!(
|
||||
std::any::type_name::<i32>(),
|
||||
info.field("foo").unwrap().type_name()
|
||||
);
|
||||
assert_eq!(MyGenericStruct::<i32>::type_path(), info.type_path());
|
||||
assert_eq!(i32::type_path(), info.field("foo").unwrap().type_path());
|
||||
assert_eq!("foo", info.field("foo").unwrap().name());
|
||||
assert_eq!(
|
||||
std::any::type_name::<usize>(),
|
||||
info.field_at(1).unwrap().type_name()
|
||||
);
|
||||
assert_eq!(usize::type_path(), info.field_at(1).unwrap().type_path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Struct`");
|
||||
}
|
||||
|
@ -1357,11 +1346,8 @@ mod tests {
|
|||
let info = MyTupleStruct::type_info();
|
||||
if let TypeInfo::TupleStruct(info) = info {
|
||||
assert!(info.is::<MyTupleStruct>());
|
||||
assert_eq!(std::any::type_name::<MyTupleStruct>(), info.type_name());
|
||||
assert_eq!(
|
||||
std::any::type_name::<i32>(),
|
||||
info.field_at(1).unwrap().type_name()
|
||||
);
|
||||
assert_eq!(MyTupleStruct::type_path(), info.type_path());
|
||||
assert_eq!(i32::type_path(), info.field_at(1).unwrap().type_path());
|
||||
assert!(info.field_at(1).unwrap().is::<i32>());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::TupleStruct`");
|
||||
|
@ -1373,11 +1359,8 @@ mod tests {
|
|||
let info = MyTuple::type_info();
|
||||
if let TypeInfo::Tuple(info) = info {
|
||||
assert!(info.is::<MyTuple>());
|
||||
assert_eq!(std::any::type_name::<MyTuple>(), info.type_name());
|
||||
assert_eq!(
|
||||
std::any::type_name::<f32>(),
|
||||
info.field_at(1).unwrap().type_name()
|
||||
);
|
||||
assert_eq!(MyTuple::type_path(), info.type_path());
|
||||
assert_eq!(f32::type_path(), info.field_at(1).unwrap().type_path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Tuple`");
|
||||
}
|
||||
|
@ -1393,8 +1376,8 @@ mod tests {
|
|||
if let TypeInfo::List(info) = info {
|
||||
assert!(info.is::<MyList>());
|
||||
assert!(info.item_is::<usize>());
|
||||
assert_eq!(std::any::type_name::<MyList>(), info.type_name());
|
||||
assert_eq!(std::any::type_name::<usize>(), info.item_type_name());
|
||||
assert_eq!(MyList::type_path(), info.type_path());
|
||||
assert_eq!(usize::type_path(), info.item_type_path_table().path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::List`");
|
||||
}
|
||||
|
@ -1412,8 +1395,8 @@ mod tests {
|
|||
if let TypeInfo::List(info) = info {
|
||||
assert!(info.is::<MySmallVec>());
|
||||
assert!(info.item_is::<String>());
|
||||
assert_eq!(std::any::type_name::<MySmallVec>(), info.type_name());
|
||||
assert_eq!(std::any::type_name::<String>(), info.item_type_name());
|
||||
assert_eq!(MySmallVec::type_path(), info.type_path());
|
||||
assert_eq!(String::type_path(), info.item_type_path_table().path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::List`");
|
||||
}
|
||||
|
@ -1431,8 +1414,8 @@ mod tests {
|
|||
if let TypeInfo::Array(info) = info {
|
||||
assert!(info.is::<MyArray>());
|
||||
assert!(info.item_is::<usize>());
|
||||
assert_eq!(std::any::type_name::<MyArray>(), info.type_name());
|
||||
assert_eq!(std::any::type_name::<usize>(), info.item_type_name());
|
||||
assert_eq!(MyArray::type_path(), info.type_path());
|
||||
assert_eq!(usize::type_path(), info.item_type_path_table().path());
|
||||
assert_eq!(3, info.capacity());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Array`");
|
||||
|
@ -1448,7 +1431,7 @@ mod tests {
|
|||
let info = MyCowStr::type_info();
|
||||
if let TypeInfo::Value(info) = info {
|
||||
assert!(info.is::<MyCowStr>());
|
||||
assert_eq!(std::any::type_name::<MyCowStr>(), info.type_name());
|
||||
assert_eq!(std::any::type_name::<MyCowStr>(), info.type_path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Value`");
|
||||
}
|
||||
|
@ -1464,8 +1447,11 @@ mod tests {
|
|||
if let TypeInfo::List(info) = info {
|
||||
assert!(info.is::<MyCowSlice>());
|
||||
assert!(info.item_is::<u8>());
|
||||
assert_eq!(std::any::type_name::<MyCowSlice>(), info.type_name());
|
||||
assert_eq!(std::any::type_name::<u8>(), info.item_type_name());
|
||||
assert_eq!(std::any::type_name::<MyCowSlice>(), info.type_path());
|
||||
assert_eq!(
|
||||
std::any::type_name::<u8>(),
|
||||
info.item_type_path_table().path()
|
||||
);
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::List`");
|
||||
}
|
||||
|
@ -1482,9 +1468,9 @@ mod tests {
|
|||
assert!(info.is::<MyMap>());
|
||||
assert!(info.key_is::<usize>());
|
||||
assert!(info.value_is::<f32>());
|
||||
assert_eq!(std::any::type_name::<MyMap>(), info.type_name());
|
||||
assert_eq!(std::any::type_name::<usize>(), info.key_type_name());
|
||||
assert_eq!(std::any::type_name::<f32>(), info.value_type_name());
|
||||
assert_eq!(MyMap::type_path(), info.type_path());
|
||||
assert_eq!(usize::type_path(), info.key_type_path_table().path());
|
||||
assert_eq!(f32::type_path(), info.value_type_path_table().path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Map`");
|
||||
}
|
||||
|
@ -1499,7 +1485,7 @@ mod tests {
|
|||
let info = MyValue::type_info();
|
||||
if let TypeInfo::Value(info) = info {
|
||||
assert!(info.is::<MyValue>());
|
||||
assert_eq!(std::any::type_name::<MyValue>(), info.type_name());
|
||||
assert_eq!(MyValue::type_path(), info.type_path());
|
||||
} else {
|
||||
panic!("Expected `TypeInfo::Value`");
|
||||
}
|
||||
|
@ -1793,7 +1779,7 @@ mod tests {
|
|||
|
||||
let reflected: &dyn Reflect = &test;
|
||||
let expected = r#"
|
||||
bevy_reflect::tests::should_reflect_debug::Test {
|
||||
bevy_reflect::tests::Test {
|
||||
value: 123,
|
||||
list: [
|
||||
"A",
|
||||
|
@ -1808,10 +1794,10 @@ bevy_reflect::tests::should_reflect_debug::Test {
|
|||
map: {
|
||||
123: 1.23,
|
||||
},
|
||||
a_struct: bevy_reflect::tests::should_reflect_debug::SomeStruct {
|
||||
a_struct: bevy_reflect::tests::SomeStruct {
|
||||
foo: "A Struct!",
|
||||
},
|
||||
a_tuple_struct: bevy_reflect::tests::should_reflect_debug::SomeTupleStruct(
|
||||
a_tuple_struct: bevy_reflect::tests::SomeTupleStruct(
|
||||
"A Tuple Struct!",
|
||||
),
|
||||
enum_unit: A,
|
||||
|
@ -1941,7 +1927,10 @@ bevy_reflect::tests::should_reflect_debug::Test {
|
|||
registry.register::<Foo<NotTypePath>>();
|
||||
|
||||
let registration = registry.get(TypeId::of::<Foo<NotTypePath>>()).unwrap();
|
||||
assert_eq!("Foo<NotTypePath>", registration.short_name());
|
||||
assert_eq!(
|
||||
"Foo<NotTypePath>",
|
||||
registration.type_info().type_path_table().short_path()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "glam")]
|
||||
|
@ -1964,7 +1953,7 @@ bevy_reflect::tests::should_reflect_debug::Test {
|
|||
let output = to_string_pretty(&ser, config).unwrap();
|
||||
let expected = r#"
|
||||
{
|
||||
"glam::f32::vec3::Vec3": (
|
||||
"glam::Vec3": (
|
||||
x: 12.0,
|
||||
y: 3.0,
|
||||
z: -6.9,
|
||||
|
@ -1978,7 +1967,7 @@ bevy_reflect::tests::should_reflect_debug::Test {
|
|||
fn vec3_deserialization() {
|
||||
let data = r#"
|
||||
{
|
||||
"glam::f32::vec3::Vec3": (
|
||||
"glam::Vec3": (
|
||||
x: 12.0,
|
||||
y: 3.0,
|
||||
z: -6.9,
|
||||
|
|
|
@ -7,6 +7,7 @@ use bevy_reflect_derive::impl_type_path;
|
|||
use crate::utility::reflect_hasher;
|
||||
use crate::{
|
||||
self as bevy_reflect, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo,
|
||||
TypePath, TypePathTable,
|
||||
};
|
||||
|
||||
/// A trait used to power [list-like] operations via [reflection].
|
||||
|
@ -108,9 +109,9 @@ pub trait List: Reflect {
|
|||
/// A container for compile-time list info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ListInfo {
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
item_type_name: &'static str,
|
||||
item_type_path: TypePathTable,
|
||||
item_type_id: TypeId,
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: Option<&'static str>,
|
||||
|
@ -118,11 +119,11 @@ pub struct ListInfo {
|
|||
|
||||
impl ListInfo {
|
||||
/// Create a new [`ListInfo`].
|
||||
pub fn new<TList: List, TItem: FromReflect>() -> Self {
|
||||
pub fn new<TList: List + TypePath, TItem: FromReflect + TypePath>() -> Self {
|
||||
Self {
|
||||
type_name: std::any::type_name::<TList>(),
|
||||
type_path: TypePathTable::of::<TList>(),
|
||||
type_id: TypeId::of::<TList>(),
|
||||
item_type_name: std::any::type_name::<TItem>(),
|
||||
item_type_path: TypePathTable::of::<TItem>(),
|
||||
item_type_id: TypeId::of::<TItem>(),
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: None,
|
||||
|
@ -135,11 +136,21 @@ impl ListInfo {
|
|||
Self { docs, ..self }
|
||||
}
|
||||
|
||||
/// The [type name] of the list.
|
||||
/// A representation of the type path of the list.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the list.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the list.
|
||||
|
@ -152,11 +163,11 @@ impl ListInfo {
|
|||
TypeId::of::<T>() == self.type_id
|
||||
}
|
||||
|
||||
/// The [type name] of the list item.
|
||||
/// A representation of the type path of the list item.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn item_type_name(&self) -> &'static str {
|
||||
self.item_type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn item_type_path_table(&self) -> &TypePathTable {
|
||||
&self.item_type_path
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the list item.
|
||||
|
@ -263,13 +274,6 @@ impl List for DynamicList {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicList {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_else(|| std::any::type_name::<Self>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
|
|
@ -5,7 +5,10 @@ use std::hash::Hash;
|
|||
use bevy_reflect_derive::impl_type_path;
|
||||
use bevy_utils::{Entry, HashMap};
|
||||
|
||||
use crate::{self as bevy_reflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo};
|
||||
use crate::{
|
||||
self as bevy_reflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath,
|
||||
TypePathTable,
|
||||
};
|
||||
|
||||
/// A trait used to power [map-like] operations via [reflection].
|
||||
///
|
||||
|
@ -93,11 +96,11 @@ pub trait Map: Reflect {
|
|||
/// A container for compile-time map info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MapInfo {
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
key_type_name: &'static str,
|
||||
key_type_path: TypePathTable,
|
||||
key_type_id: TypeId,
|
||||
value_type_name: &'static str,
|
||||
value_type_path: TypePathTable,
|
||||
value_type_id: TypeId,
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: Option<&'static str>,
|
||||
|
@ -105,13 +108,17 @@ pub struct MapInfo {
|
|||
|
||||
impl MapInfo {
|
||||
/// Create a new [`MapInfo`].
|
||||
pub fn new<TMap: Map, TKey: Hash + Reflect, TValue: Reflect>() -> Self {
|
||||
pub fn new<
|
||||
TMap: Map + TypePath,
|
||||
TKey: Hash + Reflect + TypePath,
|
||||
TValue: Reflect + TypePath,
|
||||
>() -> Self {
|
||||
Self {
|
||||
type_name: std::any::type_name::<TMap>(),
|
||||
type_path: TypePathTable::of::<TMap>(),
|
||||
type_id: TypeId::of::<TMap>(),
|
||||
key_type_name: std::any::type_name::<TKey>(),
|
||||
key_type_path: TypePathTable::of::<TKey>(),
|
||||
key_type_id: TypeId::of::<TKey>(),
|
||||
value_type_name: std::any::type_name::<TValue>(),
|
||||
value_type_path: TypePathTable::of::<TValue>(),
|
||||
value_type_id: TypeId::of::<TValue>(),
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: None,
|
||||
|
@ -124,11 +131,21 @@ impl MapInfo {
|
|||
Self { docs, ..self }
|
||||
}
|
||||
|
||||
/// The [type name] of the map.
|
||||
/// A representation of the type path of the map.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the map.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the map.
|
||||
|
@ -141,11 +158,11 @@ impl MapInfo {
|
|||
TypeId::of::<T>() == self.type_id
|
||||
}
|
||||
|
||||
/// The [type name] of the key.
|
||||
/// A representation of the type path of the key type.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn key_type_name(&self) -> &'static str {
|
||||
self.key_type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn key_type_path_table(&self) -> &TypePathTable {
|
||||
&self.key_type_path
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the key.
|
||||
|
@ -158,11 +175,11 @@ impl MapInfo {
|
|||
TypeId::of::<T>() == self.key_type_id
|
||||
}
|
||||
|
||||
/// The [type name] of the value.
|
||||
/// A representation of the type path of the value type.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn value_type_name(&self) -> &'static str {
|
||||
self.value_type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn value_type_path_table(&self) -> &TypePathTable {
|
||||
&self.value_type_path
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the value.
|
||||
|
@ -297,12 +314,6 @@ impl Map for DynamicMap {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicMap {
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_else(|| std::any::type_name::<Self>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::{
|
||||
array_debug, enum_debug, list_debug, map_debug, serde::Serializable, struct_debug, tuple_debug,
|
||||
tuple_struct_debug, Array, DynamicTypePath, Enum, List, Map, Struct, Tuple, TupleStruct,
|
||||
TypeInfo, Typed, ValueInfo,
|
||||
TypeInfo, TypePath, Typed, ValueInfo,
|
||||
};
|
||||
use std::{
|
||||
any::{self, Any, TypeId},
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
};
|
||||
|
||||
|
@ -73,8 +73,23 @@ pub enum ReflectOwned {
|
|||
/// [derive macro]: bevy_reflect_derive::Reflect
|
||||
/// [crate-level documentation]: crate
|
||||
pub trait Reflect: DynamicTypePath + Any + Send + Sync {
|
||||
/// Returns the [type name][std::any::type_name] of the underlying type.
|
||||
fn type_name(&self) -> &str;
|
||||
/// Returns the type path of the underlying type.
|
||||
///
|
||||
/// This type path will either be found through [`get_represented_type_info`]
|
||||
/// or taken from a [`TypePath`] implementation if the former isn't available.
|
||||
///
|
||||
/// This method is deprecated; please consider migrating to one of the above methods.
|
||||
///
|
||||
/// [`get_represented_type_info`]: Reflect::get_represented_type_info
|
||||
#[deprecated(
|
||||
since = "0.12.0",
|
||||
note = "view the method documentation to find alternatives to this method."
|
||||
)]
|
||||
fn type_name(&self) -> &str {
|
||||
self.get_represented_type_info()
|
||||
.map(|info| info.type_path())
|
||||
.unwrap_or_else(|| self.reflect_type_path())
|
||||
}
|
||||
|
||||
/// Returns the [`TypeInfo`] of the type _represented_ by this value.
|
||||
///
|
||||
|
@ -200,10 +215,10 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
|
|||
/// Debug formatter for the value.
|
||||
///
|
||||
/// Any value that is not an implementor of other `Reflect` subtraits
|
||||
/// (e.g. [`List`], [`Map`]), will default to the format: `"Reflect(type_name)"`,
|
||||
/// where `type_name` is the [type name] of the underlying type.
|
||||
/// (e.g. [`List`], [`Map`]), will default to the format: `"Reflect(type_path)"`,
|
||||
/// where `type_path` is the [type path] of the underlying type.
|
||||
///
|
||||
/// [type name]: Self::type_name
|
||||
/// [type path]: TypePath::type_path
|
||||
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.reflect_ref() {
|
||||
ReflectRef::Struct(dyn_struct) => struct_debug(dyn_struct, f),
|
||||
|
@ -213,7 +228,7 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
|
|||
ReflectRef::Array(dyn_array) => array_debug(dyn_array, f),
|
||||
ReflectRef::Map(dyn_map) => map_debug(dyn_map, f),
|
||||
ReflectRef::Enum(dyn_enum) => enum_debug(dyn_enum, f),
|
||||
_ => write!(f, "Reflect({})", self.type_name()),
|
||||
_ => write!(f, "Reflect({})", self.reflect_type_path()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,6 +269,19 @@ impl Typed for dyn Reflect {
|
|||
}
|
||||
}
|
||||
|
||||
// The following implementation never actually shadows the concrete TypePath implementation.
|
||||
|
||||
// See this playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=589064053f27bc100d90da89c6a860aa).
|
||||
impl TypePath for dyn Reflect {
|
||||
fn type_path() -> &'static str {
|
||||
"dyn bevy_reflect::Reflect"
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
"dyn Reflect"
|
||||
}
|
||||
}
|
||||
|
||||
#[deny(rustdoc::broken_intra_doc_links)]
|
||||
impl dyn Reflect {
|
||||
/// Downcasts the value to type `T`, consuming the trait object.
|
||||
|
@ -279,8 +307,10 @@ impl dyn Reflect {
|
|||
///
|
||||
/// Read `is` for more information on underlying values and represented types.
|
||||
#[inline]
|
||||
pub fn represents<T: Reflect>(&self) -> bool {
|
||||
self.type_name() == any::type_name::<T>()
|
||||
pub fn represents<T: Reflect + TypePath>(&self) -> bool {
|
||||
self.get_represented_type_info()
|
||||
.map(|t| t.type_path() == T::type_path())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Returns `true` if the underlying value is of type `T`, or `false`
|
||||
|
|
|
@ -25,13 +25,13 @@ pub trait DeserializeValue {
|
|||
}
|
||||
|
||||
trait StructLikeInfo {
|
||||
fn get_name(&self) -> &str;
|
||||
fn get_path(&self) -> &str;
|
||||
fn get_field(&self, name: &str) -> Option<&NamedField>;
|
||||
fn iter_fields(&self) -> Iter<'_, NamedField>;
|
||||
}
|
||||
|
||||
trait TupleLikeInfo {
|
||||
fn get_name(&self) -> &str;
|
||||
fn get_path(&self) -> &str;
|
||||
fn get_field(&self, index: usize) -> Option<&UnnamedField>;
|
||||
fn get_field_len(&self) -> usize;
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ trait Container {
|
|||
}
|
||||
|
||||
impl StructLikeInfo for StructInfo {
|
||||
fn get_name(&self) -> &str {
|
||||
self.type_name()
|
||||
fn get_path(&self) -> &str {
|
||||
self.type_path()
|
||||
}
|
||||
|
||||
fn get_field(&self, name: &str) -> Option<&NamedField> {
|
||||
|
@ -68,15 +68,15 @@ impl Container for StructInfo {
|
|||
de::Error::custom(format_args!(
|
||||
"no field at index {} on struct {}",
|
||||
index,
|
||||
self.type_name(),
|
||||
self.type_path(),
|
||||
))
|
||||
})?;
|
||||
get_registration(field.type_id(), field.type_name(), registry)
|
||||
get_registration(field.type_id(), field.type_path(), registry)
|
||||
}
|
||||
}
|
||||
|
||||
impl StructLikeInfo for StructVariantInfo {
|
||||
fn get_name(&self) -> &str {
|
||||
fn get_path(&self) -> &str {
|
||||
self.name()
|
||||
}
|
||||
|
||||
|
@ -102,13 +102,13 @@ impl Container for StructVariantInfo {
|
|||
self.name(),
|
||||
))
|
||||
})?;
|
||||
get_registration(field.type_id(), field.type_name(), registry)
|
||||
get_registration(field.type_id(), field.type_path(), registry)
|
||||
}
|
||||
}
|
||||
|
||||
impl TupleLikeInfo for TupleInfo {
|
||||
fn get_name(&self) -> &str {
|
||||
self.type_name()
|
||||
fn get_path(&self) -> &str {
|
||||
self.type_path()
|
||||
}
|
||||
|
||||
fn get_field(&self, index: usize) -> Option<&UnnamedField> {
|
||||
|
@ -121,7 +121,7 @@ impl TupleLikeInfo for TupleInfo {
|
|||
}
|
||||
|
||||
impl TupleLikeInfo for TupleVariantInfo {
|
||||
fn get_name(&self) -> &str {
|
||||
fn get_path(&self) -> &str {
|
||||
self.name()
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ impl<'de> Visitor<'de> for U32Visitor {
|
|||
///
|
||||
/// Because the type isn't known ahead of time, the serialized data must take the form of
|
||||
/// a map containing the following entries (in order):
|
||||
/// 1. `type`: The _full_ [type name]
|
||||
/// 1. `type`: The _full_ [type path]
|
||||
/// 2. `value`: The serialized value of the reflected type
|
||||
///
|
||||
/// If the type is already known and the [`TypeInfo`] for it can be retrieved,
|
||||
|
@ -234,7 +234,7 @@ impl<'de> Visitor<'de> for U32Visitor {
|
|||
/// [`DynamicStruct`]: crate::DynamicStruct
|
||||
/// [`DynamicList`]: crate::DynamicList
|
||||
/// [`FromReflect`]: crate::FromReflect
|
||||
/// [type name]: std::any::type_name
|
||||
/// [type path]: crate::TypePath::type_path
|
||||
pub struct UntypedReflectDeserializer<'a> {
|
||||
registry: &'a TypeRegistry,
|
||||
}
|
||||
|
@ -261,11 +261,11 @@ impl<'a, 'de> DeserializeSeed<'de> for UntypedReflectDeserializer<'a> {
|
|||
/// A deserializer for type registrations.
|
||||
///
|
||||
/// This will return a [`&TypeRegistration`] corresponding to the given type.
|
||||
/// This deserializer expects a string containing the _full_ [type name] of the
|
||||
/// This deserializer expects a string containing the _full_ [type path] of the
|
||||
/// type to find the `TypeRegistration` of.
|
||||
///
|
||||
/// [`&TypeRegistration`]: crate::TypeRegistration
|
||||
/// [type name]: std::any::type_name
|
||||
/// [type path]: crate::TypePath::type_path
|
||||
pub struct TypeRegistrationDeserializer<'a> {
|
||||
registry: &'a TypeRegistry,
|
||||
}
|
||||
|
@ -292,12 +292,12 @@ impl<'a, 'de> DeserializeSeed<'de> for TypeRegistrationDeserializer<'a> {
|
|||
formatter.write_str("string containing `type` entry for the reflected value")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, type_name: &str) -> Result<Self::Value, E>
|
||||
fn visit_str<E>(self, type_path: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.get_with_name(type_name).ok_or_else(|| {
|
||||
Error::custom(format_args!("No registration found for `{type_name}`"))
|
||||
self.0.get_with_type_path(type_path).ok_or_else(|| {
|
||||
Error::custom(format_args!("No registration found for `{type_path}`"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -377,7 +377,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
|
|||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let type_name = self.registration.type_name();
|
||||
let type_path = self.registration.type_info().type_path();
|
||||
|
||||
// Handle both Value case and types that have a custom `ReflectDeserialize`
|
||||
if let Some(deserialize_reflect) = self.registration.data::<ReflectDeserialize>() {
|
||||
|
@ -388,7 +388,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
|
|||
match self.registration.type_info() {
|
||||
TypeInfo::Struct(struct_info) => {
|
||||
let mut dynamic_struct = deserializer.deserialize_struct(
|
||||
struct_info.name(),
|
||||
struct_info.type_path_table().ident().unwrap(),
|
||||
struct_info.field_names(),
|
||||
StructVisitor {
|
||||
struct_info,
|
||||
|
@ -401,7 +401,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
|
|||
}
|
||||
TypeInfo::TupleStruct(tuple_struct_info) => {
|
||||
let mut dynamic_tuple_struct = deserializer.deserialize_tuple_struct(
|
||||
tuple_struct_info.name(),
|
||||
tuple_struct_info.type_path_table().ident().unwrap(),
|
||||
tuple_struct_info.field_len(),
|
||||
TupleStructVisitor {
|
||||
tuple_struct_info,
|
||||
|
@ -451,15 +451,17 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
|
|||
Ok(Box::new(dynamic_tuple))
|
||||
}
|
||||
TypeInfo::Enum(enum_info) => {
|
||||
let type_name = enum_info.type_name();
|
||||
let mut dynamic_enum = if type_name.starts_with("core::option::Option") {
|
||||
let mut dynamic_enum = if enum_info.type_path_table().module_path()
|
||||
== Some("core::option")
|
||||
&& enum_info.type_path_table().ident() == Some("Option")
|
||||
{
|
||||
deserializer.deserialize_option(OptionVisitor {
|
||||
enum_info,
|
||||
registry: self.registry,
|
||||
})?
|
||||
} else {
|
||||
deserializer.deserialize_enum(
|
||||
enum_info.name(),
|
||||
enum_info.type_path_table().ident().unwrap(),
|
||||
enum_info.variant_names(),
|
||||
EnumVisitor {
|
||||
enum_info,
|
||||
|
@ -474,7 +476,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
|
|||
TypeInfo::Value(_) => {
|
||||
// This case should already be handled
|
||||
Err(de::Error::custom(format_args!(
|
||||
"the TypeRegistration for {type_name} doesn't have ReflectDeserialize",
|
||||
"the TypeRegistration for {type_path} doesn't have ReflectDeserialize",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
@ -578,10 +580,10 @@ impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> {
|
|||
de::Error::custom(format_args!(
|
||||
"no field at index {} on tuple {}",
|
||||
index,
|
||||
self.tuple_struct_info.type_name(),
|
||||
self.tuple_struct_info.type_path(),
|
||||
))
|
||||
})?;
|
||||
get_registration(field.type_id(), field.type_name(), self.registry)
|
||||
get_registration(field.type_id(), field.type_path(), self.registry)
|
||||
};
|
||||
|
||||
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer {
|
||||
|
@ -650,7 +652,7 @@ impl<'a, 'de> Visitor<'de> for ArrayVisitor<'a> {
|
|||
let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default());
|
||||
let registration = get_registration(
|
||||
self.array_info.item_type_id(),
|
||||
self.array_info.item_type_name(),
|
||||
self.array_info.item_type_path_table().path(),
|
||||
self.registry,
|
||||
)?;
|
||||
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer {
|
||||
|
@ -690,7 +692,7 @@ impl<'a, 'de> Visitor<'de> for ListVisitor<'a> {
|
|||
let mut list = DynamicList::default();
|
||||
let registration = get_registration(
|
||||
self.list_info.item_type_id(),
|
||||
self.list_info.item_type_name(),
|
||||
self.list_info.item_type_path_table().path(),
|
||||
self.registry,
|
||||
)?;
|
||||
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer {
|
||||
|
@ -722,12 +724,12 @@ impl<'a, 'de> Visitor<'de> for MapVisitor<'a> {
|
|||
let mut dynamic_map = DynamicMap::default();
|
||||
let key_registration = get_registration(
|
||||
self.map_info.key_type_id(),
|
||||
self.map_info.key_type_name(),
|
||||
self.map_info.key_type_path_table().path(),
|
||||
self.registry,
|
||||
)?;
|
||||
let value_registration = get_registration(
|
||||
self.map_info.value_type_id(),
|
||||
self.map_info.value_type_name(),
|
||||
self.map_info.value_type_path_table().path(),
|
||||
self.registry,
|
||||
)?;
|
||||
while let Some(key) = map.next_key_seed(TypedReflectDeserializer {
|
||||
|
@ -782,7 +784,7 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> {
|
|||
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
|
||||
let field = tuple_info.field_at(0).unwrap();
|
||||
let registration =
|
||||
get_registration(field.type_id(), field.type_name(), self.registry)?;
|
||||
get_registration(field.type_id(), field.type_path(), self.registry)?;
|
||||
let value = variant.newtype_variant_seed(TypedReflectDeserializer {
|
||||
registration,
|
||||
registry: self.registry,
|
||||
|
@ -850,7 +852,7 @@ impl<'de> DeserializeSeed<'de> for VariantDeserializer {
|
|||
Error::custom(format_args!(
|
||||
"no variant found at index `{}` on enum `{}`",
|
||||
variant_index,
|
||||
self.0.name()
|
||||
self.0.type_path()
|
||||
))
|
||||
})
|
||||
}
|
||||
|
@ -960,7 +962,7 @@ impl<'a, 'de> Visitor<'de> for OptionVisitor<'a> {
|
|||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
formatter.write_str("reflected option value of type ")?;
|
||||
formatter.write_str(self.enum_info.type_name())
|
||||
formatter.write_str(self.enum_info.type_path())
|
||||
}
|
||||
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
|
@ -972,7 +974,7 @@ impl<'a, 'de> Visitor<'de> for OptionVisitor<'a> {
|
|||
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
|
||||
let field = tuple_info.field_at(0).unwrap();
|
||||
let registration =
|
||||
get_registration(field.type_id(), field.type_name(), self.registry)?;
|
||||
get_registration(field.type_id(), field.type_path(), self.registry)?;
|
||||
let de = TypedReflectDeserializer {
|
||||
registration,
|
||||
registry: self.registry,
|
||||
|
@ -1019,7 +1021,7 @@ where
|
|||
ExpectedValues(fields.collect())
|
||||
))
|
||||
})?;
|
||||
let registration = get_registration(field.type_id(), field.type_name(), registry)?;
|
||||
let registration = get_registration(field.type_id(), field.type_path(), registry)?;
|
||||
let value = map.next_value_seed(TypedReflectDeserializer {
|
||||
registration,
|
||||
registry,
|
||||
|
@ -1046,7 +1048,7 @@ where
|
|||
let field = info.get_field(index).ok_or_else(|| {
|
||||
Error::invalid_length(index, &info.get_field_len().to_string().as_str())
|
||||
})?;
|
||||
get_registration(field.type_id(), field.type_name(), registry)
|
||||
get_registration(field.type_id(), field.type_path(), registry)
|
||||
};
|
||||
|
||||
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer {
|
||||
|
@ -1074,11 +1076,11 @@ where
|
|||
|
||||
fn get_registration<'a, E: Error>(
|
||||
type_id: TypeId,
|
||||
type_name: &str,
|
||||
type_path: &str,
|
||||
registry: &'a TypeRegistry,
|
||||
) -> Result<&'a TypeRegistration, E> {
|
||||
let registration = registry.get(type_id).ok_or_else(|| {
|
||||
Error::custom(format_args!("no registration found for type `{type_name}`"))
|
||||
Error::custom(format_args!("no registration found for type `{type_path}`"))
|
||||
})?;
|
||||
Ok(registration)
|
||||
}
|
||||
|
@ -1356,7 +1358,7 @@ mod tests {
|
|||
|
||||
// === Normal === //
|
||||
let input = r#"{
|
||||
"bevy_reflect::serde::de::tests::should_deserialize_option::OptionTest": (
|
||||
"bevy_reflect::serde::de::tests::OptionTest": (
|
||||
none: None,
|
||||
simple: Some("Hello world!"),
|
||||
complex: Some((
|
||||
|
@ -1378,7 +1380,7 @@ mod tests {
|
|||
let input = r#"
|
||||
#![enable(implicit_some)]
|
||||
{
|
||||
"bevy_reflect::serde::de::tests::should_deserialize_option::OptionTest": (
|
||||
"bevy_reflect::serde::de::tests::OptionTest": (
|
||||
none: None,
|
||||
simple: "Hello world!",
|
||||
complex: (
|
||||
|
@ -1415,7 +1417,7 @@ mod tests {
|
|||
|
||||
// === Unit Variant === //
|
||||
let input = r#"{
|
||||
"bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": Unit,
|
||||
"bevy_reflect::serde::de::tests::MyEnum": Unit,
|
||||
}"#;
|
||||
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
|
||||
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
|
||||
|
@ -1426,7 +1428,7 @@ mod tests {
|
|||
|
||||
// === NewType Variant === //
|
||||
let input = r#"{
|
||||
"bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": NewType(123),
|
||||
"bevy_reflect::serde::de::tests::MyEnum": NewType(123),
|
||||
}"#;
|
||||
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
|
||||
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
|
||||
|
@ -1437,7 +1439,7 @@ mod tests {
|
|||
|
||||
// === Tuple Variant === //
|
||||
let input = r#"{
|
||||
"bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": Tuple(1.23, 3.21),
|
||||
"bevy_reflect::serde::de::tests::MyEnum": Tuple(1.23, 3.21),
|
||||
}"#;
|
||||
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
|
||||
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
|
||||
|
@ -1448,7 +1450,7 @@ mod tests {
|
|||
|
||||
// === Struct Variant === //
|
||||
let input = r#"{
|
||||
"bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": Struct(
|
||||
"bevy_reflect::serde::de::tests::MyEnum": Struct(
|
||||
value: "I <3 Enums",
|
||||
),
|
||||
}"#;
|
||||
|
|
|
@ -94,7 +94,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "cannot get type info for bevy_reflect::struct_trait::DynamicStruct")]
|
||||
#[should_panic(expected = "cannot get type info for bevy_reflect::DynamicStruct")]
|
||||
fn unproxied_dynamic_should_not_serialize() {
|
||||
let registry = TypeRegistry::default();
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ fn get_serializable<'a, E: serde::ser::Error>(
|
|||
.ok_or_else(|| {
|
||||
serde::ser::Error::custom(format_args!(
|
||||
"Type '{}' did not register ReflectSerialize",
|
||||
reflect_value.type_name()
|
||||
reflect_value.reflect_type_path()
|
||||
))
|
||||
})?;
|
||||
Ok(reflect_serialize.get_serializable(reflect_value))
|
||||
|
@ -46,10 +46,10 @@ fn get_serializable<'a, E: serde::ser::Error>(
|
|||
/// A general purpose serializer for reflected types.
|
||||
///
|
||||
/// The serialized data will take the form of a map containing the following entries:
|
||||
/// 1. `type`: The _full_ [type name]
|
||||
/// 1. `type`: The _full_ [type path]
|
||||
/// 2. `value`: The serialized value of the reflected type
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
/// [type path]: crate::TypePath::type_path
|
||||
pub struct ReflectSerializer<'a> {
|
||||
pub value: &'a dyn Reflect,
|
||||
pub registry: &'a TypeRegistry,
|
||||
|
@ -68,7 +68,7 @@ impl<'a> Serialize for ReflectSerializer<'a> {
|
|||
{
|
||||
let mut state = serializer.serialize_map(Some(1))?;
|
||||
state.serialize_entry(
|
||||
self.value.type_name(),
|
||||
self.value.reflect_type_path(),
|
||||
&TypedReflectSerializer::new(self.value, self.registry),
|
||||
)?;
|
||||
state.end()
|
||||
|
@ -172,7 +172,7 @@ impl<'a> Serialize for StructSerializer<'a> {
|
|||
.ok_or_else(|| {
|
||||
Error::custom(format_args!(
|
||||
"cannot get type info for {}",
|
||||
self.struct_value.type_name()
|
||||
self.struct_value.reflect_type_path()
|
||||
))
|
||||
})?;
|
||||
|
||||
|
@ -191,7 +191,7 @@ impl<'a> Serialize for StructSerializer<'a> {
|
|||
.and_then(|registration| registration.data::<SerializationData>());
|
||||
let ignored_len = serialization_data.map(|data| data.len()).unwrap_or(0);
|
||||
let mut state = serializer.serialize_struct(
|
||||
struct_info.name(),
|
||||
struct_info.type_path_table().ident().unwrap(),
|
||||
self.struct_value.field_len() - ignored_len,
|
||||
)?;
|
||||
|
||||
|
@ -225,7 +225,7 @@ impl<'a> Serialize for TupleStructSerializer<'a> {
|
|||
.ok_or_else(|| {
|
||||
Error::custom(format_args!(
|
||||
"cannot get type info for {}",
|
||||
self.tuple_struct.type_name()
|
||||
self.tuple_struct.reflect_type_path()
|
||||
))
|
||||
})?;
|
||||
|
||||
|
@ -244,7 +244,7 @@ impl<'a> Serialize for TupleStructSerializer<'a> {
|
|||
.and_then(|registration| registration.data::<SerializationData>());
|
||||
let ignored_len = serialization_data.map(|data| data.len()).unwrap_or(0);
|
||||
let mut state = serializer.serialize_tuple_struct(
|
||||
tuple_struct_info.name(),
|
||||
tuple_struct_info.type_path_table().ident().unwrap(),
|
||||
self.tuple_struct.field_len() - ignored_len,
|
||||
)?;
|
||||
|
||||
|
@ -274,7 +274,7 @@ impl<'a> Serialize for EnumSerializer<'a> {
|
|||
let type_info = self.enum_value.get_represented_type_info().ok_or_else(|| {
|
||||
Error::custom(format_args!(
|
||||
"cannot get type info for {}",
|
||||
self.enum_value.type_name()
|
||||
self.enum_value.reflect_type_path()
|
||||
))
|
||||
})?;
|
||||
|
||||
|
@ -287,7 +287,7 @@ impl<'a> Serialize for EnumSerializer<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let enum_name = enum_info.name();
|
||||
let enum_name = enum_info.type_path_table().ident().unwrap();
|
||||
let variant_index = self.enum_value.variant_index() as u32;
|
||||
let variant_info = enum_info
|
||||
.variant_at(variant_index as usize)
|
||||
|
@ -302,10 +302,8 @@ impl<'a> Serialize for EnumSerializer<'a> {
|
|||
|
||||
match variant_type {
|
||||
VariantType::Unit => {
|
||||
if self
|
||||
.enum_value
|
||||
.type_name()
|
||||
.starts_with("core::option::Option")
|
||||
if self.enum_value.reflect_module_path() == Some("core::option")
|
||||
&& self.enum_value.reflect_type_ident() == Some("Option")
|
||||
{
|
||||
serializer.serialize_none()
|
||||
} else {
|
||||
|
@ -341,7 +339,7 @@ impl<'a> Serialize for EnumSerializer<'a> {
|
|||
let field = self.enum_value.field_at(0).unwrap();
|
||||
if self
|
||||
.enum_value
|
||||
.type_name()
|
||||
.reflect_type_path()
|
||||
.starts_with("core::option::Option")
|
||||
{
|
||||
serializer.serialize_some(&TypedReflectSerializer::new(field, self.registry))
|
||||
|
@ -667,7 +665,7 @@ mod tests {
|
|||
|
||||
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
|
||||
let expected = r#"{
|
||||
"bevy_reflect::serde::ser::tests::should_serialize_option::OptionTest": (
|
||||
"bevy_reflect::serde::ser::tests::OptionTest": (
|
||||
none: None,
|
||||
simple: Some("Hello world!"),
|
||||
complex: Some((
|
||||
|
@ -687,7 +685,7 @@ mod tests {
|
|||
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
|
||||
let expected = r#"#![enable(implicit_some)]
|
||||
{
|
||||
"bevy_reflect::serde::ser::tests::should_serialize_option::OptionTest": (
|
||||
"bevy_reflect::serde::ser::tests::OptionTest": (
|
||||
none: None,
|
||||
simple: "Hello world!",
|
||||
complex: (
|
||||
|
@ -719,7 +717,7 @@ mod tests {
|
|||
let serializer = ReflectSerializer::new(&value, ®istry);
|
||||
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
|
||||
let expected = r#"{
|
||||
"bevy_reflect::serde::ser::tests::enum_should_serialize::MyEnum": Unit,
|
||||
"bevy_reflect::serde::ser::tests::MyEnum": Unit,
|
||||
}"#;
|
||||
assert_eq!(expected, output);
|
||||
|
||||
|
@ -728,7 +726,7 @@ mod tests {
|
|||
let serializer = ReflectSerializer::new(&value, ®istry);
|
||||
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
|
||||
let expected = r#"{
|
||||
"bevy_reflect::serde::ser::tests::enum_should_serialize::MyEnum": NewType(123),
|
||||
"bevy_reflect::serde::ser::tests::MyEnum": NewType(123),
|
||||
}"#;
|
||||
assert_eq!(expected, output);
|
||||
|
||||
|
@ -737,7 +735,7 @@ mod tests {
|
|||
let serializer = ReflectSerializer::new(&value, ®istry);
|
||||
let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();
|
||||
let expected = r#"{
|
||||
"bevy_reflect::serde::ser::tests::enum_should_serialize::MyEnum": Tuple(1.23, 3.21),
|
||||
"bevy_reflect::serde::ser::tests::MyEnum": Tuple(1.23, 3.21),
|
||||
}"#;
|
||||
assert_eq!(expected, output);
|
||||
|
||||
|
@ -748,7 +746,7 @@ mod tests {
|
|||
let serializer = ReflectSerializer::new(&value, ®istry);
|
||||
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
|
||||
let expected = r#"{
|
||||
"bevy_reflect::serde::ser::tests::enum_should_serialize::MyEnum": Struct(
|
||||
"bevy_reflect::serde::ser::tests::MyEnum": Struct(
|
||||
value: "I <3 Enums",
|
||||
),
|
||||
}"#;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
self as bevy_reflect, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo,
|
||||
TypePath, TypePathTable,
|
||||
};
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
use bevy_utils::{Entry, HashMap};
|
||||
|
@ -75,8 +76,7 @@ pub trait Struct: Reflect {
|
|||
/// A container for compile-time named struct info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StructInfo {
|
||||
name: &'static str,
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
fields: Box<[NamedField]>,
|
||||
field_names: Box<[&'static str]>,
|
||||
|
@ -90,10 +90,9 @@ impl StructInfo {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name`: The name of this struct (_without_ generics or lifetimes)
|
||||
/// * `fields`: The fields of this struct in the order they are defined
|
||||
///
|
||||
pub fn new<T: Reflect>(name: &'static str, fields: &[NamedField]) -> Self {
|
||||
pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
|
||||
let field_indices = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
@ -103,8 +102,7 @@ impl StructInfo {
|
|||
let field_names = fields.iter().map(|field| field.name()).collect();
|
||||
|
||||
Self {
|
||||
name,
|
||||
type_name: std::any::type_name::<T>(),
|
||||
type_path: TypePathTable::of::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
fields: fields.to_vec().into_boxed_slice(),
|
||||
field_names,
|
||||
|
@ -152,20 +150,21 @@ impl StructInfo {
|
|||
self.fields.len()
|
||||
}
|
||||
|
||||
/// The name of the struct.
|
||||
/// A representation of the type path of the struct.
|
||||
///
|
||||
/// This does _not_ include any generics or lifetimes.
|
||||
///
|
||||
/// For example, `foo::bar::Baz<'a, T>` would simply be `Baz`.
|
||||
pub fn name(&self) -> &'static str {
|
||||
self.name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [type name] of the struct.
|
||||
/// The [stable, full type path] of the struct.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the struct.
|
||||
|
@ -392,13 +391,6 @@ impl Struct for DynamicStruct {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicStruct {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_else(|| std::any::type_name::<Self>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
@ -551,7 +543,7 @@ pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
|
|||
/// ```
|
||||
#[inline]
|
||||
pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut debug = f.debug_struct(dyn_struct.type_name());
|
||||
let mut debug = f.debug_struct(dyn_struct.reflect_type_path());
|
||||
for field_index in 0..dyn_struct.field_len() {
|
||||
let field = dyn_struct.field_at(field_index).unwrap();
|
||||
debug.field(
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use bevy_reflect_derive::impl_type_path;
|
||||
use bevy_utils::all_tuples;
|
||||
|
||||
use crate::TypePathTable;
|
||||
use crate::{
|
||||
self as bevy_reflect, utility::GenericTypePathCell, FromReflect, GetTypeRegistration, Reflect,
|
||||
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypeRegistration, Typed,
|
||||
UnnamedField,
|
||||
};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::slice::Iter;
|
||||
|
||||
|
@ -138,7 +139,7 @@ impl GetTupleField for dyn Tuple {
|
|||
/// A container for compile-time tuple info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TupleInfo {
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
fields: Box<[UnnamedField]>,
|
||||
#[cfg(feature = "documentation")]
|
||||
|
@ -152,9 +153,9 @@ impl TupleInfo {
|
|||
///
|
||||
/// * `fields`: The fields of this tuple in the order they are defined
|
||||
///
|
||||
pub fn new<T: Reflect>(fields: &[UnnamedField]) -> Self {
|
||||
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
|
||||
Self {
|
||||
type_name: std::any::type_name::<T>(),
|
||||
type_path: TypePathTable::of::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
fields: fields.to_vec().into_boxed_slice(),
|
||||
#[cfg(feature = "documentation")]
|
||||
|
@ -183,11 +184,21 @@ impl TupleInfo {
|
|||
self.fields.len()
|
||||
}
|
||||
|
||||
/// The [type name] of the tuple.
|
||||
/// A representation of the type path of the tuple.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the tuple.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the tuple.
|
||||
|
@ -210,7 +221,6 @@ impl TupleInfo {
|
|||
/// A tuple which allows fields to be added at runtime.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct DynamicTuple {
|
||||
name: Cow<'static, str>,
|
||||
represented_type: Option<&'static TypeInfo>,
|
||||
fields: Vec<Box<dyn Reflect>>,
|
||||
}
|
||||
|
@ -230,8 +240,6 @@ impl DynamicTuple {
|
|||
"expected TypeInfo::Tuple but received: {:?}",
|
||||
represented_type
|
||||
);
|
||||
|
||||
self.name = Cow::Borrowed(represented_type.type_name());
|
||||
}
|
||||
self.represented_type = represented_type;
|
||||
}
|
||||
|
@ -240,28 +248,12 @@ impl DynamicTuple {
|
|||
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
|
||||
self.represented_type = None;
|
||||
self.fields.push(value);
|
||||
self.generate_name();
|
||||
}
|
||||
|
||||
/// Appends a typed element with value `value` to the tuple.
|
||||
pub fn insert<T: Reflect>(&mut self, value: T) {
|
||||
self.represented_type = None;
|
||||
self.insert_boxed(Box::new(value));
|
||||
self.generate_name();
|
||||
}
|
||||
|
||||
fn generate_name(&mut self) {
|
||||
let mut name = self.name.to_string();
|
||||
name.clear();
|
||||
name.push('(');
|
||||
for (i, field) in self.fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
name.push_str(", ");
|
||||
}
|
||||
name.push_str(field.type_name());
|
||||
}
|
||||
name.push(')');
|
||||
self.name = Cow::Owned(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,7 +289,6 @@ impl Tuple for DynamicTuple {
|
|||
#[inline]
|
||||
fn clone_dynamic(&self) -> DynamicTuple {
|
||||
DynamicTuple {
|
||||
name: self.name.clone(),
|
||||
represented_type: self.represented_type,
|
||||
fields: self
|
||||
.fields
|
||||
|
@ -309,13 +300,6 @@ impl Tuple for DynamicTuple {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicTuple {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_else(|| &self.name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
@ -514,7 +498,6 @@ macro_rules! impl_reflect_tuple {
|
|||
fn clone_dynamic(&self) -> DynamicTuple {
|
||||
let info = self.get_represented_type_info();
|
||||
DynamicTuple {
|
||||
name: Cow::Borrowed(::core::any::type_name::<Self>()),
|
||||
represented_type: info,
|
||||
fields: self
|
||||
.iter_fields()
|
||||
|
@ -525,10 +508,6 @@ macro_rules! impl_reflect_tuple {
|
|||
}
|
||||
|
||||
impl<$($name: Reflect + TypePath),*> Reflect for ($($name,)*) {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
@ -600,22 +579,6 @@ macro_rules! impl_reflect_tuple {
|
|||
}
|
||||
}
|
||||
|
||||
impl <$($name: Reflect + TypePath),*> TypePath for ($($name,)*) {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| {
|
||||
"(".to_owned() $(+ <$name as TypePath>::type_path())* + ")"
|
||||
})
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| {
|
||||
"(".to_owned() $(+ <$name as TypePath>::short_type_path())* + ")"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<$($name: Reflect + TypePath),*> GetTypeRegistration for ($($name,)*) {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
|
@ -655,3 +618,56 @@ impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I}
|
|||
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J}
|
||||
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K}
|
||||
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L}
|
||||
|
||||
macro_rules! impl_type_path_tuple {
|
||||
() => {
|
||||
impl TypePath for () {
|
||||
fn type_path() -> &'static str {
|
||||
"()"
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
"()"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($param:ident) => {
|
||||
impl <$param: TypePath> TypePath for ($param,) {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| {
|
||||
"(".to_owned() + $param::type_path() + ",)"
|
||||
})
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| {
|
||||
"(".to_owned() + $param::short_type_path() + ",)"
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($last:ident $(,$param:ident)*) => {
|
||||
|
||||
impl <$($param: TypePath,)* $last: TypePath> TypePath for ($($param,)* $last) {
|
||||
fn type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| {
|
||||
"(".to_owned() $(+ $param::type_path() + ", ")* + $last::type_path() + ")"
|
||||
})
|
||||
}
|
||||
|
||||
fn short_type_path() -> &'static str {
|
||||
static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
CELL.get_or_insert::<Self, _>(|| {
|
||||
"(".to_owned() $(+ $param::short_type_path() + ", ")* + $last::short_type_path() + ")"
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
all_tuples!(impl_type_path_tuple, 0, 12, P);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
use crate::{
|
||||
self as bevy_reflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, UnnamedField,
|
||||
self as bevy_reflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath,
|
||||
TypePathTable, UnnamedField,
|
||||
};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
@ -55,8 +56,7 @@ pub trait TupleStruct: Reflect {
|
|||
/// A container for compile-time tuple struct info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TupleStructInfo {
|
||||
name: &'static str,
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
fields: Box<[UnnamedField]>,
|
||||
#[cfg(feature = "documentation")]
|
||||
|
@ -68,13 +68,11 @@ impl TupleStructInfo {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name`: The name of this struct (_without_ generics or lifetimes)
|
||||
/// * `fields`: The fields of this struct in the order they are defined
|
||||
///
|
||||
pub fn new<T: Reflect>(name: &'static str, fields: &[UnnamedField]) -> Self {
|
||||
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
|
||||
Self {
|
||||
name,
|
||||
type_name: std::any::type_name::<T>(),
|
||||
type_path: TypePathTable::of::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
fields: fields.to_vec().into_boxed_slice(),
|
||||
#[cfg(feature = "documentation")]
|
||||
|
@ -103,20 +101,21 @@ impl TupleStructInfo {
|
|||
self.fields.len()
|
||||
}
|
||||
|
||||
/// The name of the struct.
|
||||
/// A representation of the type path of the struct.
|
||||
///
|
||||
/// This does _not_ include any generics or lifetimes.
|
||||
///
|
||||
/// For example, `foo::bar::Baz<'a, T>` would simply be `Baz`.
|
||||
pub fn name(&self) -> &'static str {
|
||||
self.name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [type name] of the tuple struct.
|
||||
/// The [stable, full type path] of the struct.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the tuple struct.
|
||||
|
@ -295,13 +294,6 @@ impl TupleStruct for DynamicTupleStruct {
|
|||
}
|
||||
|
||||
impl Reflect for DynamicTupleStruct {
|
||||
#[inline]
|
||||
fn type_name(&self) -> &str {
|
||||
self.represented_type
|
||||
.map(|info| info.type_name())
|
||||
.unwrap_or_else(|| std::any::type_name::<Self>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
self.represented_type
|
||||
|
@ -452,7 +444,7 @@ pub fn tuple_struct_debug(
|
|||
dyn_tuple_struct: &dyn TupleStruct,
|
||||
f: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
let mut debug = f.debug_tuple(dyn_tuple_struct.type_name());
|
||||
let mut debug = f.debug_tuple(dyn_tuple_struct.reflect_type_path());
|
||||
for field in dyn_tuple_struct.iter_fields() {
|
||||
debug.field(&field as &dyn Debug);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
ArrayInfo, EnumInfo, ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo,
|
||||
TypePath, TypePathTable,
|
||||
};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::fmt::Debug;
|
||||
|
@ -41,15 +42,17 @@ use std::fmt::Debug;
|
|||
/// NamedField::new::<usize >("foo"),
|
||||
/// NamedField::new::<(f32, f32) >("bar"),
|
||||
/// ];
|
||||
/// let info = StructInfo::new::<Self>("MyStruct", &fields);
|
||||
/// let info = StructInfo::new::<Self>(&fields);
|
||||
/// TypeInfo::Struct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #
|
||||
/// # impl TypePath for MyStruct {
|
||||
/// # fn type_path() -> &'static str { todo!() }
|
||||
/// # fn short_type_path() -> &'static str { todo!() }
|
||||
/// # }
|
||||
/// # impl Reflect for MyStruct {
|
||||
/// # fn type_name(&self) -> &str { todo!() }
|
||||
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
|
||||
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
|
||||
/// # fn as_any(&self) -> &dyn Any { todo!() }
|
||||
|
@ -64,15 +67,10 @@ use std::fmt::Debug;
|
|||
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
|
||||
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl TypePath for MyStruct {
|
||||
/// # fn type_path() -> &'static str { todo!() }
|
||||
/// # fn short_type_path() -> &'static str { todo!() }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [utility]: crate::utility
|
||||
pub trait Typed: Reflect {
|
||||
pub trait Typed: Reflect + TypePath {
|
||||
/// Returns the compile-time [info] for the underlying type.
|
||||
///
|
||||
/// [info]: TypeInfo
|
||||
|
@ -90,7 +88,7 @@ pub trait Typed: Reflect {
|
|||
/// Each return a static reference to [`TypeInfo`], but they all have their own use cases.
|
||||
/// For example, if you know the type at compile time, [`Typed::type_info`] is probably
|
||||
/// the simplest. If all you have is a `dyn Reflect`, you'll probably want [`Reflect::get_represented_type_info`].
|
||||
/// Lastly, if all you have is a [`TypeId`] or [type name], you will need to go through
|
||||
/// Lastly, if all you have is a [`TypeId`] or [type path], you will need to go through
|
||||
/// [`TypeRegistry::get_type_info`].
|
||||
///
|
||||
/// You may also opt to use [`TypeRegistry::get_type_info`] in place of the other methods simply because
|
||||
|
@ -100,7 +98,7 @@ pub trait Typed: Reflect {
|
|||
/// [`Reflect::get_represented_type_info`]: crate::Reflect::get_represented_type_info
|
||||
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
|
||||
/// [`TypeId`]: std::any::TypeId
|
||||
/// [type name]: std::any::type_name
|
||||
/// [type path]: TypePath::type_path
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TypeInfo {
|
||||
Struct(StructInfo),
|
||||
|
@ -128,22 +126,32 @@ impl TypeInfo {
|
|||
}
|
||||
}
|
||||
|
||||
/// The [name] of the underlying type.
|
||||
/// A representation of the type path of the underlying type.
|
||||
///
|
||||
/// [name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
match self {
|
||||
Self::Struct(info) => info.type_name(),
|
||||
Self::TupleStruct(info) => info.type_name(),
|
||||
Self::Tuple(info) => info.type_name(),
|
||||
Self::List(info) => info.type_name(),
|
||||
Self::Array(info) => info.type_name(),
|
||||
Self::Map(info) => info.type_name(),
|
||||
Self::Enum(info) => info.type_name(),
|
||||
Self::Value(info) => info.type_name(),
|
||||
Self::Struct(info) => info.type_path_table(),
|
||||
Self::TupleStruct(info) => info.type_path_table(),
|
||||
Self::Tuple(info) => info.type_path_table(),
|
||||
Self::List(info) => info.type_path_table(),
|
||||
Self::Array(info) => info.type_path_table(),
|
||||
Self::Map(info) => info.type_path_table(),
|
||||
Self::Enum(info) => info.type_path_table(),
|
||||
Self::Value(info) => info.type_path_table(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the underlying type.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// Check if the given type matches the underlying type.
|
||||
pub fn is<T: Any>(&self) -> bool {
|
||||
TypeId::of::<T>() == self.type_id()
|
||||
|
@ -175,16 +183,16 @@ impl TypeInfo {
|
|||
/// it _as_ a struct. It therefore makes more sense to represent it as a [`ValueInfo`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValueInfo {
|
||||
type_name: &'static str,
|
||||
type_path: TypePathTable,
|
||||
type_id: TypeId,
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl ValueInfo {
|
||||
pub fn new<T: Reflect + ?Sized>() -> Self {
|
||||
pub fn new<T: Reflect + TypePath + ?Sized>() -> Self {
|
||||
Self {
|
||||
type_name: std::any::type_name::<T>(),
|
||||
type_path: TypePathTable::of::<T>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: None,
|
||||
|
@ -197,11 +205,21 @@ impl ValueInfo {
|
|||
Self { docs: doc, ..self }
|
||||
}
|
||||
|
||||
/// The [type name] of the value.
|
||||
/// A representation of the type path of the value.
|
||||
///
|
||||
/// [type name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_name
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
pub fn type_path_table(&self) -> &TypePathTable {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The [stable, full type path] of the value.
|
||||
///
|
||||
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
|
||||
///
|
||||
/// [stable, full type path]: TypePath
|
||||
/// [`type_path_table`]: Self::type_path_table
|
||||
pub fn type_path(&self) -> &'static str {
|
||||
self.type_path_table().path()
|
||||
}
|
||||
|
||||
/// The [`TypeId`] of the value.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::fmt;
|
||||
|
||||
/// A static accessor to type paths and names.
|
||||
///
|
||||
/// The engine uses this trait over [`std::any::type_name`] for stability and flexibility.
|
||||
|
@ -82,21 +84,21 @@ pub trait TypePath: 'static {
|
|||
///
|
||||
/// Generic parameter types are also fully expanded.
|
||||
///
|
||||
/// For `Option<PhantomData>`, this is `"core::option::Option<core::marker::PhantomData>"`.
|
||||
/// For `Option<Vec<usize>>`, this is `"core::option::Option<alloc::vec::Vec<usize>>"`.
|
||||
fn type_path() -> &'static str;
|
||||
|
||||
/// Returns a short, pretty-print enabled path to the type.
|
||||
///
|
||||
/// Generic parameter types are also shortened.
|
||||
///
|
||||
/// For `Option<PhantomData>`, this is `"Option<PhantomData>"`.
|
||||
/// For `Option<Vec<usize>>`, this is `"Option<Vec<usize>>"`.
|
||||
fn short_type_path() -> &'static str;
|
||||
|
||||
/// Returns the name of the type, or [`None`] if it is [anonymous].
|
||||
///
|
||||
/// Primitive types will return [`Some`].
|
||||
///
|
||||
/// For `Option<PhantomData>`, this is `"Option"`.
|
||||
/// For `Option<Vec<usize>>`, this is `"Option"`.
|
||||
///
|
||||
/// [anonymous]: TypePath#anonymity
|
||||
fn type_ident() -> Option<&'static str> {
|
||||
|
@ -105,7 +107,7 @@ pub trait TypePath: 'static {
|
|||
|
||||
/// Returns the name of the crate the type is in, or [`None`] if it is [anonymous].
|
||||
///
|
||||
/// For `Option<PhantomData>`, this is `"core"`.
|
||||
/// For `Option<Vec<usize>>`, this is `"core"`.
|
||||
///
|
||||
/// [anonymous]: TypePath#anonymity
|
||||
fn crate_name() -> Option<&'static str> {
|
||||
|
@ -114,7 +116,7 @@ pub trait TypePath: 'static {
|
|||
|
||||
/// Returns the path to the module the type is in, or [`None`] if it is [anonymous].
|
||||
///
|
||||
/// For `Option<PhantomData>`, this is `"core::option"`.
|
||||
/// For `Option<Vec<usize>>`, this is `"core::option"`.
|
||||
///
|
||||
/// [anonymous]: TypePath#anonymity
|
||||
fn module_path() -> Option<&'static str> {
|
||||
|
@ -123,6 +125,10 @@ pub trait TypePath: 'static {
|
|||
}
|
||||
|
||||
/// Dynamic dispatch for [`TypePath`].
|
||||
///
|
||||
/// Since this is a supertrait of [`Reflect`] its methods can be called on a `dyn Reflect`.
|
||||
///
|
||||
/// [`Reflect`]: crate::Reflect
|
||||
pub trait DynamicTypePath {
|
||||
/// See [`TypePath::type_path`].
|
||||
fn reflect_type_path(&self) -> &str;
|
||||
|
@ -161,3 +167,60 @@ impl<T: TypePath> DynamicTypePath for T {
|
|||
Self::module_path()
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides dynamic access to all methods on [`TypePath`].
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TypePathTable {
|
||||
// Cache the type path as it is likely the only one that will be used.
|
||||
type_path: &'static str,
|
||||
short_type_path: fn() -> &'static str,
|
||||
type_ident: fn() -> Option<&'static str>,
|
||||
crate_name: fn() -> Option<&'static str>,
|
||||
module_path: fn() -> Option<&'static str>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for TypePathTable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TypePathVtable")
|
||||
.field("type_path", &self.type_path)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl TypePathTable {
|
||||
/// Creates a new table from a type.
|
||||
pub fn of<T: TypePath + ?Sized>() -> Self {
|
||||
Self {
|
||||
type_path: T::type_path(),
|
||||
short_type_path: T::short_type_path,
|
||||
type_ident: T::type_ident,
|
||||
crate_name: T::crate_name,
|
||||
module_path: T::module_path,
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`TypePath::type_path`].
|
||||
pub fn path(&self) -> &'static str {
|
||||
self.type_path
|
||||
}
|
||||
|
||||
/// See [`TypePath::short_type_path`].
|
||||
pub fn short_path(&self) -> &'static str {
|
||||
(self.short_type_path)()
|
||||
}
|
||||
|
||||
/// See [`TypePath::type_ident`].
|
||||
pub fn ident(&self) -> Option<&'static str> {
|
||||
(self.type_ident)()
|
||||
}
|
||||
|
||||
/// See [`TypePath::crate_name`].
|
||||
pub fn crate_name(&self) -> Option<&'static str> {
|
||||
(self.crate_name)()
|
||||
}
|
||||
|
||||
/// See [`TypePath::module_path`].
|
||||
pub fn module_path(&self) -> Option<&'static str> {
|
||||
(self.module_path)()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{serde::Serializable, Reflect, TypeInfo, Typed};
|
||||
use crate::{serde::Serializable, Reflect, TypeInfo, TypePath, Typed};
|
||||
use bevy_ptr::{Ptr, PtrMut};
|
||||
use bevy_utils::{HashMap, HashSet};
|
||||
use downcast_rs::{impl_downcast, Downcast};
|
||||
|
@ -23,9 +23,9 @@ use std::{
|
|||
/// [crate-level documentation]: crate
|
||||
pub struct TypeRegistry {
|
||||
registrations: HashMap<TypeId, TypeRegistration>,
|
||||
short_name_to_id: HashMap<String, TypeId>,
|
||||
full_name_to_id: HashMap<String, TypeId>,
|
||||
ambiguous_names: HashSet<String>,
|
||||
short_path_to_id: HashMap<&'static str, TypeId>,
|
||||
type_path_to_id: HashMap<&'static str, TypeId>,
|
||||
ambiguous_names: HashSet<&'static str>,
|
||||
}
|
||||
|
||||
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't
|
||||
|
@ -41,7 +41,7 @@ impl Debug for TypeRegistryArc {
|
|||
self.internal
|
||||
.read()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.full_name_to_id
|
||||
.type_path_to_id
|
||||
.keys()
|
||||
.fmt(f)
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ impl TypeRegistry {
|
|||
pub fn empty() -> Self {
|
||||
Self {
|
||||
registrations: Default::default(),
|
||||
short_name_to_id: Default::default(),
|
||||
full_name_to_id: Default::default(),
|
||||
short_path_to_id: Default::default(),
|
||||
type_path_to_id: Default::default(),
|
||||
ambiguous_names: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -118,19 +118,19 @@ impl TypeRegistry {
|
|||
return;
|
||||
}
|
||||
|
||||
let short_name = registration.short_name.to_string();
|
||||
if self.short_name_to_id.contains_key(&short_name)
|
||||
|| self.ambiguous_names.contains(&short_name)
|
||||
let short_name = registration.type_info().type_path_table().short_path();
|
||||
if self.short_path_to_id.contains_key(short_name)
|
||||
|| self.ambiguous_names.contains(short_name)
|
||||
{
|
||||
// name is ambiguous. fall back to long names for all ambiguous types
|
||||
self.short_name_to_id.remove(&short_name);
|
||||
self.short_path_to_id.remove(short_name);
|
||||
self.ambiguous_names.insert(short_name);
|
||||
} else {
|
||||
self.short_name_to_id
|
||||
self.short_path_to_id
|
||||
.insert(short_name, registration.type_id());
|
||||
}
|
||||
self.full_name_to_id
|
||||
.insert(registration.type_name().to_string(), registration.type_id());
|
||||
self.type_path_to_id
|
||||
.insert(registration.type_info().type_path(), registration.type_id());
|
||||
self.registrations
|
||||
.insert(registration.type_id(), registration);
|
||||
}
|
||||
|
@ -151,11 +151,11 @@ impl TypeRegistry {
|
|||
/// type_registry.register_type_data::<Option<String>, ReflectSerialize>();
|
||||
/// type_registry.register_type_data::<Option<String>, ReflectDeserialize>();
|
||||
/// ```
|
||||
pub fn register_type_data<T: Reflect + 'static, D: TypeData + FromType<T>>(&mut self) {
|
||||
pub fn register_type_data<T: Reflect + TypePath, D: TypeData + FromType<T>>(&mut self) {
|
||||
let data = self.get_mut(TypeId::of::<T>()).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::<T>(),
|
||||
T = T::type_path(),
|
||||
D = std::any::type_name::<D>(),
|
||||
)
|
||||
});
|
||||
|
@ -183,48 +183,56 @@ impl TypeRegistry {
|
|||
}
|
||||
|
||||
/// Returns a reference to the [`TypeRegistration`] of the type with the
|
||||
/// given name.
|
||||
/// given [type path].
|
||||
///
|
||||
/// If no type with the given name has been registered, returns `None`.
|
||||
pub fn get_with_name(&self, type_name: &str) -> Option<&TypeRegistration> {
|
||||
self.full_name_to_id
|
||||
.get(type_name)
|
||||
/// If no type with the given path has been registered, returns `None`.
|
||||
///
|
||||
/// [type path]: TypePath::type_path
|
||||
pub fn get_with_type_path(&self, type_path: &str) -> Option<&TypeRegistration> {
|
||||
self.type_path_to_id
|
||||
.get(type_path)
|
||||
.and_then(|id| self.get(*id))
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
|
||||
/// the given name.
|
||||
/// the given [type path].
|
||||
///
|
||||
/// If no type with the given name has been registered, returns `None`.
|
||||
pub fn get_with_name_mut(&mut self, type_name: &str) -> Option<&mut TypeRegistration> {
|
||||
self.full_name_to_id
|
||||
.get(type_name)
|
||||
/// If no type with the given type path has been registered, returns `None`.
|
||||
///
|
||||
/// [type path]: TypePath::type_path
|
||||
pub fn get_with_type_path_mut(&mut self, type_path: &str) -> Option<&mut TypeRegistration> {
|
||||
self.type_path_to_id
|
||||
.get(type_path)
|
||||
.cloned()
|
||||
.and_then(move |id| self.get_mut(id))
|
||||
}
|
||||
|
||||
/// Returns a reference to the [`TypeRegistration`] of the type with
|
||||
/// the given short name.
|
||||
/// the given [short type path].
|
||||
///
|
||||
/// If the short name is ambiguous, or if no type with the given short name
|
||||
/// If the short type path is ambiguous, or if no type with the given path
|
||||
/// has been registered, returns `None`.
|
||||
pub fn get_with_short_name(&self, short_type_name: &str) -> Option<&TypeRegistration> {
|
||||
self.short_name_to_id
|
||||
.get(short_type_name)
|
||||
///
|
||||
/// [type path]: TypePath::short_type_path
|
||||
pub fn get_with_short_type_path(&self, short_type_path: &str) -> Option<&TypeRegistration> {
|
||||
self.short_path_to_id
|
||||
.get(short_type_path)
|
||||
.and_then(|id| self.registrations.get(id))
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
|
||||
/// the given short name.
|
||||
/// the given [short type path].
|
||||
///
|
||||
/// If the short name is ambiguous, or if no type with the given short name
|
||||
/// If the short type path is ambiguous, or if no type with the given path
|
||||
/// has been registered, returns `None`.
|
||||
pub fn get_with_short_name_mut(
|
||||
///
|
||||
/// [type path]: TypePath::short_type_path
|
||||
pub fn get_with_short_type_path_mut(
|
||||
&mut self,
|
||||
short_type_name: &str,
|
||||
short_type_path: &str,
|
||||
) -> Option<&mut TypeRegistration> {
|
||||
self.short_name_to_id
|
||||
.get(short_type_name)
|
||||
self.short_path_to_id
|
||||
.get(short_type_path)
|
||||
.and_then(|id| self.registrations.get_mut(id))
|
||||
}
|
||||
|
||||
|
@ -292,7 +300,7 @@ impl TypeRegistryArc {
|
|||
/// but is more often automatically generated using [`#[derive(Reflect)]`](derive@crate::Reflect) which itself generates
|
||||
/// an implementation of the [`GetTypeRegistration`] trait.
|
||||
///
|
||||
/// Along with the type's [`TypeInfo`] and [short name],
|
||||
/// Along with the type's [`TypeInfo`],
|
||||
/// this struct also contains a type's registered [`TypeData`].
|
||||
///
|
||||
/// See the [crate-level documentation] for more information on type registration.
|
||||
|
@ -303,17 +311,15 @@ impl TypeRegistryArc {
|
|||
/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault, FromType};
|
||||
/// let mut registration = TypeRegistration::of::<Option<String>>();
|
||||
///
|
||||
/// assert_eq!("core::option::Option<alloc::string::String>", registration.type_name());
|
||||
/// assert_eq!("Option<String>", registration.short_name());
|
||||
/// assert_eq!("core::option::Option<alloc::string::String>", registration.type_info().type_path());
|
||||
/// assert_eq!("Option<String>", registration.type_info().type_path_table().short_path());
|
||||
///
|
||||
/// registration.insert::<ReflectDefault>(FromType::<Option<String>>::from_type());
|
||||
/// assert!(registration.data::<ReflectDefault>().is_some())
|
||||
/// ```
|
||||
///
|
||||
/// [short name]: bevy_utils::get_short_name
|
||||
/// [crate-level documentation]: crate
|
||||
pub struct TypeRegistration {
|
||||
short_name: String,
|
||||
data: HashMap<TypeId, Box<dyn TypeData>>,
|
||||
type_info: &'static TypeInfo,
|
||||
}
|
||||
|
@ -321,7 +327,6 @@ pub struct TypeRegistration {
|
|||
impl Debug for TypeRegistration {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("TypeRegistration")
|
||||
.field("short_name", &self.short_name)
|
||||
.field("type_info", &self.type_info)
|
||||
.finish()
|
||||
}
|
||||
|
@ -369,28 +374,12 @@ impl TypeRegistration {
|
|||
}
|
||||
|
||||
/// Creates type registration information for `T`.
|
||||
pub fn of<T: Reflect + Typed>() -> Self {
|
||||
let type_name = std::any::type_name::<T>();
|
||||
pub fn of<T: Reflect + Typed + TypePath>() -> Self {
|
||||
Self {
|
||||
data: HashMap::default(),
|
||||
short_name: bevy_utils::get_short_name(type_name),
|
||||
type_info: T::type_info(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [short name] of the type.
|
||||
///
|
||||
/// [short name]: bevy_utils::get_short_name
|
||||
pub fn short_name(&self) -> &str {
|
||||
&self.short_name
|
||||
}
|
||||
|
||||
/// Returns the [name] of the type.
|
||||
///
|
||||
/// [name]: std::any::type_name
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
self.type_info.type_name()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TypeRegistration {
|
||||
|
@ -402,7 +391,6 @@ impl Clone for TypeRegistration {
|
|||
|
||||
TypeRegistration {
|
||||
data,
|
||||
short_name: self.short_name.clone(),
|
||||
type_info: self.type_info,
|
||||
}
|
||||
}
|
||||
|
@ -455,7 +443,7 @@ impl<T: Reflect + erased_serde::Serialize> FromType<T> for ReflectSerialize {
|
|||
ReflectSerialize {
|
||||
get_serializable: |value| {
|
||||
let value = value.downcast_ref::<T>().unwrap_or_else(|| {
|
||||
panic!("ReflectSerialize::get_serialize called with type `{}`, even though it was created for `{}`", value.type_name(), std::any::type_name::<T>())
|
||||
panic!("ReflectSerialize::get_serialize called with type `{}`, even though it was created for `{}`", value.reflect_type_path(), std::any::type_name::<T>())
|
||||
});
|
||||
Serializable::Borrowed(value)
|
||||
},
|
||||
|
@ -611,9 +599,8 @@ impl<T: Reflect> FromType<T> for ReflectFromPtr {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{GetTypeRegistration, ReflectFromPtr, TypeRegistration};
|
||||
use crate::{GetTypeRegistration, ReflectFromPtr};
|
||||
use bevy_ptr::{Ptr, PtrMut};
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
use crate as bevy_reflect;
|
||||
use crate::Reflect;
|
||||
|
@ -658,37 +645,4 @@ mod test {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_property_type_registration() {
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<Option<f64>>().short_name,
|
||||
"Option<f64>"
|
||||
);
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<HashMap<u32, String>>().short_name,
|
||||
"HashMap<u32, String>"
|
||||
);
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<Option<HashMap<u32, String>>>().short_name,
|
||||
"Option<HashMap<u32, String>>"
|
||||
);
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<Option<HashMap<u32, Option<String>>>>().short_name,
|
||||
"Option<HashMap<u32, Option<String>>>"
|
||||
);
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<Option<HashMap<String, Option<String>>>>().short_name,
|
||||
"Option<HashMap<String, Option<String>>>"
|
||||
);
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<Option<HashMap<Option<String>, Option<String>>>>().short_name,
|
||||
"Option<HashMap<Option<String>, Option<String>>>"
|
||||
);
|
||||
assert_eq!(
|
||||
TypeRegistration::of::<Option<HashMap<Option<String>, (String, Option<String>)>>>()
|
||||
.short_name,
|
||||
"Option<HashMap<Option<String>, (String, Option<String>)>>"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,14 +62,16 @@ mod sealed {
|
|||
/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
|
||||
/// CELL.get_or_set(|| {
|
||||
/// let fields = [NamedField::new::<i32>("bar")];
|
||||
/// let info = StructInfo::new::<Self>("Foo", &fields);
|
||||
/// let info = StructInfo::new::<Self>(&fields);
|
||||
/// TypeInfo::Struct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # impl TypePath for Foo {
|
||||
/// # fn type_path() -> &'static str { todo!() }
|
||||
/// # fn short_type_path() -> &'static str { todo!() }
|
||||
/// # }
|
||||
/// # impl Reflect for Foo {
|
||||
/// # fn type_name(&self) -> &str { todo!() }
|
||||
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
|
||||
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
|
||||
/// # fn as_any(&self) -> &dyn Any { todo!() }
|
||||
|
@ -84,11 +86,6 @@ mod sealed {
|
|||
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
|
||||
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
|
||||
/// # }
|
||||
|
||||
/// # impl TypePath for Foo {
|
||||
/// # fn type_path() -> &'static str { todo!() }
|
||||
/// # fn short_type_path() -> &'static str { todo!() }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`TypePath`]: crate::TypePath
|
||||
|
@ -133,19 +130,21 @@ impl<T: TypedProperty> NonGenericTypeCell<T> {
|
|||
///
|
||||
/// struct Foo<T>(T);
|
||||
///
|
||||
/// impl<T: Reflect> Typed for Foo<T> {
|
||||
/// impl<T: Reflect + TypePath> Typed for Foo<T> {
|
||||
/// fn type_info() -> &'static TypeInfo {
|
||||
/// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
/// CELL.get_or_insert::<Self, _>(|| {
|
||||
/// let fields = [UnnamedField::new::<T>(0)];
|
||||
/// let info = TupleStructInfo::new::<Self>("Foo", &fields);
|
||||
/// let info = TupleStructInfo::new::<Self>(&fields);
|
||||
/// TypeInfo::TupleStruct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # impl<T: Reflect> Reflect for Foo<T> {
|
||||
/// # fn type_name(&self) -> &str { todo!() }
|
||||
/// # impl<T: TypePath> TypePath for Foo<T> {
|
||||
/// # fn type_path() -> &'static str { todo!() }
|
||||
/// # fn short_type_path() -> &'static str { todo!() }
|
||||
/// # }
|
||||
/// # impl<T: Reflect + TypePath> Reflect for Foo<T> {
|
||||
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
|
||||
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
|
||||
/// # fn as_any(&self) -> &dyn Any { todo!() }
|
||||
|
@ -160,22 +159,18 @@ impl<T: TypedProperty> NonGenericTypeCell<T> {
|
|||
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
|
||||
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
|
||||
/// # }
|
||||
/// # impl<T: Reflect> TypePath for Foo<T> {
|
||||
/// # fn type_path() -> &'static str { todo!() }
|
||||
/// # fn short_type_path() -> &'static str { todo!() }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Implementing [`TypePath`] with generics.
|
||||
///
|
||||
/// ```
|
||||
/// # use std::any::Any;
|
||||
/// # use bevy_reflect::{DynamicTypePath, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath};
|
||||
/// # use bevy_reflect::TypePath;
|
||||
/// use bevy_reflect::utility::GenericTypePathCell;
|
||||
///
|
||||
/// struct Foo<T>(T);
|
||||
///
|
||||
/// impl<T: Reflect + TypePath> TypePath for Foo<T> {
|
||||
/// impl<T: TypePath> TypePath for Foo<T> {
|
||||
/// fn type_path() -> &'static str {
|
||||
/// static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
/// CELL.get_or_insert::<Self, _>(|| format!("my_crate::foo::Foo<{}>", T::type_path()))
|
||||
|
@ -185,24 +180,19 @@ impl<T: TypedProperty> NonGenericTypeCell<T> {
|
|||
/// static CELL: GenericTypePathCell = GenericTypePathCell::new();
|
||||
/// CELL.get_or_insert::<Self, _>(|| format!("Foo<{}>", T::short_type_path()))
|
||||
/// }
|
||||
///
|
||||
/// fn type_ident() -> Option<&'static str> {
|
||||
/// Some("Foo")
|
||||
/// }
|
||||
///
|
||||
/// fn module_path() -> Option<&'static str> {
|
||||
/// Some("my_crate::foo")
|
||||
/// }
|
||||
///
|
||||
/// fn crate_name() -> Option<&'static str> {
|
||||
/// Some("my_crate")
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # impl<T: Reflect + TypePath> Reflect for Foo<T> {
|
||||
/// # fn type_name(&self) -> &str { todo!() }
|
||||
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
|
||||
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
|
||||
/// # fn as_any(&self) -> &dyn Any { todo!() }
|
||||
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
|
||||
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
|
||||
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
|
||||
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
|
||||
/// # fn apply(&mut self, value: &dyn Reflect) { todo!() }
|
||||
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
|
||||
/// # fn reflect_ref(&self) -> ReflectRef { todo!() }
|
||||
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
|
||||
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
|
||||
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
|
||||
/// # }
|
||||
/// ```
|
||||
/// [`impl_type_path`]: crate::impl_type_path
|
||||
/// [`TypePath`]: crate::TypePath
|
||||
|
|
|
@ -73,14 +73,19 @@ impl DynamicScene {
|
|||
let type_registry = type_registry.read();
|
||||
|
||||
for resource in &self.resources {
|
||||
let registration = type_registry
|
||||
.get_with_name(resource.type_name())
|
||||
.ok_or_else(|| SceneSpawnError::UnregisteredType {
|
||||
type_name: resource.type_name().to_string(),
|
||||
})?;
|
||||
let type_info = resource.get_represented_type_info().ok_or_else(|| {
|
||||
SceneSpawnError::NoRepresentedType {
|
||||
type_path: resource.reflect_type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
let registration = type_registry.get(type_info.type_id()).ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredButReflectedType {
|
||||
type_path: type_info.type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
let reflect_resource = registration.data::<ReflectResource>().ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredResource {
|
||||
type_name: resource.type_name().to_string(),
|
||||
type_path: type_info.type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
|
||||
|
@ -106,15 +111,20 @@ impl DynamicScene {
|
|||
|
||||
// Apply/ add each component to the given entity.
|
||||
for component in &scene_entity.components {
|
||||
let registration = type_registry
|
||||
.get_with_name(component.type_name())
|
||||
.ok_or_else(|| SceneSpawnError::UnregisteredType {
|
||||
type_name: component.type_name().to_string(),
|
||||
})?;
|
||||
let type_info = component.get_represented_type_info().ok_or_else(|| {
|
||||
SceneSpawnError::NoRepresentedType {
|
||||
type_path: component.reflect_type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
let registration = type_registry.get(type_info.type_id()).ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredButReflectedType {
|
||||
type_path: type_info.type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
let reflect_component =
|
||||
registration.data::<ReflectComponent>().ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredComponent {
|
||||
type_name: component.type_name().to_string(),
|
||||
type_path: type_info.type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
|
||||
|
|
|
@ -82,11 +82,11 @@ impl Scene {
|
|||
type_registry
|
||||
.get(type_id)
|
||||
.ok_or_else(|| SceneSpawnError::UnregisteredType {
|
||||
type_name: component_info.name().to_string(),
|
||||
std_type_name: component_info.name().to_string(),
|
||||
})?;
|
||||
let reflect_resource = registration.data::<ReflectResource>().ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredResource {
|
||||
type_name: component_info.name().to_string(),
|
||||
type_path: registration.type_info().type_path().to_string(),
|
||||
}
|
||||
})?;
|
||||
reflect_resource.copy(&self.world, world);
|
||||
|
@ -108,12 +108,12 @@ impl Scene {
|
|||
let reflect_component = type_registry
|
||||
.get(component_info.type_id().unwrap())
|
||||
.ok_or_else(|| SceneSpawnError::UnregisteredType {
|
||||
type_name: component_info.name().to_string(),
|
||||
std_type_name: component_info.name().to_string(),
|
||||
})
|
||||
.and_then(|registration| {
|
||||
registration.data::<ReflectComponent>().ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredComponent {
|
||||
type_name: component_info.name().to_string(),
|
||||
type_path: registration.type_info().type_path().to_string(),
|
||||
}
|
||||
})
|
||||
})?;
|
||||
|
|
|
@ -74,22 +74,42 @@ pub struct SceneSpawner {
|
|||
#[derive(Error, Debug)]
|
||||
pub enum SceneSpawnError {
|
||||
/// Scene contains an unregistered component type.
|
||||
#[error("scene contains the unregistered component `{type_name}`. consider adding `#[reflect(Component)]` to your type")]
|
||||
#[error("scene contains the unregistered component `{type_path}`. consider adding `#[reflect(Component)]` to your type")]
|
||||
UnregisteredComponent {
|
||||
/// Type of the unregistered component.
|
||||
type_name: String,
|
||||
type_path: String,
|
||||
},
|
||||
/// Scene contains an unregistered resource type.
|
||||
#[error("scene contains the unregistered resource `{type_name}`. consider adding `#[reflect(Resource)]` to your type")]
|
||||
#[error("scene contains the unregistered resource `{type_path}`. consider adding `#[reflect(Resource)]` to your type")]
|
||||
UnregisteredResource {
|
||||
/// Type of the unregistered resource.
|
||||
type_name: String,
|
||||
type_path: String,
|
||||
},
|
||||
/// Scene contains an unregistered type.
|
||||
#[error("scene contains the unregistered type `{type_name}`. consider registering the type using `app.register_type::<T>()`")]
|
||||
#[error(
|
||||
"scene contains the unregistered type `{std_type_name}`. \
|
||||
consider reflecting it with `#[derive(Reflect)]` \
|
||||
and registering the type using `app.register_type::<T>()`"
|
||||
)]
|
||||
UnregisteredType {
|
||||
/// The [type name] for the unregistered type.
|
||||
/// [type name]: std::any::type_name
|
||||
std_type_name: String,
|
||||
},
|
||||
/// Scene contains an unregistered type which has a `TypePath`.
|
||||
#[error(
|
||||
"scene contains the reflected type `{type_path}` but it was not found in the type registry. \
|
||||
consider registering the type using `app.register_type::<T>()``"
|
||||
)]
|
||||
UnregisteredButReflectedType {
|
||||
/// The unregistered type.
|
||||
type_name: String,
|
||||
type_path: String,
|
||||
},
|
||||
/// Scene contains a proxy without a represented type.
|
||||
#[error("scene contains dynamic type `{type_path}` without a represented type. consider changing this using `set_represented_type`.")]
|
||||
NoRepresentedType {
|
||||
/// The dynamic instance type.
|
||||
type_path: String,
|
||||
},
|
||||
/// Dynamic scene with the given id does not exist.
|
||||
#[error("scene does not exist")]
|
||||
|
|
|
@ -181,7 +181,7 @@ impl<'a> Serialize for SceneMapSerializer<'a> {
|
|||
let mut state = serializer.serialize_map(Some(self.entries.len()))?;
|
||||
for reflect in self.entries {
|
||||
state.serialize_entry(
|
||||
reflect.type_name(),
|
||||
reflect.get_represented_type_info().unwrap().type_path(),
|
||||
&TypedReflectSerializer::new(&**reflect, &self.registry.read()),
|
||||
)?;
|
||||
}
|
||||
|
@ -467,7 +467,7 @@ impl<'a, 'de> Visitor<'de> for SceneMapVisitor<'a> {
|
|||
if !added.insert(registration.type_id()) {
|
||||
return Err(Error::custom(format_args!(
|
||||
"duplicate reflect type: `{}`",
|
||||
registration.type_name()
|
||||
registration.type_info().type_path(),
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -887,9 +887,15 @@ mod tests {
|
|||
let received = received
|
||||
.components
|
||||
.iter()
|
||||
.find(|component| component.type_name() == expected.type_name())
|
||||
.find(|component| {
|
||||
component.get_represented_type_info().unwrap().type_path()
|
||||
== expected.get_represented_type_info().unwrap().type_path()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
panic!("missing component (expected: `{}`)", expected.type_name())
|
||||
panic!(
|
||||
"missing component (expected: `{}`)",
|
||||
expected.get_represented_type_info().unwrap().type_path()
|
||||
)
|
||||
});
|
||||
|
||||
assert!(
|
||||
|
|
|
@ -21,7 +21,10 @@ fn setup(type_registry: Res<AppTypeRegistry>) {
|
|||
let type_registry = type_registry.read();
|
||||
|
||||
let registration = type_registry.get(TypeId::of::<MyType<u32>>()).unwrap();
|
||||
info!("Registration for {} exists", registration.short_name());
|
||||
info!(
|
||||
"Registration for {} exists",
|
||||
registration.type_info().type_path(),
|
||||
);
|
||||
|
||||
// MyType<String> was not manually registered, so it does not exist
|
||||
assert!(type_registry.get(TypeId::of::<MyType<String>>()).is_none());
|
||||
|
|
Loading…
Reference in a new issue