From ed5e997103555bed274820cccd0093917bb13a97 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Fri, 25 Feb 2022 16:52:05 -0800 Subject: [PATCH 01/44] Added TypeInfo --- .../bevy_reflect_derive/src/lib.rs | 35 +++++++++ crates/bevy_reflect/src/fields.rs | 53 +++++++++++++ crates/bevy_reflect/src/impls/smallvec.rs | 12 ++- crates/bevy_reflect/src/impls/std.rs | 24 ++++-- crates/bevy_reflect/src/lib.rs | 5 ++ crates/bevy_reflect/src/list.rs | 41 +++++++++- crates/bevy_reflect/src/map.rs | 42 +++++++++- crates/bevy_reflect/src/reflect.rs | 5 +- crates/bevy_reflect/src/struct_trait.rs | 76 ++++++++++++++++++- crates/bevy_reflect/src/tuple.rs | 60 ++++++++++++++- crates/bevy_reflect/src/tuple_struct.rs | 51 ++++++++++++- crates/bevy_reflect/src/type_info.rs | 65 ++++++++++++++++ crates/bevy_reflect/src/type_registry.rs | 18 ++++- 13 files changed, 474 insertions(+), 13 deletions(-) create mode 100644 crates/bevy_reflect/src/fields.rs create mode 100644 crates/bevy_reflect/src/type_info.rs diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 8128b292b8559..f3a0985aebfd0 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -189,6 +189,12 @@ fn impl_struct( .unwrap_or_else(|| Member::Unnamed(Index::from(*index))) }) .collect::>(); + let field_types = active_fields + .iter() + .map(|(field, _index)| { + field.ty.clone() + }) + .collect::>(); let field_count = active_fields.len(); let field_indices = (0..field_count).collect::>(); @@ -317,6 +323,15 @@ fn impl_struct( fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { #partial_eq_fn } + + fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { + let name = std::any::type_name::(); + let fields: [(&str, &str); #field_count] = [ + #((#field_names, std::any::type_name::<#field_types>()),)* + ]; + let info = #bevy_reflect_path::StructInfo::new(name, fields); + #bevy_reflect_path::TypeInfo::Struct(info) + } } }) } @@ -333,6 +348,12 @@ fn impl_tuple_struct( .iter() .map(|(_field, index)| Member::Unnamed(Index::from(*index))) .collect::>(); + let field_types = active_fields + .iter() + .map(|(field, _index)| { + field.ty.clone() + }) + .collect::>(); let field_count = active_fields.len(); let field_indices = (0..field_count).collect::>(); @@ -438,6 +459,15 @@ fn impl_tuple_struct( fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { #partial_eq_fn } + + fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { + let name = std::any::type_name::(); + let fields: [&str; #field_count] = [ + #(std::any::type_name::<#field_types>(),)* + ]; + let info = #bevy_reflect_path::TupleStructInfo::new(name, fields); + #bevy_reflect_path::TypeInfo::TupleStruct(info) + } } }) } @@ -514,6 +544,11 @@ fn impl_value( fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> { #serialize_fn } + + fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { + let info = #bevy_reflect_path::ValueInfo::new::(); + #bevy_reflect_path::TypeInfo::Value(info) + } } }) } diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs new file mode 100644 index 0000000000000..94afbc4d6220b --- /dev/null +++ b/crates/bevy_reflect/src/fields.rs @@ -0,0 +1,53 @@ +use std::borrow::{Borrow, Cow}; + +/// The named field of a struct +#[derive(Clone, Debug)] +pub struct NamedField { + name: Cow<'static, str>, + type_name: Cow<'static, str>, +} + +impl NamedField { + pub fn new>(name: I, type_name: I) -> Self { + Self { + name: Cow::Owned(name.into()), + type_name: Cow::Owned(type_name.into()), + } + } + + /// Returns the name of the field + pub fn name(&self) -> &str { + self.name.borrow() + } + + /// Returns the type of the field + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } +} + +/// The unnamed field of a tuple or tuple struct +#[derive(Clone, Debug)] +pub struct UnnamedField { + index: usize, + type_name: Cow<'static, str>, +} + +impl UnnamedField { + pub fn new>(index: usize, type_name: I) -> Self { + Self { + index, + type_name: Cow::Owned(type_name.into()), + } + } + + /// Returns the index of the field + pub fn index(&self) -> usize { + self.index + } + + /// Returns the type of the field + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } +} diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 4d6417c6df068..1e622343f28c8 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,7 +1,10 @@ use smallvec::{Array, SmallVec}; use std::any::Any; -use crate::{serde::Serializable, FromReflect, List, ListIter, Reflect, ReflectMut, ReflectRef}; +use crate::{ + serde::Serializable, FromReflect, List, ListInfo, ListIter, Reflect, ReflectMut, ReflectRef, + TypeInfo, +}; impl List for SmallVec where @@ -96,6 +99,13 @@ where fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo + where + Self: Sized, + { + TypeInfo::List(ListInfo::new::(Some(T::size()))) + } } impl FromReflect for SmallVec diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 0b1d4097e1e11..45a7ee6ebedf4 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,9 +1,5 @@ use crate as bevy_reflect; -use crate::{ - map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, - List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, - TypeRegistration, -}; +use crate::{map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, ValueInfo}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; @@ -142,6 +138,13 @@ unsafe impl Reflect for Vec { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo + where + Self: Sized, + { + TypeInfo::List(ListInfo::new::(None)) + } } impl Deserialize<'de>> GetTypeRegistration for Vec { @@ -260,6 +263,13 @@ unsafe impl Reflect for HashMap { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo + where + Self: Sized, + { + TypeInfo::Map(MapInfo::new::()) + } } impl GetTypeRegistration for HashMap @@ -349,6 +359,10 @@ unsafe impl Reflect for Cow<'static, str> { fn serializable(&self) -> Option { Some(Serializable::Borrowed(self)) } + + fn type_info() -> TypeInfo where Self: Sized { + TypeInfo::Value(ValueInfo::new::()) + } } impl GetTypeRegistration for Cow<'static, str> { diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index cd479d1e07dec..89ea600aaeed7 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1,5 +1,6 @@ #![doc = include_str!("../README.md")] +mod fields; mod list; mod map; mod path; @@ -7,6 +8,7 @@ mod reflect; mod struct_trait; mod tuple; mod tuple_struct; +mod type_info; mod type_registry; mod type_uuid; mod impls { @@ -24,6 +26,7 @@ mod impls { } pub mod serde; + pub mod prelude { #[doc(hidden)] pub use crate::{ @@ -32,6 +35,7 @@ pub mod prelude { }; } +pub use fields::*; pub use impls::*; pub use list::*; pub use map::*; @@ -40,6 +44,7 @@ pub use reflect::*; pub use struct_trait::*; pub use tuple::*; pub use tuple_struct::*; +pub use type_info::*; pub use type_registry::*; pub use type_uuid::*; diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index d9572cd1b42db..a9a1fb91f70a1 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,6 +1,7 @@ use std::any::Any; +use std::borrow::{Borrow, Cow}; -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; +use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef, FromReflect, TypeInfo, DynamicInfo}; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. pub trait List: Reflect { @@ -33,6 +34,40 @@ pub trait List: Reflect { } } +/// A container for compile-time list info +#[derive(Clone, Debug)] +pub struct ListInfo { + name: Cow<'static, str>, + item_type: Cow<'static, str>, + capacity: Option, +} + +impl ListInfo { + /// Create a new [`ListInfo`] + pub fn new(capacity: Option) -> Self { + Self { + name: Cow::Owned(std::any::type_name::().to_string()), + item_type: Cow::Owned(std::any::type_name::().to_string()), + capacity + } + } + + /// The name of this list + pub fn name(&self) -> &str { + self.name.borrow() + } + + /// The item type of this list + pub fn item_type(&self) -> &str { + self.item_type.borrow() + } + + /// The compile-time capacity of this list, if any + pub fn capacity(&self) -> Option { + self.capacity + } +} + /// A list of reflected values. #[derive(Default)] pub struct DynamicList { @@ -158,6 +193,10 @@ unsafe impl Reflect for DynamicList { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo where Self: Sized { + TypeInfo::Dynamic(DynamicInfo::new::()) + } } /// An iterator over the elements of a [`List`]. diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 4fdba328c6714..ab2311e8f6b30 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -1,8 +1,10 @@ use std::any::Any; +use std::borrow::{Borrow, Cow}; +use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; +use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef, TypeInfo, DynamicInfo}; /// An ordered mapping between [`Reflect`] values. /// @@ -43,6 +45,40 @@ pub trait Map: Reflect { fn clone_dynamic(&self) -> DynamicMap; } +/// A container for compile-time map info +#[derive(Clone, Debug)] +pub struct MapInfo { + name: Cow<'static, str>, + key_type: Cow<'static, str>, + value_type: Cow<'static, str>, +} + +impl MapInfo { + /// Create a new [`MapInfo`] + pub fn new() -> Self { + Self { + name: Cow::Owned(std::any::type_name::().to_string()), + key_type: Cow::Owned(std::any::type_name::().to_string()), + value_type: Cow::Owned(std::any::type_name::().to_string()), + } + } + + /// The name of this map + pub fn name(&self) -> &str { + self.name.borrow() + } + + /// The key type of this map + pub fn key_type(&self) -> &str { + self.key_type.borrow() + } + + /// The value type of this map + pub fn value_type(&self) -> &str { + self.value_type.borrow() + } +} + const HASH_ERROR: &str = "the given key does not support hashing"; /// An ordered mapping between reflected values. @@ -187,6 +223,10 @@ unsafe impl Reflect for DynamicMap { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo where Self: Sized { + TypeInfo::Dynamic(DynamicInfo::new::()) + } } /// An iterator over the key-value pairs of a [`Map`]. diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 4362068df918e..607a8744f7e63 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,4 +1,4 @@ -use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct}; +use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct, TypeInfo}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; @@ -133,6 +133,9 @@ pub unsafe trait Reflect: Any + Send + Sync { /// /// If the underlying type does not support serialization, returns `None`. fn serializable(&self) -> Option; + + /// Returns the compile-time info for the underlying type + fn type_info() -> TypeInfo where Self: Sized; } /// A trait for types which can be constructed from a reflected type. diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index f8a413e6f6030..502310130afc1 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,5 +1,7 @@ -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; +use crate::{serde::Serializable, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, DynamicInfo}; use bevy_utils::{Entry, HashMap}; +use std::borrow::Borrow; +use std::slice::Iter; use std::{any::Any, borrow::Cow}; /// A reflected Rust regular struct type. @@ -60,6 +62,74 @@ pub trait Struct: Reflect { fn clone_dynamic(&self) -> DynamicStruct; } +/// A container for compile-time struct info +#[derive(Clone, Debug)] +pub struct StructInfo { + name: Cow<'static, str>, + fields: Vec, + field_indices: HashMap, usize>, +} + +impl StructInfo { + /// Create a new [`StructInfo`] + /// + /// # Arguments + /// + /// * `name`: The name of the struct + /// * `fields`: An iterator over the fields. Takes the form: `(field_name, field_type)`. + /// + pub fn new, F: IntoIterator>(name: I, fields: F) -> Self { + let (fields, field_indices): (Vec<_>, HashMap<_, _>) = fields + .into_iter() + .enumerate() + .map(|(index, field)| { + let field_name = field.0.into(); + let field = NamedField::new(field_name.clone(), field.1.into()); + let field_index = (Cow::Owned(field_name), index); + (field, field_index) + }) + .unzip(); + + Self { + name: Cow::Owned(name.into()), + fields, + field_indices, + } + } + + /// The name of this struct + pub fn name(&self) -> &str { + self.name.borrow() + } + + /// Get a field with the given name + pub fn field(&self, name: &str) -> Option<&NamedField> { + self.field_indices + .get(name) + .map(|index| &self.fields[*index]) + } + + /// Get a field at the given index + pub fn field_at(&self, index: usize) -> Option<&NamedField> { + self.fields.get(index) + } + + /// Get the index of a field with the given name + pub fn index_of(&self, name: &str) -> Option { + self.field_indices.get(name).map(|index| *index) + } + + /// Iterate over the fields of this struct + pub fn iter(&self) -> Iter<'_, NamedField> { + self.fields.iter() + } + + /// The total number of fields in this struct + pub fn len(&self) -> usize { + self.fields.len() + } +} + /// An iterator over the field values of a struct. pub struct FieldIter<'a> { pub(crate) struct_val: &'a dyn Struct, @@ -313,6 +383,10 @@ unsafe impl Reflect for DynamicStruct { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo where Self: Sized { + TypeInfo::Dynamic(DynamicInfo::new::()) + } } /// Compares a [`Struct`] with a [`Reflect`] value. diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 1ebec67fdb032..d616cb316213e 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,6 +1,8 @@ use std::any::Any; +use std::borrow::{Borrow, Cow}; +use std::slice::Iter; -use crate::{serde::Serializable, FromReflect, Reflect, ReflectMut, ReflectRef}; +use crate::{serde::Serializable, FromReflect, Reflect, ReflectMut, ReflectRef, UnnamedField, TypeInfo, create_tuple_fields, DynamicInfo}; /// A reflected Rust tuple. /// @@ -120,6 +122,49 @@ impl GetTupleField for dyn Tuple { } } +/// A container for compile-time tuple info +#[derive(Clone, Debug)] +pub struct TupleInfo { + name: Cow<'static, str>, + fields: Vec, +} + +impl TupleInfo { + /// Create a new [`TupleInfo`] + /// + /// # Arguments + /// + /// * `name`: The name of the tuple + /// * `fields`: An iterator over the field types + /// + pub fn new, F: IntoIterator>(name: I, fields: F) -> Self { + Self { + name: Cow::Owned(name.into()), + fields: create_tuple_fields(fields), + } + } + + /// The name of this tuple + pub fn name(&self) -> &str { + self.name.borrow() + } + + /// Get a field at the given index + pub fn field_at(&self, index: usize) -> Option<&UnnamedField> { + self.fields.get(index) + } + + /// Iterate over the fields of this tuple + pub fn iter(&self) -> Iter<'_, UnnamedField> { + self.fields.iter() + } + + /// The total number of fields in this tuple + pub fn len(&self) -> usize { + self.fields.len() + } +} + /// A tuple which allows fields to be added at runtime. #[derive(Default)] pub struct DynamicTuple { @@ -257,6 +302,10 @@ unsafe impl Reflect for DynamicTuple { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo where Self: Sized { + TypeInfo::Dynamic(DynamicInfo::new::()) + } } /// Applies the elements of `b` to the corresponding elements of `a`. @@ -398,6 +447,15 @@ macro_rules! impl_reflect_tuple { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo where Self: Sized { + let name = std::any::type_name::(); + let fields = [ + $(std::any::type_name::<$name>(),)* + ]; + let info = TupleInfo::new(name, fields); + TypeInfo::Tuple(info) + } } impl<$($name: FromReflect),*> FromReflect for ($($name,)*) diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 00e478f5f38e8..ffaec85bb7453 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,5 +1,7 @@ -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; +use crate::{create_tuple_fields, serde::Serializable, Reflect, ReflectMut, ReflectRef, UnnamedField, TypeInfo, DynamicInfo}; use std::any::Any; +use std::borrow::{Borrow, Cow}; +use std::slice::Iter; /// A reflected Rust tuple struct. /// @@ -43,6 +45,49 @@ pub trait TupleStruct: Reflect { fn clone_dynamic(&self) -> DynamicTupleStruct; } +/// A container for compile-time tuple struct info +#[derive(Clone, Debug)] +pub struct TupleStructInfo { + name: Cow<'static, str>, + fields: Vec, +} + +impl TupleStructInfo { + /// Create a new [`TupleStructInfo`] + /// + /// # Arguments + /// + /// * `name`: The name of the tuple struct + /// * `fields`: An iterator over the field types + /// + pub fn new, F: IntoIterator>(name: I, fields: F) -> Self { + Self { + name: Cow::Owned(name.into()), + fields: create_tuple_fields(fields), + } + } + + /// The name of this struct + pub fn name(&self) -> &str { + self.name.borrow() + } + + /// Get a field at the given index + pub fn field_at(&self, index: usize) -> Option<&UnnamedField> { + self.fields.get(index) + } + + /// Iterate over the fields of this struct + pub fn iter(&self) -> Iter<'_, UnnamedField> { + self.fields.iter() + } + + /// The total number of fields in this struct + pub fn len(&self) -> usize { + self.fields.len() + } +} + /// An iterator over the field values of a tuple struct. pub struct TupleStructFieldIter<'a> { pub(crate) tuple_struct: &'a dyn TupleStruct, @@ -252,6 +297,10 @@ unsafe impl Reflect for DynamicTupleStruct { fn serializable(&self) -> Option { None } + + fn type_info() -> TypeInfo where Self: Sized { + TypeInfo::Dynamic(DynamicInfo::new::()) + } } /// Compares a [`TupleStruct`] with a [`Reflect`] value. diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs new file mode 100644 index 0000000000000..b42ca92cbdf78 --- /dev/null +++ b/crates/bevy_reflect/src/type_info.rs @@ -0,0 +1,65 @@ +use std::borrow::{Borrow, Cow}; +use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo, UnnamedField}; + +/// Compile-time type information for various object types +#[derive(Debug, Clone)] +pub enum TypeInfo { + Struct(StructInfo), + TupleStruct(TupleStructInfo), + Tuple(TupleInfo), + List(ListInfo), + Map(MapInfo), + Value(ValueInfo), + /// Type information for "dynamic" types whose metadata can't be known at compile-time + /// + /// This includes structs like [`DynamicStruct`](crate::DynamicStruct) and [`DynamicList`](crate::DynamicList) + Dynamic(DynamicInfo), +} + +/// A container for compile-time info related to general value types, including primitives +#[derive(Debug, Clone)] +pub struct ValueInfo { + name: Cow<'static, str> +} + +impl ValueInfo { + pub fn new() -> Self { + Self { + name: Cow::Owned(std::any::type_name::().to_string()) + } + } + + /// The name of this value + pub fn name(&self) -> &str { + self.name.borrow() + } +} + +#[derive(Debug, Clone)] +pub struct DynamicInfo { + name: Cow<'static, str> +} + +impl DynamicInfo { + pub fn new() -> Self { + Self { + name: Cow::Owned(std::any::type_name::().to_string()) + } + } + + /// The name of this value + pub fn name(&self) -> &str { + self.name.borrow() + } +} + +/// Create a collection of unnamed fields from an iterator of field type names +pub(crate) fn create_tuple_fields, F: IntoIterator>( + fields: F, +) -> Vec { + fields + .into_iter() + .enumerate() + .map(|(index, field)| UnnamedField::new(index, field.into())) + .collect() +} diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index bd313836208cc..6167fd5f6f062 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -1,4 +1,4 @@ -use crate::Reflect; +use crate::{Reflect, TypeInfo}; use bevy_utils::{HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; @@ -129,6 +129,14 @@ impl TypeRegistry { .and_then(|registration| registration.data::()) } + /// Returns the [`TypeInfo`] associated with the given `TypeId`. + /// + /// If the specified type has not been registered, returns `None`. + pub fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo> { + self.get(type_id) + .and_then(|registration| Some(registration.type_info())) + } + /// Returns an iterator overed the [`TypeRegistration`]s of the registered /// types. pub fn iter(&self) -> impl Iterator { @@ -167,6 +175,7 @@ pub struct TypeRegistration { short_name: String, name: &'static str, data: HashMap>, + type_info: TypeInfo, } impl TypeRegistration { @@ -198,6 +207,11 @@ impl TypeRegistration { .and_then(|value| value.downcast_mut()) } + /// Returns a reference to the registration's [`TypeInfo`] + pub fn type_info(&self) -> &TypeInfo { + &self.type_info + } + /// Inserts an instance of `T` into this registration's type data. /// /// If another instance of `T` was previously inserted, it is replaced. @@ -214,6 +228,7 @@ impl TypeRegistration { data: HashMap::default(), name: type_name, short_name: Self::get_short_name(type_name), + type_info: T::type_info(), } } @@ -285,6 +300,7 @@ impl Clone for TypeRegistration { name: self.name, short_name: self.short_name.clone(), type_id: self.type_id, + type_info: self.type_info.clone(), } } } From bfcfa259f811bdb973df5631d8c8aa3e376f27fc Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Fri, 25 Feb 2022 17:34:15 -0800 Subject: [PATCH 02/44] Added tests --- crates/bevy_reflect/src/lib.rs | 102 +++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 89ea600aaeed7..ff750692db092 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -428,4 +428,106 @@ mod tests { std::any::type_name::() ); } + + #[test] + fn reflect_type_info() { + // Struct + #[derive(Reflect)] + struct MyStruct { + foo: i32, + bar: usize, + } + + let info = MyStruct::type_info(); + if let TypeInfo::Struct(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + assert_eq!(std::any::type_name::(), info.field("foo").unwrap().type_name()); + assert_eq!("foo", info.field("foo").unwrap().name()); + assert_eq!(std::any::type_name::(), info.field_at(1).unwrap().type_name()); + } else { + panic!("Expected `TypeInfo::Struct`"); + } + + // Tuple Struct + #[derive(Reflect)] + struct MyTupleStruct(usize, i32, MyStruct); + + let info = MyTupleStruct::type_info(); + if let TypeInfo::TupleStruct(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + assert_eq!(std::any::type_name::(), info.field_at(1).unwrap().type_name()); + } else { + panic!("Expected `TypeInfo::TupleStruct`"); + } + + // Tuple + type MyTuple = (u32, f32, String); + + let info = MyTuple::type_info(); + if let TypeInfo::Tuple(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + assert_eq!(std::any::type_name::(), info.field_at(1).unwrap().type_name()); + } else { + panic!("Expected `TypeInfo::Tuple`"); + } + + // List + type MyList = Vec; + + let info = MyList::type_info(); + if let TypeInfo::List(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + assert_eq!(std::any::type_name::(), info.item_type()); + assert_eq!(None, info.capacity()); + } else { + panic!("Expected `TypeInfo::List`"); + } + + // List (with capacity) + #[cfg(feature = "smallvec")] + { + type MyListWithCapacity = smallvec::SmallVec<[String; 123]>; + + let info = MyListWithCapacity::type_info(); + if let TypeInfo::List(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + assert_eq!(std::any::type_name::(), info.item_type()); + assert_eq!(Some(123usize), info.capacity()); + } else { + panic!("Expected `TypeInfo::List`"); + } + } + + // Map + type MyMap = HashMap; + + let info = MyMap::type_info(); + if let TypeInfo::Map(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + assert_eq!(std::any::type_name::(), info.key_type()); + assert_eq!(std::any::type_name::(), info.value_type()); + } else { + panic!("Expected `TypeInfo::Map`"); + } + + // Value + type MyValue = String; + + let info = MyValue::type_info(); + if let TypeInfo::Value(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + } else { + panic!("Expected `TypeInfo::Value`"); + } + + // Dynamic + type MyDynamic = DynamicList; + + let info = MyDynamic::type_info(); + if let TypeInfo::Dynamic(info) = info { + assert_eq!(std::any::type_name::(), info.name()); + } else { + panic!("Expected `TypeInfo::Dynamic`"); + } + } } From 190dbc2c55f737543ce91ca8fbed19c17904f6bc Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Fri, 25 Feb 2022 17:39:29 -0800 Subject: [PATCH 03/44] Fix clippy warnings --- crates/bevy_reflect/src/struct_trait.rs | 4 ++-- crates/bevy_reflect/src/tuple.rs | 2 +- crates/bevy_reflect/src/tuple_struct.rs | 2 +- crates/bevy_reflect/src/type_registry.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 502310130afc1..dd570ae55c0e9 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -116,7 +116,7 @@ impl StructInfo { /// Get the index of a field with the given name pub fn index_of(&self, name: &str) -> Option { - self.field_indices.get(name).map(|index| *index) + self.field_indices.get(name).copied() } /// Iterate over the fields of this struct @@ -125,7 +125,7 @@ impl StructInfo { } /// The total number of fields in this struct - pub fn len(&self) -> usize { + pub fn field_len(&self) -> usize { self.fields.len() } } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index d616cb316213e..e02eaad51f6ce 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -160,7 +160,7 @@ impl TupleInfo { } /// The total number of fields in this tuple - pub fn len(&self) -> usize { + pub fn field_len(&self) -> usize { self.fields.len() } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index ffaec85bb7453..2334dee9d0462 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -83,7 +83,7 @@ impl TupleStructInfo { } /// The total number of fields in this struct - pub fn len(&self) -> usize { + pub fn field_len(&self) -> usize { self.fields.len() } } diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 6167fd5f6f062..082808e4edd35 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -134,7 +134,7 @@ impl TypeRegistry { /// If the specified type has not been registered, returns `None`. pub fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo> { self.get(type_id) - .and_then(|registration| Some(registration.type_info())) + .map(|registration| registration.type_info()) } /// Returns an iterator overed the [`TypeRegistration`]s of the registered From ea4915233d528de9e2b33a839f2739a3a0adcd2e Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Fri, 25 Feb 2022 17:44:58 -0800 Subject: [PATCH 04/44] Formatting --- .../bevy_reflect_derive/src/lib.rs | 8 ++------ crates/bevy_reflect/src/impls/std.rs | 11 ++++++++-- crates/bevy_reflect/src/lib.rs | 20 +++++++++++++++---- crates/bevy_reflect/src/list.rs | 11 +++++++--- crates/bevy_reflect/src/map.rs | 7 +++++-- crates/bevy_reflect/src/reflect.rs | 4 +++- crates/bevy_reflect/src/struct_trait.rs | 9 +++++++-- crates/bevy_reflect/src/tuple.rs | 10 ++++++++-- crates/bevy_reflect/src/tuple_struct.rs | 10 ++++++++-- crates/bevy_reflect/src/type_info.rs | 10 +++++----- 10 files changed, 71 insertions(+), 29 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index f3a0985aebfd0..b1d9205ffd7d0 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -191,9 +191,7 @@ fn impl_struct( .collect::>(); let field_types = active_fields .iter() - .map(|(field, _index)| { - field.ty.clone() - }) + .map(|(field, _index)| field.ty.clone()) .collect::>(); let field_count = active_fields.len(); let field_indices = (0..field_count).collect::>(); @@ -350,9 +348,7 @@ fn impl_tuple_struct( .collect::>(); let field_types = active_fields .iter() - .map(|(field, _index)| { - field.ty.clone() - }) + .map(|(field, _index)| field.ty.clone()) .collect::>(); let field_count = active_fields.len(); let field_indices = (0..field_count).collect::>(); diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 45a7ee6ebedf4..934989a4d3a92 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,5 +1,9 @@ use crate as bevy_reflect; -use crate::{map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, ValueInfo}; +use crate::{ + map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, + List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, + ReflectRef, TypeInfo, TypeRegistration, ValueInfo, +}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; @@ -360,7 +364,10 @@ unsafe impl Reflect for Cow<'static, str> { Some(Serializable::Borrowed(self)) } - fn type_info() -> TypeInfo where Self: Sized { + fn type_info() -> TypeInfo + where + Self: Sized, + { TypeInfo::Value(ValueInfo::new::()) } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index ff750692db092..e6a1c5b75d5a1 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -441,9 +441,15 @@ mod tests { let info = MyStruct::type_info(); if let TypeInfo::Struct(info) = info { assert_eq!(std::any::type_name::(), info.name()); - assert_eq!(std::any::type_name::(), info.field("foo").unwrap().type_name()); + assert_eq!( + std::any::type_name::(), + info.field("foo").unwrap().type_name() + ); assert_eq!("foo", info.field("foo").unwrap().name()); - assert_eq!(std::any::type_name::(), info.field_at(1).unwrap().type_name()); + assert_eq!( + std::any::type_name::(), + info.field_at(1).unwrap().type_name() + ); } else { panic!("Expected `TypeInfo::Struct`"); } @@ -455,7 +461,10 @@ mod tests { let info = MyTupleStruct::type_info(); if let TypeInfo::TupleStruct(info) = info { assert_eq!(std::any::type_name::(), info.name()); - assert_eq!(std::any::type_name::(), info.field_at(1).unwrap().type_name()); + assert_eq!( + std::any::type_name::(), + info.field_at(1).unwrap().type_name() + ); } else { panic!("Expected `TypeInfo::TupleStruct`"); } @@ -466,7 +475,10 @@ mod tests { let info = MyTuple::type_info(); if let TypeInfo::Tuple(info) = info { assert_eq!(std::any::type_name::(), info.name()); - assert_eq!(std::any::type_name::(), info.field_at(1).unwrap().type_name()); + assert_eq!( + std::any::type_name::(), + info.field_at(1).unwrap().type_name() + ); } else { panic!("Expected `TypeInfo::Tuple`"); } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index a9a1fb91f70a1..678615282a895 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,7 +1,9 @@ use std::any::Any; use std::borrow::{Borrow, Cow}; -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef, FromReflect, TypeInfo, DynamicInfo}; +use crate::{ + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, +}; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. pub trait List: Reflect { @@ -48,7 +50,7 @@ impl ListInfo { Self { name: Cow::Owned(std::any::type_name::().to_string()), item_type: Cow::Owned(std::any::type_name::().to_string()), - capacity + capacity, } } @@ -194,7 +196,10 @@ unsafe impl Reflect for DynamicList { None } - fn type_info() -> TypeInfo where Self: Sized { + fn type_info() -> TypeInfo + where + Self: Sized, + { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index ab2311e8f6b30..857d59e0b2fb1 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -4,7 +4,7 @@ use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef, TypeInfo, DynamicInfo}; +use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo}; /// An ordered mapping between [`Reflect`] values. /// @@ -224,7 +224,10 @@ unsafe impl Reflect for DynamicMap { None } - fn type_info() -> TypeInfo where Self: Sized { + fn type_info() -> TypeInfo + where + Self: Sized, + { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 607a8744f7e63..13835d754abea 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -135,7 +135,9 @@ pub unsafe trait Reflect: Any + Send + Sync { fn serializable(&self) -> Option; /// Returns the compile-time info for the underlying type - fn type_info() -> TypeInfo where Self: Sized; + fn type_info() -> TypeInfo + where + Self: Sized; } /// A trait for types which can be constructed from a reflected type. diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index dd570ae55c0e9..295c014a4542a 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,4 +1,6 @@ -use crate::{serde::Serializable, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, DynamicInfo}; +use crate::{ + serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, +}; use bevy_utils::{Entry, HashMap}; use std::borrow::Borrow; use std::slice::Iter; @@ -384,7 +386,10 @@ unsafe impl Reflect for DynamicStruct { None } - fn type_info() -> TypeInfo where Self: Sized { + fn type_info() -> TypeInfo + where + Self: Sized, + { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index e02eaad51f6ce..f8782ba3428ed 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -2,7 +2,10 @@ use std::any::Any; use std::borrow::{Borrow, Cow}; use std::slice::Iter; -use crate::{serde::Serializable, FromReflect, Reflect, ReflectMut, ReflectRef, UnnamedField, TypeInfo, create_tuple_fields, DynamicInfo}; +use crate::{ + create_tuple_fields, serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, + ReflectRef, TypeInfo, UnnamedField, +}; /// A reflected Rust tuple. /// @@ -303,7 +306,10 @@ unsafe impl Reflect for DynamicTuple { None } - fn type_info() -> TypeInfo where Self: Sized { + fn type_info() -> TypeInfo + where + Self: Sized, + { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 2334dee9d0462..228afc9ab3637 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,4 +1,7 @@ -use crate::{create_tuple_fields, serde::Serializable, Reflect, ReflectMut, ReflectRef, UnnamedField, TypeInfo, DynamicInfo}; +use crate::{ + create_tuple_fields, serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, + TypeInfo, UnnamedField, +}; use std::any::Any; use std::borrow::{Borrow, Cow}; use std::slice::Iter; @@ -298,7 +301,10 @@ unsafe impl Reflect for DynamicTupleStruct { None } - fn type_info() -> TypeInfo where Self: Sized { + fn type_info() -> TypeInfo + where + Self: Sized, + { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index b42ca92cbdf78..9592880c590c9 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -1,5 +1,5 @@ -use std::borrow::{Borrow, Cow}; use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo, UnnamedField}; +use std::borrow::{Borrow, Cow}; /// Compile-time type information for various object types #[derive(Debug, Clone)] @@ -19,13 +19,13 @@ pub enum TypeInfo { /// A container for compile-time info related to general value types, including primitives #[derive(Debug, Clone)] pub struct ValueInfo { - name: Cow<'static, str> + name: Cow<'static, str>, } impl ValueInfo { pub fn new() -> Self { Self { - name: Cow::Owned(std::any::type_name::().to_string()) + name: Cow::Owned(std::any::type_name::().to_string()), } } @@ -37,13 +37,13 @@ impl ValueInfo { #[derive(Debug, Clone)] pub struct DynamicInfo { - name: Cow<'static, str> + name: Cow<'static, str>, } impl DynamicInfo { pub fn new() -> Self { Self { - name: Cow::Owned(std::any::type_name::().to_string()) + name: Cow::Owned(std::any::type_name::().to_string()), } } From 0ec22705d1ae090354f6052aae9a2048e9614c64 Mon Sep 17 00:00:00 2001 From: MrGVSV <49806985+MrGVSV@users.noreply.github.com> Date: Fri, 25 Feb 2022 19:00:22 -0800 Subject: [PATCH 05/44] Apply suggestions from code review Co-authored-by: Alice Cecile --- crates/bevy_reflect/src/fields.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 94afbc4d6220b..3a2235dfee9a7 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -1,6 +1,6 @@ use std::borrow::{Borrow, Cow}; -/// The named field of a struct +/// The named field of a reflected struct #[derive(Clone, Debug)] pub struct NamedField { name: Cow<'static, str>, @@ -15,12 +15,12 @@ impl NamedField { } } - /// Returns the name of the field + /// The name of the field pub fn name(&self) -> &str { self.name.borrow() } - /// Returns the type of the field + /// The type name of the field pub fn type_name(&self) -> &str { self.type_name.borrow() } From b0dfaa951aded9a7f783752f9316f06f986fd0bd Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 26 Feb 2022 16:38:00 -0800 Subject: [PATCH 06/44] Added relevant TypeIds to info structs --- .../bevy_reflect_derive/src/lib.rs | 14 ++-- crates/bevy_reflect/src/fields.rs | 38 ++++++++-- crates/bevy_reflect/src/lib.rs | 72 +++++++++++++++---- crates/bevy_reflect/src/list.rs | 48 +++++++++---- crates/bevy_reflect/src/map.rs | 70 +++++++++++++----- crates/bevy_reflect/src/struct_trait.rs | 43 ++++++----- crates/bevy_reflect/src/tuple.rs | 38 ++++++---- crates/bevy_reflect/src/tuple_struct.rs | 33 ++++++--- crates/bevy_reflect/src/type_info.rs | 58 +++++++++------ 9 files changed, 294 insertions(+), 120 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index b1d9205ffd7d0..4403797cdff1c 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -323,11 +323,10 @@ fn impl_struct( } fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { - let name = std::any::type_name::(); - let fields: [(&str, &str); #field_count] = [ - #((#field_names, std::any::type_name::<#field_types>()),)* + let fields: [#bevy_reflect_path::NamedField; #field_count] = [ + #(#bevy_reflect_path::NamedField::new::<#field_types>(#field_names),)* ]; - let info = #bevy_reflect_path::StructInfo::new(name, fields); + let info = #bevy_reflect_path::StructInfo::new::(&fields); #bevy_reflect_path::TypeInfo::Struct(info) } } @@ -457,11 +456,10 @@ fn impl_tuple_struct( } fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { - let name = std::any::type_name::(); - let fields: [&str; #field_count] = [ - #(std::any::type_name::<#field_types>(),)* + let fields: [#bevy_reflect_path::UnnamedField; #field_count] = [ + #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_indices),)* ]; - let info = #bevy_reflect_path::TupleStructInfo::new(name, fields); + let info = #bevy_reflect_path::TupleStructInfo::new::(&fields); #bevy_reflect_path::TypeInfo::TupleStruct(info) } } diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 3a2235dfee9a7..684e751e771e0 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -1,3 +1,5 @@ +use crate::Reflect; +use std::any::TypeId; use std::borrow::{Borrow, Cow}; /// The named field of a reflected struct @@ -5,13 +7,15 @@ use std::borrow::{Borrow, Cow}; pub struct NamedField { name: Cow<'static, str>, type_name: Cow<'static, str>, + type_id: TypeId, } impl NamedField { - pub fn new>(name: I, type_name: I) -> Self { + pub fn new(name: &str) -> Self { Self { name: Cow::Owned(name.into()), - type_name: Cow::Owned(type_name.into()), + type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::(), } } @@ -24,20 +28,32 @@ impl NamedField { pub fn type_name(&self) -> &str { self.type_name.borrow() } + + /// The `TypeId` of the field + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this field's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } } -/// The unnamed field of a tuple or tuple struct +/// The unnamed field of a reflected tuple or tuple struct #[derive(Clone, Debug)] pub struct UnnamedField { index: usize, type_name: Cow<'static, str>, + type_id: TypeId, } impl UnnamedField { - pub fn new>(index: usize, type_name: I) -> Self { + pub fn new(index: usize) -> Self { Self { index, - type_name: Cow::Owned(type_name.into()), + type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::(), } } @@ -46,8 +62,18 @@ impl UnnamedField { self.index } - /// Returns the type of the field + /// The type name of the field pub fn type_name(&self) -> &str { self.type_name.borrow() } + + /// The `TypeId` of the field + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this field's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index e6a1c5b75d5a1..34d5e005bd4dd 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -440,7 +440,40 @@ mod tests { let info = MyStruct::type_info(); if let TypeInfo::Struct(info) = info { - assert_eq!(std::any::type_name::(), info.name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!( + std::any::type_name::(), + info.field("foo").unwrap().type_name() + ); + assert_eq!( + std::any::TypeId::of::(), + info.field("foo").unwrap().type_id() + ); + assert!(info.field("foo").unwrap().is::()); + assert_eq!("foo", info.field("foo").unwrap().name()); + assert_eq!( + std::any::type_name::(), + info.field_at(1).unwrap().type_name() + ); + } else { + panic!("Expected `TypeInfo::Struct`"); + } + + // Struct (generic) + #[derive(Reflect)] + struct MyGenericStruct { + foo: T, + bar: usize, + } + + let info = >::type_info(); + if let TypeInfo::Struct(info) = info { + assert!(info.is::>()); + assert_eq!( + std::any::type_name::>(), + info.type_name() + ); assert_eq!( std::any::type_name::(), info.field("foo").unwrap().type_name() @@ -460,11 +493,13 @@ mod tests { let info = MyTupleStruct::type_info(); if let TypeInfo::TupleStruct(info) = info { - assert_eq!(std::any::type_name::(), info.name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), info.field_at(1).unwrap().type_name() ); + assert!(info.field_at(1).unwrap().is::()); } else { panic!("Expected `TypeInfo::TupleStruct`"); } @@ -474,7 +509,8 @@ mod tests { let info = MyTuple::type_info(); if let TypeInfo::Tuple(info) = info { - assert_eq!(std::any::type_name::(), info.name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), info.field_at(1).unwrap().type_name() @@ -488,8 +524,10 @@ mod tests { let info = MyList::type_info(); if let TypeInfo::List(info) = info { - assert_eq!(std::any::type_name::(), info.name()); - assert_eq!(std::any::type_name::(), info.item_type()); + assert!(info.is::()); + assert!(info.item_is::()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::type_name::(), info.item_type_name()); assert_eq!(None, info.capacity()); } else { panic!("Expected `TypeInfo::List`"); @@ -502,8 +540,13 @@ mod tests { let info = MyListWithCapacity::type_info(); if let TypeInfo::List(info) = info { - assert_eq!(std::any::type_name::(), info.name()); - assert_eq!(std::any::type_name::(), info.item_type()); + assert!(info.is::()); + assert!(info.item_is::()); + assert_eq!( + std::any::type_name::(), + info.type_name() + ); + assert_eq!(std::any::type_name::(), info.item_type_name()); assert_eq!(Some(123usize), info.capacity()); } else { panic!("Expected `TypeInfo::List`"); @@ -515,9 +558,12 @@ mod tests { let info = MyMap::type_info(); if let TypeInfo::Map(info) = info { - assert_eq!(std::any::type_name::(), info.name()); - assert_eq!(std::any::type_name::(), info.key_type()); - assert_eq!(std::any::type_name::(), info.value_type()); + assert!(info.is::()); + assert!(info.key_is::()); + assert!(info.value_is::()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::type_name::(), info.key_type_name()); + assert_eq!(std::any::type_name::(), info.value_type_name()); } else { panic!("Expected `TypeInfo::Map`"); } @@ -527,7 +573,8 @@ mod tests { let info = MyValue::type_info(); if let TypeInfo::Value(info) = info { - assert_eq!(std::any::type_name::(), info.name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); } else { panic!("Expected `TypeInfo::Value`"); } @@ -537,7 +584,8 @@ mod tests { let info = MyDynamic::type_info(); if let TypeInfo::Dynamic(info) = info { - assert_eq!(std::any::type_name::(), info.name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); } else { panic!("Expected `TypeInfo::Dynamic`"); } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 678615282a895..64f483f0122b6 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,4 +1,4 @@ -use std::any::Any; +use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use crate::{ @@ -39,29 +39,53 @@ pub trait List: Reflect { /// A container for compile-time list info #[derive(Clone, Debug)] pub struct ListInfo { - name: Cow<'static, str>, - item_type: Cow<'static, str>, + type_name: Cow<'static, str>, + item_type_name: Cow<'static, str>, + type_id: TypeId, + item_type_id: TypeId, capacity: Option, } impl ListInfo { /// Create a new [`ListInfo`] - pub fn new(capacity: Option) -> Self { + pub fn new(capacity: Option) -> Self { Self { - name: Cow::Owned(std::any::type_name::().to_string()), - item_type: Cow::Owned(std::any::type_name::().to_string()), + type_name: Cow::Owned(std::any::type_name::().to_string()), + item_type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::(), + item_type_id: TypeId::of::(), capacity, } } - /// The name of this list - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this list + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } + + /// The item type name of this list + pub fn item_type_name(&self) -> &str { + self.item_type_name.borrow() + } + + /// The `TypeId` of this list + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// The item `TypeId` of this list + pub fn item_type_id(&self) -> TypeId { + self.item_type_id + } + + /// Check if the given type matches this list's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } - /// The item type of this list - pub fn item_type(&self) -> &str { - self.item_type.borrow() + /// Check if the given type matches this list's item type + pub fn item_is(&self) -> bool { + TypeId::of::() == self.item_type_id } /// The compile-time capacity of this list, if any diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 857d59e0b2fb1..75d77dae9914f 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -1,4 +1,4 @@ -use std::any::Any; +use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::hash::Hash; @@ -48,34 +48,70 @@ pub trait Map: Reflect { /// A container for compile-time map info #[derive(Clone, Debug)] pub struct MapInfo { - name: Cow<'static, str>, - key_type: Cow<'static, str>, - value_type: Cow<'static, str>, + type_name: Cow<'static, str>, + key_type_name: Cow<'static, str>, + value_type_name: Cow<'static, str>, + type_id: TypeId, + key_type_id: TypeId, + value_type_id: TypeId, } impl MapInfo { /// Create a new [`MapInfo`] - pub fn new() -> Self { + pub fn new() -> Self { Self { - name: Cow::Owned(std::any::type_name::().to_string()), - key_type: Cow::Owned(std::any::type_name::().to_string()), - value_type: Cow::Owned(std::any::type_name::().to_string()), + type_name: Cow::Owned(std::any::type_name::().to_string()), + key_type_name: Cow::Owned(std::any::type_name::().to_string()), + value_type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::(), + key_type_id: TypeId::of::(), + value_type_id: TypeId::of::(), } } - /// The name of this map - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this map + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } + + /// The key type name of this map + pub fn key_type_name(&self) -> &str { + self.key_type_name.borrow() + } + + /// The value type name of this map + pub fn value_type_name(&self) -> &str { + self.value_type_name.borrow() + } + + /// The `TypeId` of this map + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// The key `TypeId` of this map + pub fn key_type_id(&self) -> TypeId { + self.key_type_id + } + + /// The value `TypeId` of this map + pub fn value_type_id(&self) -> TypeId { + self.value_type_id + } + + /// Check if the given type matches this map's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } - /// The key type of this map - pub fn key_type(&self) -> &str { - self.key_type.borrow() + /// Check if the given type matches this map's key type + pub fn key_is(&self) -> bool { + TypeId::of::() == self.key_type_id } - /// The value type of this map - pub fn value_type(&self) -> &str { - self.value_type.borrow() + /// Check if the given type matches this map's value type + pub fn value_is(&self) -> bool { + TypeId::of::() == self.value_type_id } } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 295c014a4542a..e4cd181c3566a 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -5,6 +5,7 @@ use bevy_utils::{Entry, HashMap}; use std::borrow::Borrow; use std::slice::Iter; use std::{any::Any, borrow::Cow}; +use std::any::TypeId; /// A reflected Rust regular struct type. /// @@ -67,7 +68,8 @@ pub trait Struct: Reflect { /// A container for compile-time struct info #[derive(Clone, Debug)] pub struct StructInfo { - name: Cow<'static, str>, + type_name: Cow<'static, str>, + type_id: TypeId, fields: Vec, field_indices: HashMap, usize>, } @@ -77,31 +79,36 @@ impl StructInfo { /// /// # Arguments /// - /// * `name`: The name of the struct - /// * `fields`: An iterator over the fields. Takes the form: `(field_name, field_type)`. + /// * `fields`: The fields of this struct in the order they are defined /// - pub fn new, F: IntoIterator>(name: I, fields: F) -> Self { - let (fields, field_indices): (Vec<_>, HashMap<_, _>) = fields - .into_iter() - .enumerate() + pub fn new(fields: &[NamedField]) -> Self { + let field_indices = fields.iter().enumerate() .map(|(index, field)| { - let field_name = field.0.into(); - let field = NamedField::new(field_name.clone(), field.1.into()); - let field_index = (Cow::Owned(field_name), index); - (field, field_index) - }) - .unzip(); + let name = field.name().to_string(); + (Cow::Owned(name), index) + }).collect::>(); Self { - name: Cow::Owned(name.into()), - fields, + type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::(), + fields: fields.to_vec(), field_indices, } } - /// The name of this struct - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this struct + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } + + /// The `TypeId` of this struct + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this struct's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } /// Get a field with the given name diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index f8782ba3428ed..2750de34f1325 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,9 +1,9 @@ -use std::any::Any; +use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::slice::Iter; use crate::{ - create_tuple_fields, serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, }; @@ -128,8 +128,9 @@ impl GetTupleField for dyn Tuple { /// A container for compile-time tuple info #[derive(Clone, Debug)] pub struct TupleInfo { - name: Cow<'static, str>, + type_name: Cow<'static, str>, fields: Vec, + type_id: TypeId } impl TupleInfo { @@ -137,19 +138,29 @@ impl TupleInfo { /// /// # Arguments /// - /// * `name`: The name of the tuple - /// * `fields`: An iterator over the field types + /// * `fields`: The fields of this tuple in the order they are defined /// - pub fn new, F: IntoIterator>(name: I, fields: F) -> Self { + pub fn new(fields: &[UnnamedField]) -> Self { Self { - name: Cow::Owned(name.into()), - fields: create_tuple_fields(fields), + type_name: Cow::Owned(std::any::type_name::().to_string()), + fields: fields.to_vec(), + type_id: TypeId::of::() } } - /// The name of this tuple - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this tuple + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } + + /// The `TypeId` of this tuple + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this tuple's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } /// Get a field at the given index @@ -455,11 +466,10 @@ macro_rules! impl_reflect_tuple { } fn type_info() -> TypeInfo where Self: Sized { - let name = std::any::type_name::(); let fields = [ - $(std::any::type_name::<$name>(),)* + $(UnnamedField::new::<$name>($index),)* ]; - let info = TupleInfo::new(name, fields); + let info = TupleInfo::new::(&fields); TypeInfo::Tuple(info) } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 228afc9ab3637..25d8402d10f4f 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,8 +1,8 @@ use crate::{ - create_tuple_fields, serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, + serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, }; -use std::any::Any; +use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::slice::Iter; @@ -51,8 +51,9 @@ pub trait TupleStruct: Reflect { /// A container for compile-time tuple struct info #[derive(Clone, Debug)] pub struct TupleStructInfo { - name: Cow<'static, str>, + type_name: Cow<'static, str>, fields: Vec, + type_id: TypeId } impl TupleStructInfo { @@ -60,19 +61,29 @@ impl TupleStructInfo { /// /// # Arguments /// - /// * `name`: The name of the tuple struct - /// * `fields`: An iterator over the field types + /// * `fields`: The fields of this struct in the order they are defined /// - pub fn new, F: IntoIterator>(name: I, fields: F) -> Self { + pub fn new(fields: &[UnnamedField]) -> Self { Self { - name: Cow::Owned(name.into()), - fields: create_tuple_fields(fields), + type_name: Cow::Owned(std::any::type_name::().to_string()), + fields: fields.to_vec(), + type_id: TypeId::of::() } } - /// The name of this struct - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this struct + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } + + /// The `TypeId` of this struct + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this struct's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } /// Get a field at the given index diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 9592880c590c9..23d96be8151a8 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -1,4 +1,5 @@ -use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo, UnnamedField}; +use std::any::TypeId; +use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo}; use std::borrow::{Borrow, Cow}; /// Compile-time type information for various object types @@ -19,47 +20,60 @@ pub enum TypeInfo { /// A container for compile-time info related to general value types, including primitives #[derive(Debug, Clone)] pub struct ValueInfo { - name: Cow<'static, str>, + type_name: Cow<'static, str>, + type_id: TypeId } impl ValueInfo { pub fn new() -> Self { Self { - name: Cow::Owned(std::any::type_name::().to_string()), + type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::() } } - /// The name of this value - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this value + pub fn type_name(&self) -> &str { + self.type_name.borrow() + } + + /// The `TypeId` of this value + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this value's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } } #[derive(Debug, Clone)] pub struct DynamicInfo { - name: Cow<'static, str>, + type_name: Cow<'static, str>, + type_id: TypeId } impl DynamicInfo { pub fn new() -> Self { Self { - name: Cow::Owned(std::any::type_name::().to_string()), + type_name: Cow::Owned(std::any::type_name::().to_string()), + type_id: TypeId::of::() } } - /// The name of this value - pub fn name(&self) -> &str { - self.name.borrow() + /// The type name of this value + pub fn type_name(&self) -> &str { + self.type_name.borrow() } -} -/// Create a collection of unnamed fields from an iterator of field type names -pub(crate) fn create_tuple_fields, F: IntoIterator>( - fields: F, -) -> Vec { - fields - .into_iter() - .enumerate() - .map(|(index, field)| UnnamedField::new(index, field.into())) - .collect() -} + /// The `TypeId` of this value + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches this value's type + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } +} \ No newline at end of file From 23e276a892c43e352a6a59de63987d3cd5d49093 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 26 Feb 2022 16:47:00 -0800 Subject: [PATCH 07/44] Formatting --- crates/bevy_reflect/src/struct_trait.rs | 9 ++++++--- crates/bevy_reflect/src/tuple.rs | 8 ++++---- crates/bevy_reflect/src/tuple_struct.rs | 7 +++---- crates/bevy_reflect/src/type_info.rs | 12 ++++++------ 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index e4cd181c3566a..b8aa890a1b609 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -2,10 +2,10 @@ use crate::{ serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, }; use bevy_utils::{Entry, HashMap}; +use std::any::TypeId; use std::borrow::Borrow; use std::slice::Iter; use std::{any::Any, borrow::Cow}; -use std::any::TypeId; /// A reflected Rust regular struct type. /// @@ -82,11 +82,14 @@ impl StructInfo { /// * `fields`: The fields of this struct in the order they are defined /// pub fn new(fields: &[NamedField]) -> Self { - let field_indices = fields.iter().enumerate() + let field_indices = fields + .iter() + .enumerate() .map(|(index, field)| { let name = field.name().to_string(); (Cow::Owned(name), index) - }).collect::>(); + }) + .collect::>(); Self { type_name: Cow::Owned(std::any::type_name::().to_string()), diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 2750de34f1325..deae4f9a66d34 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -3,8 +3,8 @@ use std::borrow::{Borrow, Cow}; use std::slice::Iter; use crate::{ - serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, - ReflectRef, TypeInfo, UnnamedField, + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, + UnnamedField, }; /// A reflected Rust tuple. @@ -130,7 +130,7 @@ impl GetTupleField for dyn Tuple { pub struct TupleInfo { type_name: Cow<'static, str>, fields: Vec, - type_id: TypeId + type_id: TypeId, } impl TupleInfo { @@ -144,7 +144,7 @@ impl TupleInfo { Self { type_name: Cow::Owned(std::any::type_name::().to_string()), fields: fields.to_vec(), - type_id: TypeId::of::() + type_id: TypeId::of::(), } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 25d8402d10f4f..bc4fa71c9bc36 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,6 +1,5 @@ use crate::{ - serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, - TypeInfo, UnnamedField, + serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, }; use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; @@ -53,7 +52,7 @@ pub trait TupleStruct: Reflect { pub struct TupleStructInfo { type_name: Cow<'static, str>, fields: Vec, - type_id: TypeId + type_id: TypeId, } impl TupleStructInfo { @@ -67,7 +66,7 @@ impl TupleStructInfo { Self { type_name: Cow::Owned(std::any::type_name::().to_string()), fields: fields.to_vec(), - type_id: TypeId::of::() + type_id: TypeId::of::(), } } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 23d96be8151a8..6946d70868c42 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -1,5 +1,5 @@ -use std::any::TypeId; use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo}; +use std::any::TypeId; use std::borrow::{Borrow, Cow}; /// Compile-time type information for various object types @@ -21,14 +21,14 @@ pub enum TypeInfo { #[derive(Debug, Clone)] pub struct ValueInfo { type_name: Cow<'static, str>, - type_id: TypeId + type_id: TypeId, } impl ValueInfo { pub fn new() -> Self { Self { type_name: Cow::Owned(std::any::type_name::().to_string()), - type_id: TypeId::of::() + type_id: TypeId::of::(), } } @@ -51,14 +51,14 @@ impl ValueInfo { #[derive(Debug, Clone)] pub struct DynamicInfo { type_name: Cow<'static, str>, - type_id: TypeId + type_id: TypeId, } impl DynamicInfo { pub fn new() -> Self { Self { type_name: Cow::Owned(std::any::type_name::().to_string()), - type_id: TypeId::of::() + type_id: TypeId::of::(), } } @@ -76,4 +76,4 @@ impl DynamicInfo { pub fn is(&self) -> bool { TypeId::of::() == self.type_id } -} \ No newline at end of file +} From 83c5e6e72ffc913ccb9ec5cd61e0a57757357082 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 26 Feb 2022 17:02:54 -0800 Subject: [PATCH 08/44] Added convenience methods to TypeInfo --- crates/bevy_reflect/src/lib.rs | 5 +++++ crates/bevy_reflect/src/type_info.rs | 30 +++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 34d5e005bd4dd..c6506e8e4a129 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -431,6 +431,11 @@ mod tests { #[test] fn reflect_type_info() { + // TypeInfo + let info = i32::type_info(); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::TypeId::of::(), info.type_id()); + // Struct #[derive(Reflect)] struct MyStruct { diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 6946d70868c42..7d4c89caa463c 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -2,7 +2,7 @@ use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo}; use std::any::TypeId; use std::borrow::{Borrow, Cow}; -/// Compile-time type information for various object types +/// Compile-time type information for various reflected types #[derive(Debug, Clone)] pub enum TypeInfo { Struct(StructInfo), @@ -17,6 +17,34 @@ pub enum TypeInfo { Dynamic(DynamicInfo), } +impl TypeInfo { + /// The name of the reflected type + pub fn type_name(&self) -> &str { + 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::Map(info) => info.type_name(), + Self::Value(info) => info.type_name(), + Self::Dynamic(info) => info.type_name(), + } + } + + /// The `TypeId` of the reflected type + pub fn type_id(&self) -> TypeId { + match self { + Self::Struct(info) => info.type_id(), + Self::TupleStruct(info) => info.type_id(), + Self::Tuple(info) => info.type_id(), + Self::List(info) => info.type_id(), + Self::Map(info) => info.type_id(), + Self::Value(info) => info.type_id(), + Self::Dynamic(info) => info.type_id(), + } + } +} + /// A container for compile-time info related to general value types, including primitives #[derive(Debug, Clone)] pub struct ValueInfo { From 81c1298dcd465f5918d0cce7c9967697b8d49e1c Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Fri, 4 Mar 2022 16:05:03 -0800 Subject: [PATCH 09/44] Added Typed trait Moved type_info() method from Reflect to Typed. This removes the unnecessary restriction of "where Self: Sized" which prevented using the method on unsized types (i.e. dyn Reflect). This should hopefully be more useful if/when Reflect is implemented for an unsized type. --- .../bevy_reflect_derive/src/lib.rs | 18 ++++++++----- crates/bevy_reflect/src/impls/smallvec.rs | 12 ++++----- crates/bevy_reflect/src/impls/std.rs | 27 +++++++------------ crates/bevy_reflect/src/list.rs | 11 +++----- crates/bevy_reflect/src/map.rs | 9 +++---- crates/bevy_reflect/src/reflect.rs | 7 +---- crates/bevy_reflect/src/struct_trait.rs | 9 +++---- crates/bevy_reflect/src/tuple.rs | 16 +++++------ crates/bevy_reflect/src/tuple_struct.rs | 11 +++----- crates/bevy_reflect/src/type_info.rs | 11 ++++++++ crates/bevy_reflect/src/type_registry.rs | 7 ++--- 11 files changed, 66 insertions(+), 72 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 4403797cdff1c..87e631796fc44 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -321,8 +321,10 @@ fn impl_struct( fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { #partial_eq_fn } + } - fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { + impl #impl_generics #bevy_reflect_path::Typed for #struct_name #ty_generics #where_clause { + fn type_info() -> #bevy_reflect_path::TypeInfo { let fields: [#bevy_reflect_path::NamedField; #field_count] = [ #(#bevy_reflect_path::NamedField::new::<#field_types>(#field_names),)* ]; @@ -362,11 +364,11 @@ fn impl_tuple_struct( TraitImpl::Implemented | TraitImpl::Custom(_) => reflect_attrs.get_partial_eq_impl(), }; - let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl(); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); TokenStream::from(quote! { #get_type_registration_impl - impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name #ty_generics { + impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name #ty_generics #where_clause { fn field(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { match index { #(#field_indices => Some(&self.#field_idents),)* @@ -398,7 +400,7 @@ fn impl_tuple_struct( } // SAFE: any and any_mut both return self - unsafe impl #impl_generics #bevy_reflect_path::Reflect for #struct_name #ty_generics { + unsafe impl #impl_generics #bevy_reflect_path::Reflect for #struct_name #ty_generics #where_clause { #[inline] fn type_name(&self) -> &str { std::any::type_name::() @@ -454,8 +456,10 @@ fn impl_tuple_struct( fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option { #partial_eq_fn } + } - fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { + impl #impl_generics #bevy_reflect_path::Typed for #struct_name #ty_generics #where_clause { + fn type_info() -> #bevy_reflect_path::TypeInfo { let fields: [#bevy_reflect_path::UnnamedField; #field_count] = [ #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_indices),)* ]; @@ -538,8 +542,10 @@ fn impl_value( fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> { #serialize_fn } + } - fn type_info() -> #bevy_reflect_path::TypeInfo where Self: Sized { + impl #impl_generics #bevy_reflect_path::Typed for #type_name #ty_generics #where_clause { + fn type_info() -> #bevy_reflect_path::TypeInfo { let info = #bevy_reflect_path::ValueInfo::new::(); #bevy_reflect_path::TypeInfo::Value(info) } diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 1e622343f28c8..221c9f68ff5c3 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,10 +1,7 @@ use smallvec::{Array, SmallVec}; use std::any::Any; -use crate::{ - serde::Serializable, FromReflect, List, ListInfo, ListIter, Reflect, ReflectMut, ReflectRef, - TypeInfo, -}; +use crate::{serde::Serializable, FromReflect, List, ListInfo, ListIter, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; impl List for SmallVec where @@ -99,11 +96,12 @@ where fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo +impl Typed for SmallVec where - Self: Sized, - { + T::Item: FromReflect + Clone, { + fn type_info() -> TypeInfo { TypeInfo::List(ListInfo::new::(Some(T::size()))) } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 934989a4d3a92..a67bd61631192 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,9 +1,5 @@ use crate as bevy_reflect; -use crate::{ - map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, - List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, - ReflectRef, TypeInfo, TypeRegistration, ValueInfo, -}; +use crate::{map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, ValueInfo, Typed}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; @@ -142,11 +138,10 @@ unsafe impl Reflect for Vec { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for Vec { + fn type_info() -> TypeInfo { TypeInfo::List(ListInfo::new::(None)) } } @@ -267,11 +262,10 @@ unsafe impl Reflect for HashMap { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for HashMap { + fn type_info() -> TypeInfo { TypeInfo::Map(MapInfo::new::()) } } @@ -363,11 +357,10 @@ unsafe impl Reflect for Cow<'static, str> { fn serializable(&self) -> Option { Some(Serializable::Borrowed(self)) } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for Cow<'static, str> { + fn type_info() -> TypeInfo { TypeInfo::Value(ValueInfo::new::()) } } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 64f483f0122b6..5a334283252bd 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,9 +1,7 @@ use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; -use crate::{ - serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, -}; +use crate::{serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. pub trait List: Reflect { @@ -219,11 +217,10 @@ unsafe impl Reflect for DynamicList { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for DynamicList { + fn type_info() -> TypeInfo { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 75d77dae9914f..2c80464b26dfc 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -4,7 +4,7 @@ use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo}; +use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; /// An ordered mapping between [`Reflect`] values. /// @@ -259,11 +259,10 @@ unsafe impl Reflect for DynamicMap { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for DynamicMap { + fn type_info() -> TypeInfo { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 13835d754abea..4362068df918e 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,4 +1,4 @@ -use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct, TypeInfo}; +use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; @@ -133,11 +133,6 @@ pub unsafe trait Reflect: Any + Send + Sync { /// /// If the underlying type does not support serialization, returns `None`. fn serializable(&self) -> Option; - - /// Returns the compile-time info for the underlying type - fn type_info() -> TypeInfo - where - Self: Sized; } /// A trait for types which can be constructed from a reflected type. diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index b8aa890a1b609..516d81e0fba67 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,5 +1,5 @@ use crate::{ - serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, + serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, }; use bevy_utils::{Entry, HashMap}; use std::any::TypeId; @@ -395,11 +395,10 @@ unsafe impl Reflect for DynamicStruct { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for DynamicStruct { + fn type_info() -> TypeInfo { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index deae4f9a66d34..c784262ca7c9b 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -2,10 +2,7 @@ use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::slice::Iter; -use crate::{ - serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, - UnnamedField, -}; +use crate::{serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, Typed}; /// A reflected Rust tuple. /// @@ -316,11 +313,10 @@ unsafe impl Reflect for DynamicTuple { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for DynamicTuple { + fn type_info() -> TypeInfo { TypeInfo::Dynamic(DynamicInfo::new::()) } } @@ -464,8 +460,10 @@ macro_rules! impl_reflect_tuple { fn serializable(&self) -> Option { None } + } - fn type_info() -> TypeInfo where Self: Sized { + impl <$($name: Typed),*> Typed for ($($name,)*) { + fn type_info() -> TypeInfo { let fields = [ $(UnnamedField::new::<$name>($index),)* ]; diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index bc4fa71c9bc36..fc36893ae0cd4 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,6 +1,4 @@ -use crate::{ - serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, -}; +use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, Typed}; use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::slice::Iter; @@ -310,11 +308,10 @@ unsafe impl Reflect for DynamicTupleStruct { fn serializable(&self) -> Option { None } +} - fn type_info() -> TypeInfo - where - Self: Sized, - { +impl Typed for DynamicTupleStruct { + fn type_info() -> TypeInfo { TypeInfo::Dynamic(DynamicInfo::new::()) } } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 7d4c89caa463c..c7173f172fa5b 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -2,6 +2,17 @@ use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo}; use std::any::TypeId; use std::borrow::{Borrow, Cow}; +/// A static accessor to compile-time type information +/// +/// This is used by the `#[derive(Reflect)]` macro to generate an implementation +/// of [`TypeInfo`] to pass to register via [`TypeRegistration::of`][0]. +/// +/// [0]: crate::TypeRegistration::of +pub trait Typed: Reflect { + /// Returns the compile-time info for the underlying type + fn type_info() -> TypeInfo; +} + /// Compile-time type information for various reflected types #[derive(Debug, Clone)] pub enum TypeInfo { diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 082808e4edd35..9fb52b1228c5c 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -1,4 +1,4 @@ -use crate::{Reflect, TypeInfo}; +use crate::{Reflect, Typed, TypeInfo}; use bevy_utils::{HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; @@ -158,7 +158,7 @@ impl TypeRegistryArc { /// A record of data about a type. /// -/// This contains the [`TypeId`], [name], and [short name] of the type. +/// This contains the [`TypeId`], [name], [short name], and [`TypeInfo`] of the type. /// /// For each trait specified by the [`#[reflect(_)]`][0] attribute of /// [`#[derive(Reflect)]`][1] on the registered type, this record also contains @@ -168,6 +168,7 @@ impl TypeRegistryArc { /// [`TypeId`]: std::any::TypeId /// [name]: std::any::type_name /// [short name]: TypeRegistration::get_short_name +/// [`TypeInfo`]: crate::TypeInfo /// [0]: crate::Reflect /// [1]: crate::Reflect pub struct TypeRegistration { @@ -220,7 +221,7 @@ impl TypeRegistration { } /// Creates type registration information for `T`. - pub fn of() -> Self { + pub fn of() -> Self { let ty = TypeId::of::(); let type_name = std::any::type_name::(); Self { From 8ad235ccf28a73403a2042e3ba5d09c36dc6bfcc Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Fri, 4 Mar 2022 16:12:42 -0800 Subject: [PATCH 10/44] Formatting --- crates/bevy_reflect/src/impls/smallvec.rs | 10 +++++++--- crates/bevy_reflect/src/impls/std.rs | 6 +++++- crates/bevy_reflect/src/list.rs | 4 +++- crates/bevy_reflect/src/tuple.rs | 5 ++++- crates/bevy_reflect/src/tuple_struct.rs | 5 ++++- crates/bevy_reflect/src/type_registry.rs | 2 +- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 221c9f68ff5c3..67291fc772c5e 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,7 +1,10 @@ use smallvec::{Array, SmallVec}; use std::any::Any; -use crate::{serde::Serializable, FromReflect, List, ListInfo, ListIter, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; +use crate::{ + serde::Serializable, FromReflect, List, ListInfo, ListIter, Reflect, ReflectMut, ReflectRef, + TypeInfo, Typed, +}; impl List for SmallVec where @@ -99,8 +102,9 @@ where } impl Typed for SmallVec - where - T::Item: FromReflect + Clone, { +where + T::Item: FromReflect + Clone, +{ fn type_info() -> TypeInfo { TypeInfo::List(ListInfo::new::(Some(T::size()))) } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index a67bd61631192..695f71d13521d 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,5 +1,9 @@ use crate as bevy_reflect; -use crate::{map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, ValueInfo, Typed}; +use crate::{ + map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, + List, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, + ReflectRef, TypeInfo, TypeRegistration, Typed, ValueInfo, +}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 5a334283252bd..0e1a8e96f72e9 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,7 +1,9 @@ use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; -use crate::{serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; +use crate::{ + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, +}; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. pub trait List: Reflect { diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index c784262ca7c9b..ec7122badc6bc 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -2,7 +2,10 @@ use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::slice::Iter; -use crate::{serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, Typed}; +use crate::{ + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, + Typed, UnnamedField, +}; /// A reflected Rust tuple. /// diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index fc36893ae0cd4..cc2e102ecf345 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,4 +1,7 @@ -use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, UnnamedField, Typed}; +use crate::{ + serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, + UnnamedField, +}; use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; use std::slice::Iter; diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 9fb52b1228c5c..39421a9337d03 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -1,4 +1,4 @@ -use crate::{Reflect, Typed, TypeInfo}; +use crate::{Reflect, TypeInfo, Typed}; use bevy_utils::{HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; From e9f39cf170f3ede59b92c9428d165258d44c6c2f Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 00:49:07 -0800 Subject: [PATCH 11/44] Impl Typed for dyn Reflect --- crates/bevy_reflect/src/lib.rs | 5 ++++- crates/bevy_reflect/src/reflect.rs | 8 +++++++- crates/bevy_reflect/src/type_info.rs | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index c6506e8e4a129..bb03c604cefa9 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -436,6 +436,9 @@ mod tests { assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::TypeId::of::(), info.type_id()); + // TypeInfo (unsized) + assert_eq!(std::any::TypeId::of::(), ::type_info().type_id()); + // Struct #[derive(Reflect)] struct MyStruct { @@ -595,4 +598,4 @@ mod tests { panic!("Expected `TypeInfo::Dynamic`"); } } -} +} \ No newline at end of file diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 4362068df918e..4b6962f317476 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,4 +1,4 @@ -use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct}; +use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct, Typed, TypeInfo, ValueInfo}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; @@ -156,6 +156,12 @@ impl Debug for dyn Reflect { } } +impl Typed for dyn Reflect { + fn type_info() -> TypeInfo { + TypeInfo::Value(ValueInfo::new::()) + } +} + impl dyn Reflect { /// Downcasts the value to type `T`, consuming the trait object. /// diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index c7173f172fa5b..6a6fed4bad182 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -64,7 +64,7 @@ pub struct ValueInfo { } impl ValueInfo { - pub fn new() -> Self { + pub fn new() -> Self { Self { type_name: Cow::Owned(std::any::type_name::().to_string()), type_id: TypeId::of::(), From ad786ad8d5643b5d5b47c4ff105fa57572b793fc Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 00:50:39 -0800 Subject: [PATCH 12/44] Formatting --- crates/bevy_reflect/src/lib.rs | 7 +++++-- crates/bevy_reflect/src/reflect.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index bb03c604cefa9..e98df4473411d 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -437,7 +437,10 @@ mod tests { assert_eq!(std::any::TypeId::of::(), info.type_id()); // TypeInfo (unsized) - assert_eq!(std::any::TypeId::of::(), ::type_info().type_id()); + assert_eq!( + std::any::TypeId::of::(), + ::type_info().type_id() + ); // Struct #[derive(Reflect)] @@ -598,4 +601,4 @@ mod tests { panic!("Expected `TypeInfo::Dynamic`"); } } -} \ No newline at end of file +} diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 4b6962f317476..8723134c8c3dc 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,4 +1,6 @@ -use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct, Typed, TypeInfo, ValueInfo}; +use crate::{ + serde::Serializable, List, Map, Struct, Tuple, TupleStruct, TypeInfo, Typed, ValueInfo, +}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; From a5ca84dbdf3d576a72bbc975c9775c9a2a847fd5 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 11:47:43 -0800 Subject: [PATCH 13/44] Replaced Cow<'static, str> with &'static str Also replaced Reflect bound in is() methods with Any --- crates/bevy_reflect/src/fields.rs | 22 +++++++++--------- crates/bevy_reflect/src/list.rs | 21 ++++++++--------- crates/bevy_reflect/src/map.rs | 31 ++++++++++++------------- crates/bevy_reflect/src/struct_trait.rs | 19 ++++++++------- crates/bevy_reflect/src/tuple.rs | 11 ++++----- crates/bevy_reflect/src/tuple_struct.rs | 11 ++++----- crates/bevy_reflect/src/type_info.rs | 23 +++++++++--------- 7 files changed, 67 insertions(+), 71 deletions(-) diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 684e751e771e0..187086ade7616 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -1,12 +1,12 @@ use crate::Reflect; -use std::any::TypeId; +use std::any::{Any, TypeId}; use std::borrow::{Borrow, Cow}; /// The named field of a reflected struct #[derive(Clone, Debug)] pub struct NamedField { name: Cow<'static, str>, - type_name: Cow<'static, str>, + type_name: &'static str, type_id: TypeId, } @@ -14,7 +14,7 @@ impl NamedField { pub fn new(name: &str) -> Self { Self { name: Cow::Owned(name.into()), - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), type_id: TypeId::of::(), } } @@ -26,16 +26,16 @@ impl NamedField { /// The type name of the field pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of the field + /// The [`TypeId`] of the field pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this field's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } } @@ -44,7 +44,7 @@ impl NamedField { #[derive(Clone, Debug)] pub struct UnnamedField { index: usize, - type_name: Cow<'static, str>, + type_name: &'static str, type_id: TypeId, } @@ -52,7 +52,7 @@ impl UnnamedField { pub fn new(index: usize) -> Self { Self { index, - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), type_id: TypeId::of::(), } } @@ -64,16 +64,16 @@ impl UnnamedField { /// The type name of the field pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of the field + /// The [`TypeId`] of the field pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this field's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 0e1a8e96f72e9..ebf83f9acef55 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,5 +1,4 @@ use std::any::{Any, TypeId}; -use std::borrow::{Borrow, Cow}; use crate::{ serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, @@ -39,8 +38,8 @@ pub trait List: Reflect { /// A container for compile-time list info #[derive(Clone, Debug)] pub struct ListInfo { - type_name: Cow<'static, str>, - item_type_name: Cow<'static, str>, + type_name: &'static str, + item_type_name: &'static str, type_id: TypeId, item_type_id: TypeId, capacity: Option, @@ -50,8 +49,8 @@ impl ListInfo { /// Create a new [`ListInfo`] pub fn new(capacity: Option) -> Self { Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), - item_type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), + item_type_name: std::any::type_name::(), type_id: TypeId::of::(), item_type_id: TypeId::of::(), capacity, @@ -60,31 +59,31 @@ impl ListInfo { /// The type name of this list pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } /// The item type name of this list pub fn item_type_name(&self) -> &str { - self.item_type_name.borrow() + self.item_type_name } - /// The `TypeId` of this list + /// The [`TypeId`] of this list pub fn type_id(&self) -> TypeId { self.type_id } - /// The item `TypeId` of this list + /// The item [`TypeId`] of this list pub fn item_type_id(&self) -> TypeId { self.item_type_id } /// Check if the given type matches this list's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } /// Check if the given type matches this list's item type - pub fn item_is(&self) -> bool { + pub fn item_is(&self) -> bool { TypeId::of::() == self.item_type_id } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 2c80464b26dfc..baeb3bce0ae01 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -1,5 +1,4 @@ use std::any::{Any, TypeId}; -use std::borrow::{Borrow, Cow}; use std::hash::Hash; use bevy_utils::{Entry, HashMap}; @@ -48,9 +47,9 @@ pub trait Map: Reflect { /// A container for compile-time map info #[derive(Clone, Debug)] pub struct MapInfo { - type_name: Cow<'static, str>, - key_type_name: Cow<'static, str>, - value_type_name: Cow<'static, str>, + type_name: &'static str, + key_type_name: &'static str, + value_type_name: &'static str, type_id: TypeId, key_type_id: TypeId, value_type_id: TypeId, @@ -60,9 +59,9 @@ impl MapInfo { /// Create a new [`MapInfo`] pub fn new() -> Self { Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), - key_type_name: Cow::Owned(std::any::type_name::().to_string()), - value_type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), + key_type_name: std::any::type_name::(), + value_type_name: std::any::type_name::(), type_id: TypeId::of::(), key_type_id: TypeId::of::(), value_type_id: TypeId::of::(), @@ -71,46 +70,46 @@ impl MapInfo { /// The type name of this map pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } /// The key type name of this map pub fn key_type_name(&self) -> &str { - self.key_type_name.borrow() + self.key_type_name } /// The value type name of this map pub fn value_type_name(&self) -> &str { - self.value_type_name.borrow() + self.value_type_name } - /// The `TypeId` of this map + /// The [`TypeId`] of this map pub fn type_id(&self) -> TypeId { self.type_id } - /// The key `TypeId` of this map + /// The key [`TypeId`] of this map pub fn key_type_id(&self) -> TypeId { self.key_type_id } - /// The value `TypeId` of this map + /// The value [`TypeId`] of this map pub fn value_type_id(&self) -> TypeId { self.value_type_id } /// Check if the given type matches this map's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } /// Check if the given type matches this map's key type - pub fn key_is(&self) -> bool { + pub fn key_is(&self) -> bool { TypeId::of::() == self.key_type_id } /// Check if the given type matches this map's value type - pub fn value_is(&self) -> bool { + pub fn value_is(&self) -> bool { TypeId::of::() == self.value_type_id } } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 516d81e0fba67..238a912764d3b 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -2,10 +2,11 @@ use crate::{ serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, }; use bevy_utils::{Entry, HashMap}; -use std::any::TypeId; -use std::borrow::Borrow; -use std::slice::Iter; -use std::{any::Any, borrow::Cow}; +use std::{ + any::{Any, TypeId}, + borrow::Cow, + slice::Iter, +}; /// A reflected Rust regular struct type. /// @@ -68,7 +69,7 @@ pub trait Struct: Reflect { /// A container for compile-time struct info #[derive(Clone, Debug)] pub struct StructInfo { - type_name: Cow<'static, str>, + type_name: &'static str, type_id: TypeId, fields: Vec, field_indices: HashMap, usize>, @@ -92,7 +93,7 @@ impl StructInfo { .collect::>(); Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), type_id: TypeId::of::(), fields: fields.to_vec(), field_indices, @@ -101,16 +102,16 @@ impl StructInfo { /// The type name of this struct pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of this struct + /// The [`TypeId`] of this struct pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this struct's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index ec7122badc6bc..cafcff69f7468 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,5 +1,4 @@ use std::any::{Any, TypeId}; -use std::borrow::{Borrow, Cow}; use std::slice::Iter; use crate::{ @@ -128,7 +127,7 @@ impl GetTupleField for dyn Tuple { /// A container for compile-time tuple info #[derive(Clone, Debug)] pub struct TupleInfo { - type_name: Cow<'static, str>, + type_name: &'static str, fields: Vec, type_id: TypeId, } @@ -142,7 +141,7 @@ impl TupleInfo { /// pub fn new(fields: &[UnnamedField]) -> Self { Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), fields: fields.to_vec(), type_id: TypeId::of::(), } @@ -150,16 +149,16 @@ impl TupleInfo { /// The type name of this tuple pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of this tuple + /// The [`TypeId`] of this tuple pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this tuple's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index cc2e102ecf345..6eb2b8f80dfab 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -3,7 +3,6 @@ use crate::{ UnnamedField, }; use std::any::{Any, TypeId}; -use std::borrow::{Borrow, Cow}; use std::slice::Iter; /// A reflected Rust tuple struct. @@ -51,7 +50,7 @@ pub trait TupleStruct: Reflect { /// A container for compile-time tuple struct info #[derive(Clone, Debug)] pub struct TupleStructInfo { - type_name: Cow<'static, str>, + type_name: &'static str, fields: Vec, type_id: TypeId, } @@ -65,7 +64,7 @@ impl TupleStructInfo { /// pub fn new(fields: &[UnnamedField]) -> Self { Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), fields: fields.to_vec(), type_id: TypeId::of::(), } @@ -73,16 +72,16 @@ impl TupleStructInfo { /// The type name of this struct pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of this struct + /// The [`TypeId`] of this struct pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this struct's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 6a6fed4bad182..0437492f379a0 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -1,6 +1,5 @@ use crate::{ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo}; -use std::any::TypeId; -use std::borrow::{Borrow, Cow}; +use std::any::{Any, TypeId}; /// A static accessor to compile-time type information /// @@ -59,60 +58,60 @@ impl TypeInfo { /// A container for compile-time info related to general value types, including primitives #[derive(Debug, Clone)] pub struct ValueInfo { - type_name: Cow<'static, str>, + type_name: &'static str, type_id: TypeId, } impl ValueInfo { pub fn new() -> Self { Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), type_id: TypeId::of::(), } } /// The type name of this value pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of this value + /// The [`TypeId`] of this value pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this value's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } } #[derive(Debug, Clone)] pub struct DynamicInfo { - type_name: Cow<'static, str>, + type_name: &'static str, type_id: TypeId, } impl DynamicInfo { pub fn new() -> Self { Self { - type_name: Cow::Owned(std::any::type_name::().to_string()), + type_name: std::any::type_name::(), type_id: TypeId::of::(), } } /// The type name of this value pub fn type_name(&self) -> &str { - self.type_name.borrow() + self.type_name } - /// The `TypeId` of this value + /// The [`TypeId`] of this value pub fn type_id(&self) -> TypeId { self.type_id } /// Check if the given type matches this value's type - pub fn is(&self) -> bool { + pub fn is(&self) -> bool { TypeId::of::() == self.type_id } } From f8e57a951e6220f474aabdfdafa0df129cda4b04 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 14:57:08 -0800 Subject: [PATCH 14/44] Store fields as Box<[T]> --- crates/bevy_reflect/src/struct_trait.rs | 4 ++-- crates/bevy_reflect/src/tuple.rs | 4 ++-- crates/bevy_reflect/src/tuple_struct.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 238a912764d3b..fc291918cfb93 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -71,7 +71,7 @@ pub trait Struct: Reflect { pub struct StructInfo { type_name: &'static str, type_id: TypeId, - fields: Vec, + fields: Box<[NamedField]>, field_indices: HashMap, usize>, } @@ -95,7 +95,7 @@ impl StructInfo { Self { type_name: std::any::type_name::(), type_id: TypeId::of::(), - fields: fields.to_vec(), + fields: fields.to_vec().into_boxed_slice(), field_indices, } } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index cafcff69f7468..572bf6cfe1b44 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -128,7 +128,7 @@ impl GetTupleField for dyn Tuple { #[derive(Clone, Debug)] pub struct TupleInfo { type_name: &'static str, - fields: Vec, + fields: Box<[UnnamedField]>, type_id: TypeId, } @@ -142,7 +142,7 @@ impl TupleInfo { pub fn new(fields: &[UnnamedField]) -> Self { Self { type_name: std::any::type_name::(), - fields: fields.to_vec(), + fields: fields.to_vec().into_boxed_slice(), type_id: TypeId::of::(), } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 6eb2b8f80dfab..92ed291aa06fb 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -51,7 +51,7 @@ pub trait TupleStruct: Reflect { #[derive(Clone, Debug)] pub struct TupleStructInfo { type_name: &'static str, - fields: Vec, + fields: Box<[UnnamedField]>, type_id: TypeId, } @@ -65,7 +65,7 @@ impl TupleStructInfo { pub fn new(fields: &[UnnamedField]) -> Self { Self { type_name: std::any::type_name::(), - fields: fields.to_vec(), + fields: fields.to_vec().into_boxed_slice(), type_id: TypeId::of::(), } } From fea53436aafbaa830d57c2a66a3a3e4e95417d3e Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 15:22:53 -0800 Subject: [PATCH 15/44] Added documentation for DynamicInfo --- crates/bevy_reflect/src/type_info.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 0437492f379a0..2d7a064848591 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -86,6 +86,14 @@ impl ValueInfo { } } +/// A container for compile-time info related to general Bevy's _dynamic_ types, including primitives. +/// +/// This is functionally the same as [`ValueInfo`], however, semantically it refers to dynamic +/// types such as [`DynamicStruct`], [`DynamicTuple`], [`DynamicList`], etc. +/// +/// [`DynamicStruct`]: crate::DynamicStruct +/// [`DynamicTuple`]: crate::DynamicTuple +/// [`DynamicList`]: crate::DynamicList #[derive(Debug, Clone)] pub struct DynamicInfo { type_name: &'static str, From 091e5e8947bf4f3e145dad86c666ee883f4363fa Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 15:43:27 -0800 Subject: [PATCH 16/44] Added TypeIdentity This type contains data and methods used by a number of type info structs and was added to reduce duplication --- crates/bevy_reflect/src/type_info.rs | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 2d7a064848591..bb805b4d0069a 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -12,6 +12,37 @@ pub trait Typed: Reflect { fn type_info() -> TypeInfo; } +#[derive(Clone, Debug)] +/// Type information used to identify a given type, including the type name and its [`TypeId`]. +pub struct TypeIdentity(&'static str, TypeId); + +impl TypeIdentity { + /// Creates a new [`TypeIdentity`] with the given type name and [`TypeId`] + pub const fn new(name: &'static str, type_id: TypeId) -> Self { + Self(name, type_id) + } + + /// Creates a new [`TypeIdentity`] for the given type, [`T`] + pub fn of() -> Self { + Self(std::any::type_name::(), TypeId::of::()) + } + + /// The name of this type + pub fn type_name(&self) -> &str { + self.0 + } + + /// The [`TypeId`] of this type + pub fn type_id(&self) -> TypeId { + self.1 + } + + /// Check if the given type matches this type + pub fn is(&self) -> bool { + TypeId::of::() == self.1 + } +} + /// Compile-time type information for various reflected types #[derive(Debug, Clone)] pub enum TypeInfo { From 8cf502941b55254984a5dfdfb4eb4494a82a53a6 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 15:44:51 -0800 Subject: [PATCH 17/44] Integrated TypeIdentity across type info structs --- crates/bevy_reflect/src/fields.rs | 47 ++++--------- crates/bevy_reflect/src/lib.rs | 73 +++++++++++---------- crates/bevy_reflect/src/list.rs | 49 ++++---------- crates/bevy_reflect/src/map.rs | 73 ++++++--------------- crates/bevy_reflect/src/struct_trait.rs | 31 +++------ crates/bevy_reflect/src/tuple.rs | 28 +++----- crates/bevy_reflect/src/tuple_struct.rs | 28 +++----- crates/bevy_reflect/src/type_info.rs | 87 +++++++++++-------------- 8 files changed, 144 insertions(+), 272 deletions(-) diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 187086ade7616..e52b94233eea9 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -1,21 +1,18 @@ -use crate::Reflect; -use std::any::{Any, TypeId}; +use crate::{Reflect, TypeIdentity}; use std::borrow::{Borrow, Cow}; /// The named field of a reflected struct #[derive(Clone, Debug)] pub struct NamedField { name: Cow<'static, str>, - type_name: &'static str, - type_id: TypeId, + id: TypeIdentity, } impl NamedField { pub fn new(name: &str) -> Self { Self { name: Cow::Owned(name.into()), - type_name: std::any::type_name::(), - type_id: TypeId::of::(), + id: TypeIdentity::of::(), } } @@ -24,19 +21,9 @@ impl NamedField { self.name.borrow() } - /// The type name of the field - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of the field - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this field's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of the field + pub fn id(&self) -> &TypeIdentity { + &self.id } } @@ -44,16 +31,14 @@ impl NamedField { #[derive(Clone, Debug)] pub struct UnnamedField { index: usize, - type_name: &'static str, - type_id: TypeId, + id: TypeIdentity, } impl UnnamedField { pub fn new(index: usize) -> Self { Self { index, - type_name: std::any::type_name::(), - type_id: TypeId::of::(), + id: TypeIdentity::of::(), } } @@ -62,18 +47,8 @@ impl UnnamedField { self.index } - /// The type name of the field - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of the field - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this field's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of the field + pub fn id(&self) -> &TypeIdentity { + &self.id } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index e98df4473411d..4bccc5c4d02d0 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -451,21 +451,21 @@ mod tests { let info = MyStruct::type_info(); if let TypeInfo::Struct(info) = info { - assert!(info.is::()); - assert_eq!(std::any::type_name::(), info.type_name()); + assert!(info.id().is::()); + assert_eq!(std::any::type_name::(), info.id().type_name()); assert_eq!( std::any::type_name::(), - info.field("foo").unwrap().type_name() + info.field("foo").unwrap().id().type_name() ); assert_eq!( std::any::TypeId::of::(), - info.field("foo").unwrap().type_id() + info.field("foo").unwrap().id().type_id() ); - assert!(info.field("foo").unwrap().is::()); + assert!(info.field("foo").unwrap().id().is::()); assert_eq!("foo", info.field("foo").unwrap().name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().type_name() + info.field_at(1).unwrap().id().type_name() ); } else { panic!("Expected `TypeInfo::Struct`"); @@ -480,19 +480,19 @@ mod tests { let info = >::type_info(); if let TypeInfo::Struct(info) = info { - assert!(info.is::>()); + assert!(info.id().is::>()); assert_eq!( std::any::type_name::>(), - info.type_name() + info.id().type_name() ); assert_eq!( std::any::type_name::(), - info.field("foo").unwrap().type_name() + info.field("foo").unwrap().id().type_name() ); assert_eq!("foo", info.field("foo").unwrap().name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().type_name() + info.field_at(1).unwrap().id().type_name() ); } else { panic!("Expected `TypeInfo::Struct`"); @@ -504,13 +504,16 @@ mod tests { let info = MyTupleStruct::type_info(); if let TypeInfo::TupleStruct(info) = info { - assert!(info.is::()); - assert_eq!(std::any::type_name::(), info.type_name()); + assert!(info.id().is::()); + assert_eq!( + std::any::type_name::(), + info.id().type_name() + ); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().type_name() + info.field_at(1).unwrap().id().type_name() ); - assert!(info.field_at(1).unwrap().is::()); + assert!(info.field_at(1).unwrap().id().is::()); } else { panic!("Expected `TypeInfo::TupleStruct`"); } @@ -520,11 +523,11 @@ mod tests { let info = MyTuple::type_info(); if let TypeInfo::Tuple(info) = info { - assert!(info.is::()); - assert_eq!(std::any::type_name::(), info.type_name()); + assert!(info.id().is::()); + assert_eq!(std::any::type_name::(), info.id().type_name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().type_name() + info.field_at(1).unwrap().id().type_name() ); } else { panic!("Expected `TypeInfo::Tuple`"); @@ -535,10 +538,10 @@ mod tests { let info = MyList::type_info(); if let TypeInfo::List(info) = info { - assert!(info.is::()); - assert!(info.item_is::()); - assert_eq!(std::any::type_name::(), info.type_name()); - assert_eq!(std::any::type_name::(), info.item_type_name()); + assert!(info.id().is::()); + assert!(info.item().is::()); + assert_eq!(std::any::type_name::(), info.id().type_name()); + assert_eq!(std::any::type_name::(), info.item().type_name()); assert_eq!(None, info.capacity()); } else { panic!("Expected `TypeInfo::List`"); @@ -551,13 +554,13 @@ mod tests { let info = MyListWithCapacity::type_info(); if let TypeInfo::List(info) = info { - assert!(info.is::()); - assert!(info.item_is::()); + assert!(info.id().is::()); + assert!(info.item().is::()); assert_eq!( std::any::type_name::(), - info.type_name() + info.id().type_name() ); - assert_eq!(std::any::type_name::(), info.item_type_name()); + assert_eq!(std::any::type_name::(), info.item().type_name()); assert_eq!(Some(123usize), info.capacity()); } else { panic!("Expected `TypeInfo::List`"); @@ -569,12 +572,12 @@ mod tests { let info = MyMap::type_info(); if let TypeInfo::Map(info) = info { - assert!(info.is::()); - assert!(info.key_is::()); - assert!(info.value_is::()); - assert_eq!(std::any::type_name::(), info.type_name()); - assert_eq!(std::any::type_name::(), info.key_type_name()); - assert_eq!(std::any::type_name::(), info.value_type_name()); + assert!(info.id().is::()); + assert!(info.key().is::()); + assert!(info.value().is::()); + assert_eq!(std::any::type_name::(), info.id().type_name()); + assert_eq!(std::any::type_name::(), info.key().type_name()); + assert_eq!(std::any::type_name::(), info.value().type_name()); } else { panic!("Expected `TypeInfo::Map`"); } @@ -584,8 +587,8 @@ mod tests { let info = MyValue::type_info(); if let TypeInfo::Value(info) = info { - assert!(info.is::()); - assert_eq!(std::any::type_name::(), info.type_name()); + assert!(info.id().is::()); + assert_eq!(std::any::type_name::(), info.id().type_name()); } else { panic!("Expected `TypeInfo::Value`"); } @@ -595,8 +598,8 @@ mod tests { let info = MyDynamic::type_info(); if let TypeInfo::Dynamic(info) = info { - assert!(info.is::()); - assert_eq!(std::any::type_name::(), info.type_name()); + assert!(info.id().is::()); + assert_eq!(std::any::type_name::(), info.id().type_name()); } else { panic!("Expected `TypeInfo::Dynamic`"); } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index ebf83f9acef55..481df94e1d23b 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,7 +1,8 @@ -use std::any::{Any, TypeId}; +use std::any::Any; use crate::{ - serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeIdentity, + TypeInfo, Typed, }; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. @@ -38,10 +39,8 @@ pub trait List: Reflect { /// A container for compile-time list info #[derive(Clone, Debug)] pub struct ListInfo { - type_name: &'static str, - item_type_name: &'static str, - type_id: TypeId, - item_type_id: TypeId, + id: TypeIdentity, + item_id: TypeIdentity, capacity: Option, } @@ -49,42 +48,20 @@ impl ListInfo { /// Create a new [`ListInfo`] pub fn new(capacity: Option) -> Self { Self { - type_name: std::any::type_name::(), - item_type_name: std::any::type_name::(), - type_id: TypeId::of::(), - item_type_id: TypeId::of::(), + id: TypeIdentity::of::(), + item_id: TypeIdentity::of::(), capacity, } } - /// The type name of this list - pub fn type_name(&self) -> &str { - self.type_name + /// The [`TypeIdentity`] of this list + pub fn id(&self) -> &TypeIdentity { + &self.id } - /// The item type name of this list - pub fn item_type_name(&self) -> &str { - self.item_type_name - } - - /// The [`TypeId`] of this list - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// The item [`TypeId`] of this list - pub fn item_type_id(&self) -> TypeId { - self.item_type_id - } - - /// Check if the given type matches this list's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id - } - - /// Check if the given type matches this list's item type - pub fn item_is(&self) -> bool { - TypeId::of::() == self.item_type_id + /// The [`TypeIdentity`] of this list's item type + pub fn item(&self) -> &TypeIdentity { + &self.item_id } /// The compile-time capacity of this list, if any diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index baeb3bce0ae01..87567061c5666 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -1,9 +1,12 @@ -use std::any::{Any, TypeId}; +use std::any::Any; use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; +use crate::{ + serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, + Typed, +}; /// An ordered mapping between [`Reflect`] values. /// @@ -47,70 +50,34 @@ pub trait Map: Reflect { /// A container for compile-time map info #[derive(Clone, Debug)] pub struct MapInfo { - type_name: &'static str, - key_type_name: &'static str, - value_type_name: &'static str, - type_id: TypeId, - key_type_id: TypeId, - value_type_id: TypeId, + id: TypeIdentity, + key_id: TypeIdentity, + value_id: TypeIdentity, } impl MapInfo { /// Create a new [`MapInfo`] pub fn new() -> Self { Self { - type_name: std::any::type_name::(), - key_type_name: std::any::type_name::(), - value_type_name: std::any::type_name::(), - type_id: TypeId::of::(), - key_type_id: TypeId::of::(), - value_type_id: TypeId::of::(), + id: TypeIdentity::of::(), + key_id: TypeIdentity::of::(), + value_id: TypeIdentity::of::(), } } - /// The type name of this map - pub fn type_name(&self) -> &str { - self.type_name + /// The [`TypeIdentity`] of this map + pub fn id(&self) -> &TypeIdentity { + &self.id } - /// The key type name of this map - pub fn key_type_name(&self) -> &str { - self.key_type_name + /// The [`TypeIdentity`] of this map's key type + pub fn key(&self) -> &TypeIdentity { + &self.key_id } - /// The value type name of this map - pub fn value_type_name(&self) -> &str { - self.value_type_name - } - - /// The [`TypeId`] of this map - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// The key [`TypeId`] of this map - pub fn key_type_id(&self) -> TypeId { - self.key_type_id - } - - /// The value [`TypeId`] of this map - pub fn value_type_id(&self) -> TypeId { - self.value_type_id - } - - /// Check if the given type matches this map's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id - } - - /// Check if the given type matches this map's key type - pub fn key_is(&self) -> bool { - TypeId::of::() == self.key_type_id - } - - /// Check if the given type matches this map's value type - pub fn value_is(&self) -> bool { - TypeId::of::() == self.value_type_id + /// The [`TypeIdentity`] of this map's value type + pub fn value(&self) -> &TypeIdentity { + &self.value_id } } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index fc291918cfb93..b22bde1ef7f75 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,12 +1,9 @@ use crate::{ - serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, + serde::Serializable, DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeIdentity, + TypeInfo, Typed, }; use bevy_utils::{Entry, HashMap}; -use std::{ - any::{Any, TypeId}, - borrow::Cow, - slice::Iter, -}; +use std::{any::Any, borrow::Cow, slice::Iter}; /// A reflected Rust regular struct type. /// @@ -69,8 +66,7 @@ pub trait Struct: Reflect { /// A container for compile-time struct info #[derive(Clone, Debug)] pub struct StructInfo { - type_name: &'static str, - type_id: TypeId, + id: TypeIdentity, fields: Box<[NamedField]>, field_indices: HashMap, usize>, } @@ -93,26 +89,15 @@ impl StructInfo { .collect::>(); Self { - type_name: std::any::type_name::(), - type_id: TypeId::of::(), + id: TypeIdentity::of::(), fields: fields.to_vec().into_boxed_slice(), field_indices, } } - /// The type name of this struct - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of this struct - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this struct's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of this struct + pub fn id(&self) -> &TypeIdentity { + &self.id } /// Get a field with the given name diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 572bf6cfe1b44..9612685e1389e 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,9 +1,9 @@ -use std::any::{Any, TypeId}; +use std::any::Any; use std::slice::Iter; use crate::{ - serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, - Typed, UnnamedField, + serde::Serializable, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeIdentity, + TypeInfo, Typed, UnnamedField, }; /// A reflected Rust tuple. @@ -127,9 +127,8 @@ impl GetTupleField for dyn Tuple { /// A container for compile-time tuple info #[derive(Clone, Debug)] pub struct TupleInfo { - type_name: &'static str, + id: TypeIdentity, fields: Box<[UnnamedField]>, - type_id: TypeId, } impl TupleInfo { @@ -141,25 +140,14 @@ impl TupleInfo { /// pub fn new(fields: &[UnnamedField]) -> Self { Self { - type_name: std::any::type_name::(), + id: TypeIdentity::of::(), fields: fields.to_vec().into_boxed_slice(), - type_id: TypeId::of::(), } } - /// The type name of this tuple - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of this tuple - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this tuple's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of this tuple + pub fn id(&self) -> &TypeIdentity { + &self.id } /// Get a field at the given index diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 92ed291aa06fb..fbb246e3e0201 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,8 +1,8 @@ use crate::{ - serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, - UnnamedField, + serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, + Typed, UnnamedField, }; -use std::any::{Any, TypeId}; +use std::any::Any; use std::slice::Iter; /// A reflected Rust tuple struct. @@ -50,9 +50,8 @@ pub trait TupleStruct: Reflect { /// A container for compile-time tuple struct info #[derive(Clone, Debug)] pub struct TupleStructInfo { - type_name: &'static str, + id: TypeIdentity, fields: Box<[UnnamedField]>, - type_id: TypeId, } impl TupleStructInfo { @@ -64,25 +63,14 @@ impl TupleStructInfo { /// pub fn new(fields: &[UnnamedField]) -> Self { Self { - type_name: std::any::type_name::(), + id: TypeIdentity::of::(), fields: fields.to_vec().into_boxed_slice(), - type_id: TypeId::of::(), } } - /// The type name of this struct - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of this struct - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this struct's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of this struct + pub fn id(&self) -> &TypeIdentity { + &self.id } /// Get a field at the given index diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index bb805b4d0069a..7219734764ad4 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -59,29 +59,42 @@ pub enum TypeInfo { } impl TypeInfo { + /// The [`TypeIdentity`] of the reflected type + pub fn id(&self) -> &TypeIdentity { + match self { + Self::Struct(info) => info.id(), + Self::TupleStruct(info) => info.id(), + Self::Tuple(info) => info.id(), + Self::List(info) => info.id(), + Self::Map(info) => info.id(), + Self::Value(info) => info.id(), + Self::Dynamic(info) => info.id(), + } + } + /// The name of the reflected type pub fn type_name(&self) -> &str { 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::Map(info) => info.type_name(), - Self::Value(info) => info.type_name(), - Self::Dynamic(info) => info.type_name(), + Self::Struct(info) => info.id().type_name(), + Self::TupleStruct(info) => info.id().type_name(), + Self::Tuple(info) => info.id().type_name(), + Self::List(info) => info.id().type_name(), + Self::Map(info) => info.id().type_name(), + Self::Value(info) => info.id().type_name(), + Self::Dynamic(info) => info.id().type_name(), } } - /// The `TypeId` of the reflected type + /// The [`TypeId`] of the reflected type pub fn type_id(&self) -> TypeId { match self { - Self::Struct(info) => info.type_id(), - Self::TupleStruct(info) => info.type_id(), - Self::Tuple(info) => info.type_id(), - Self::List(info) => info.type_id(), - Self::Map(info) => info.type_id(), - Self::Value(info) => info.type_id(), - Self::Dynamic(info) => info.type_id(), + Self::Struct(info) => info.id().type_id(), + Self::TupleStruct(info) => info.id().type_id(), + Self::Tuple(info) => info.id().type_id(), + Self::List(info) => info.id().type_id(), + Self::Map(info) => info.id().type_id(), + Self::Value(info) => info.id().type_id(), + Self::Dynamic(info) => info.id().type_id(), } } } @@ -89,31 +102,19 @@ impl TypeInfo { /// A container for compile-time info related to general value types, including primitives #[derive(Debug, Clone)] pub struct ValueInfo { - type_name: &'static str, - type_id: TypeId, + id: TypeIdentity, } impl ValueInfo { pub fn new() -> Self { Self { - type_name: std::any::type_name::(), - type_id: TypeId::of::(), + id: TypeIdentity::of::(), } } - /// The type name of this value - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of this value - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this value's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of this value + pub fn id(&self) -> &TypeIdentity { + &self.id } } @@ -127,30 +128,18 @@ impl ValueInfo { /// [`DynamicList`]: crate::DynamicList #[derive(Debug, Clone)] pub struct DynamicInfo { - type_name: &'static str, - type_id: TypeId, + id: TypeIdentity, } impl DynamicInfo { pub fn new() -> Self { Self { - type_name: std::any::type_name::(), - type_id: TypeId::of::(), + id: TypeIdentity::of::(), } } - /// The type name of this value - pub fn type_name(&self) -> &str { - self.type_name - } - - /// The [`TypeId`] of this value - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches this value's type - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id + /// The [`TypeIdentity`] of this dynamic value + pub fn id(&self) -> &TypeIdentity { + &self.id } } From 9cbaf281d5224dfe88d788891487f8cff94b9b66 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Sat, 5 Mar 2022 16:02:39 -0800 Subject: [PATCH 18/44] Fixed doc error --- crates/bevy_reflect/src/type_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 7219734764ad4..c9dedd073f489 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -22,7 +22,7 @@ impl TypeIdentity { Self(name, type_id) } - /// Creates a new [`TypeIdentity`] for the given type, [`T`] + /// Creates a new [`TypeIdentity`] for the given type pub fn of() -> Self { Self(std::any::type_name::(), TypeId::of::()) } From f6cbb1da641692441a901a476fd358e3286d8c7c Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Mon, 7 Mar 2022 18:45:12 -0800 Subject: [PATCH 19/44] Remove duplicated data TypeRegistration does not need to store its own TypeId and type name since it now contains TypeInfo --- crates/bevy_reflect/src/type_info.rs | 2 +- crates/bevy_reflect/src/type_registry.rs | 25 +++++++++--------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index c9dedd073f489..b9fee445c08d9 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -28,7 +28,7 @@ impl TypeIdentity { } /// The name of this type - pub fn type_name(&self) -> &str { + pub fn type_name(&self) -> &'static str { self.0 } diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 39421a9337d03..e9f5b2698d94f 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -55,12 +55,12 @@ impl TypeRegistry { self.ambiguous_names.insert(short_name); } else { self.short_name_to_id - .insert(short_name, registration.type_id); + .insert(short_name, registration.type_id()); } self.full_name_to_id - .insert(registration.name.to_string(), registration.type_id); + .insert(registration.name().to_string(), registration.type_id()); self.registrations - .insert(registration.type_id, registration); + .insert(registration.type_id(), registration); } /// Returns a reference to the [`TypeRegistration`] of the type with the @@ -158,23 +158,19 @@ impl TypeRegistryArc { /// A record of data about a type. /// -/// This contains the [`TypeId`], [name], [short name], and [`TypeInfo`] of the type. +/// This contains the [`TypeInfo`] of the type, as well as its [short name]. /// /// For each trait specified by the [`#[reflect(_)]`][0] attribute of /// [`#[derive(Reflect)]`][1] on the registered type, this record also contains /// a [`TypeData`] which can be used to downcast [`Reflect`] trait objects of /// this type to trait objects of the relevant trait. /// -/// [`TypeId`]: std::any::TypeId -/// [name]: std::any::type_name /// [short name]: TypeRegistration::get_short_name /// [`TypeInfo`]: crate::TypeInfo /// [0]: crate::Reflect /// [1]: crate::Reflect pub struct TypeRegistration { - type_id: TypeId, short_name: String, - name: &'static str, data: HashMap>, type_info: TypeInfo, } @@ -185,7 +181,7 @@ impl TypeRegistration { /// [`TypeId`]: std::any::TypeId #[inline] pub fn type_id(&self) -> TypeId { - self.type_id + self.type_info.id().type_id() } /// Returns a reference to the value of type `T` in this registration's type @@ -222,12 +218,9 @@ impl TypeRegistration { /// Creates type registration information for `T`. pub fn of() -> Self { - let ty = TypeId::of::(); let type_name = std::any::type_name::(); Self { - type_id: ty, data: HashMap::default(), - name: type_name, short_name: Self::get_short_name(type_name), type_info: T::type_info(), } @@ -240,9 +233,11 @@ impl TypeRegistration { &self.short_name } - /// Returns the name of the type. + /// Returns the [name] of the type. + /// + /// [name]: std::any::type_name pub fn name(&self) -> &'static str { - self.name + self.type_info.id().type_name() } /// Calculates the short name of a type. @@ -298,9 +293,7 @@ impl Clone for TypeRegistration { TypeRegistration { data, - name: self.name, short_name: self.short_name.clone(), - type_id: self.type_id, type_info: self.type_info.clone(), } } From 55e023bf253b891c04e5ed7e0c315ff814ab7df2 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Mon, 7 Mar 2022 18:53:18 -0800 Subject: [PATCH 20/44] Removed unnecessary methods --- crates/bevy_reflect/src/lib.rs | 6 +++--- crates/bevy_reflect/src/type_info.rs | 26 -------------------------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 4bccc5c4d02d0..ec70c212c4995 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -433,13 +433,13 @@ mod tests { fn reflect_type_info() { // TypeInfo let info = i32::type_info(); - assert_eq!(std::any::type_name::(), info.type_name()); - assert_eq!(std::any::TypeId::of::(), info.type_id()); + assert_eq!(std::any::type_name::(), info.id().type_name()); + assert_eq!(std::any::TypeId::of::(), info.id().type_id()); // TypeInfo (unsized) assert_eq!( std::any::TypeId::of::(), - ::type_info().type_id() + ::type_info().id().type_id() ); // Struct diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index b9fee445c08d9..dd4d138cb17c0 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -71,32 +71,6 @@ impl TypeInfo { Self::Dynamic(info) => info.id(), } } - - /// The name of the reflected type - pub fn type_name(&self) -> &str { - match self { - Self::Struct(info) => info.id().type_name(), - Self::TupleStruct(info) => info.id().type_name(), - Self::Tuple(info) => info.id().type_name(), - Self::List(info) => info.id().type_name(), - Self::Map(info) => info.id().type_name(), - Self::Value(info) => info.id().type_name(), - Self::Dynamic(info) => info.id().type_name(), - } - } - - /// The [`TypeId`] of the reflected type - pub fn type_id(&self) -> TypeId { - match self { - Self::Struct(info) => info.id().type_id(), - Self::TupleStruct(info) => info.id().type_id(), - Self::Tuple(info) => info.id().type_id(), - Self::List(info) => info.id().type_id(), - Self::Map(info) => info.id().type_id(), - Self::Value(info) => info.id().type_id(), - Self::Dynamic(info) => info.id().type_id(), - } - } } /// A container for compile-time info related to general value types, including primitives From 000c32764b5647294b058d144a3ad755be7c2db8 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Mon, 7 Mar 2022 18:55:07 -0800 Subject: [PATCH 21/44] Clarify comments --- crates/bevy_reflect/src/type_info.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index dd4d138cb17c0..55c11c516105a 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -13,7 +13,9 @@ pub trait Typed: Reflect { } #[derive(Clone, Debug)] -/// Type information used to identify a given type, including the type name and its [`TypeId`]. +/// Type information used to identify a given type, including its [name] and its [`TypeId`]. +/// +/// [name]: std::any::type_name pub struct TypeIdentity(&'static str, TypeId); impl TypeIdentity { @@ -27,7 +29,9 @@ impl TypeIdentity { Self(std::any::type_name::(), TypeId::of::()) } - /// The name of this type + /// The [name] of this type + /// + /// [name]: std::any::type_name pub fn type_name(&self) -> &'static str { self.0 } From 097b1f2987c33bddd76c774d326b42ce9744308a Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Mon, 7 Mar 2022 19:16:14 -0800 Subject: [PATCH 22/44] Added static_new method to create field with static str --- crates/bevy_reflect/bevy_reflect_derive/src/lib.rs | 2 +- crates/bevy_reflect/src/fields.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 87e631796fc44..e3ad78476b06f 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -326,7 +326,7 @@ fn impl_struct( impl #impl_generics #bevy_reflect_path::Typed for #struct_name #ty_generics #where_clause { fn type_info() -> #bevy_reflect_path::TypeInfo { let fields: [#bevy_reflect_path::NamedField; #field_count] = [ - #(#bevy_reflect_path::NamedField::new::<#field_types>(#field_names),)* + #(#bevy_reflect_path::NamedField::static_new::<#field_types>(#field_names),)* ]; let info = #bevy_reflect_path::StructInfo::new::(&fields); #bevy_reflect_path::TypeInfo::Struct(info) diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index e52b94233eea9..d0847b809de0e 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -9,6 +9,7 @@ pub struct NamedField { } impl NamedField { + /// Create a new [`NamedField`] pub fn new(name: &str) -> Self { Self { name: Cow::Owned(name.into()), @@ -16,6 +17,17 @@ impl NamedField { } } + /// Create a new [`NamedField`] using a static string + /// + /// This helps save an allocation when the string has a static lifetime, such + /// as when using [`std::any::type_name`]. + pub fn static_new(name: &'static str) -> Self { + Self { + name: Cow::Borrowed(name), + id: TypeIdentity::of::(), + } + } + /// The name of the field pub fn name(&self) -> &str { self.name.borrow() From d1ddb1f401d7efc80ccbd873fc3d12a22ef4e64e Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Tue, 8 Mar 2022 14:00:27 -0800 Subject: [PATCH 23/44] Use the cow Switched NamedField::name() from returning `&str` to `&Cow<'static, str>` to reduce extra allocations when creating `StructInfo` --- crates/bevy_reflect/src/fields.rs | 6 +++--- crates/bevy_reflect/src/struct_trait.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index d0847b809de0e..662684a418b83 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -1,5 +1,5 @@ use crate::{Reflect, TypeIdentity}; -use std::borrow::{Borrow, Cow}; +use std::borrow::Cow; /// The named field of a reflected struct #[derive(Clone, Debug)] @@ -29,8 +29,8 @@ impl NamedField { } /// The name of the field - pub fn name(&self) -> &str { - self.name.borrow() + pub fn name(&self) -> &Cow<'static, str> { + &self.name } /// The [`TypeIdentity`] of the field diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index b22bde1ef7f75..77bd1cc6a0f5d 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -83,8 +83,8 @@ impl StructInfo { .iter() .enumerate() .map(|(index, field)| { - let name = field.name().to_string(); - (Cow::Owned(name), index) + let name = field.name().clone(); + (name, index) }) .collect::>(); From ab8d022a4ecc0856e8f403d3ab3208413c93aa78 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Thu, 12 May 2022 23:03:10 -0700 Subject: [PATCH 24/44] Resolve merge conflict --- crates/bevy_reflect/src/type_registry.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index fd87b1ef5d97b..7238feb351a0e 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -4,6 +4,7 @@ use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use serde::Deserialize; use std::{any::TypeId, fmt::Debug, sync::Arc}; +use serde::de::Error; /// A registry of reflected types. #[derive(Default)] @@ -160,14 +161,6 @@ impl TypeRegistry { .map(|registration| registration.type_info()) } - /// Returns the [`TypeInfo`] associated with the given `TypeId`. - /// - /// If the specified type has not been registered, returns `None`. - pub fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo> { - self.get(type_id) - .map(|registration| registration.type_info()) - } - /// Returns an iterator over the [`TypeRegistration`]s of the registered /// types. pub fn iter(&self) -> impl Iterator { From 9a41c8559f1449b476b39435d1ff21fa54049e3f Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Thu, 12 May 2022 23:04:07 -0700 Subject: [PATCH 25/44] Formatting --- crates/bevy_reflect/bevy_reflect_derive/src/lib.rs | 1 - crates/bevy_reflect/src/array.rs | 5 ++++- crates/bevy_reflect/src/impls/std.rs | 6 +++++- crates/bevy_reflect/src/type_registry.rs | 3 +-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs index 2224176abdbe4..8d59def2c0f9b 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/lib.rs @@ -57,7 +57,6 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream { } } - /// Derives the `FromReflect` trait. /// /// This macro supports the following field attributes: diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 71b723629ee0b..c25cbaddc2c87 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -1,4 +1,7 @@ -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed, DynamicInfo}; +use crate::{ + serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, + Typed, +}; use serde::ser::SerializeSeq; use std::{ any::Any, diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 33140387218ac..b037f968d709e 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,5 +1,9 @@ use crate as bevy_reflect; -use crate::{map_partial_eq, serde::Serializable, Array, ArrayInfo, ArrayIter, DynamicMap, FromReflect, FromType, GetTypeRegistration, ListInfo, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, ValueInfo, List}; +use crate::{ + map_partial_eq, serde::Serializable, Array, ArrayInfo, ArrayIter, DynamicMap, FromReflect, + FromType, GetTypeRegistration, List, ListInfo, Map, MapInfo, MapIter, Reflect, + ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, ValueInfo, +}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 7238feb351a0e..71100c7161e73 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -4,7 +4,6 @@ use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use serde::Deserialize; use std::{any::TypeId, fmt::Debug, sync::Arc}; -use serde::de::Error; /// A registry of reflected types. #[derive(Default)] @@ -152,7 +151,7 @@ impl TypeRegistry { self.get_mut(type_id) .and_then(|registration| registration.data_mut::()) } - + /// Returns the [`TypeInfo`] associated with the given `TypeId`. /// /// If the specified type has not been registered, returns `None`. From 16d3ab632aa12e8748aec8d89fc0007403b5d90d Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Thu, 12 May 2022 23:06:50 -0700 Subject: [PATCH 26/44] Fix doc wording --- crates/bevy_reflect/src/array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index c25cbaddc2c87..5e41c06c7af96 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -68,7 +68,7 @@ impl ArrayInfo { &self.item_id } - /// The compile-time capacity of this array, if any + /// The compile-time capacity of this array pub fn capacity(&self) -> usize { self.capacity } From ea9d34b7beab0a7809911cf68ff2ee9d5ef6c7df Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Tue, 17 May 2022 17:14:46 -0700 Subject: [PATCH 27/44] Add Reflect::get_type_info --- .../bevy_reflect_derive/src/impls.rs | 15 +++++ crates/bevy_reflect/src/array.rs | 5 ++ crates/bevy_reflect/src/impls/smallvec.rs | 4 ++ crates/bevy_reflect/src/impls/std.rs | 16 ++++++ crates/bevy_reflect/src/lib.rs | 55 ++++++++++++++++++- crates/bevy_reflect/src/list.rs | 5 ++ crates/bevy_reflect/src/map.rs | 5 ++ crates/bevy_reflect/src/reflect.rs | 9 +++ crates/bevy_reflect/src/struct_trait.rs | 5 ++ crates/bevy_reflect/src/tuple.rs | 11 +++- crates/bevy_reflect/src/tuple_struct.rs | 5 ++ 11 files changed, 131 insertions(+), 4 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs index b885c36d7a20d..aae5194f10196 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs @@ -121,6 +121,11 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { std::any::type_name::() } + #[inline] + fn get_type_info(&self) -> #bevy_reflect_path::TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn std::any::Any { self @@ -271,6 +276,11 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream std::any::type_name::() } + #[inline] + fn get_type_info(&self) -> #bevy_reflect_path::TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn std::any::Any { self @@ -373,6 +383,11 @@ pub(crate) fn impl_value( std::any::type_name::() } + #[inline] + fn get_type_info(&self) -> #bevy_reflect_path::TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn std::any::Any { self diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 5e41c06c7af96..f7a5a68f92da2 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -126,6 +126,11 @@ unsafe impl Reflect for DynamicArray { self.name.as_str() } + #[inline] + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn Any { self diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 27e95512e6c03..0131e0688f11a 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -64,6 +64,10 @@ where std::any::type_name::() } + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + fn any(&self) -> &dyn Any { self } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index b037f968d709e..a7710ce313a87 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -108,6 +108,10 @@ unsafe impl Reflect for Vec { std::any::type_name::() } + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + fn any(&self) -> &dyn Any { self } @@ -232,6 +236,10 @@ unsafe impl Reflect for HashMap { std::any::type_name::() } + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + fn any(&self) -> &dyn Any { self } @@ -356,6 +364,10 @@ unsafe impl Reflect for [T; N] { std::any::type_name::() } + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn Any { self @@ -482,6 +494,10 @@ unsafe impl Reflect for Cow<'static, str> { std::any::type_name::() } + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + fn any(&self) -> &dyn Any { self } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 17b4b12b363a8..a2ab8bd1bf4a6 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -488,9 +488,14 @@ mod tests { // TypeInfo (unsized) assert_eq!( std::any::TypeId::of::(), - ::type_info().id().type_id() + ::type_info().id().type_id() ); + // TypeInfo (instance) + let value: &dyn Reflect = &123; + let info = value.get_type_info(); + assert!(info.id().is::()); + // Struct #[derive(Reflect)] struct MyStruct { @@ -520,6 +525,10 @@ mod tests { panic!("Expected `TypeInfo::Struct`"); } + let value: &dyn Reflect = &MyStruct { foo: 123, bar: 321 }; + let info = value.get_type_info(); + assert!(info.id().is::()); + // Struct (generic) #[derive(Reflect)] struct MyGenericStruct { @@ -547,6 +556,13 @@ mod tests { panic!("Expected `TypeInfo::Struct`"); } + let value: &dyn Reflect = &MyGenericStruct { + foo: String::from("Hello!"), + bar: 321, + }; + let info = value.get_type_info(); + assert!(info.id().is::>()); + // Tuple Struct #[derive(Reflect)] struct MyTupleStruct(usize, i32, MyStruct); @@ -567,6 +583,10 @@ mod tests { panic!("Expected `TypeInfo::TupleStruct`"); } + let value: &dyn Reflect = &MyTupleStruct(123, 321, MyStruct { foo: 123, bar: 321 }); + let info = value.get_type_info(); + assert!(info.id().is::()); + // Tuple type MyTuple = (u32, f32, String); @@ -582,6 +602,10 @@ mod tests { panic!("Expected `TypeInfo::Tuple`"); } + let value: &dyn Reflect = &(123_u32, 1.23_f32, String::from("Hello!")); + let info = value.get_type_info(); + assert!(info.id().is::()); + // List type MyList = Vec; @@ -596,10 +620,14 @@ mod tests { panic!("Expected `TypeInfo::List`"); } + let value: &dyn Reflect = &vec![123_usize]; + let info = value.get_type_info(); + assert!(info.id().is::()); + // List (with capacity) #[cfg(feature = "smallvec")] { - type MyListWithCapacity = smallvec::SmallVec<[String; 123]>; + type MyListWithCapacity = smallvec::SmallVec<[String; 2]>; let info = MyListWithCapacity::type_info(); if let TypeInfo::List(info) = info { @@ -610,10 +638,15 @@ mod tests { info.id().type_name() ); assert_eq!(std::any::type_name::(), info.item().type_name()); - assert_eq!(Some(123usize), info.capacity()); + assert_eq!(Some(2usize), info.capacity()); } else { panic!("Expected `TypeInfo::List`"); } + + let value: MyListWithCapacity = smallvec::smallvec![String::default(); 2]; + let value: &dyn Reflect = &value; + let info = value.get_type_info(); + assert!(info.id().is::()); } // Array @@ -630,6 +663,10 @@ mod tests { panic!("Expected `TypeInfo::Array`"); } + let value: &dyn Reflect = &[1usize, 2usize, 3usize]; + let info = value.get_type_info(); + assert!(info.id().is::()); + // Map type MyMap = HashMap; @@ -645,6 +682,10 @@ mod tests { panic!("Expected `TypeInfo::Map`"); } + let value: &dyn Reflect = &MyMap::new(); + let info = value.get_type_info(); + assert!(info.id().is::()); + // Value type MyValue = String; @@ -656,6 +697,10 @@ mod tests { panic!("Expected `TypeInfo::Value`"); } + let value: &dyn Reflect = &String::from("Hello!"); + let info = value.get_type_info(); + assert!(info.id().is::()); + // Dynamic type MyDynamic = DynamicList; @@ -666,6 +711,10 @@ mod tests { } else { panic!("Expected `TypeInfo::Dynamic`"); } + + let value: &dyn Reflect = &DynamicList::default(); + let info = value.get_type_info(); + assert!(info.id().is::()); } #[test] diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 12a9f38540961..aaf3c7e20d188 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -147,6 +147,11 @@ unsafe impl Reflect for DynamicList { self.name.as_str() } + #[inline] + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn Any { self diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 08b615c9aaf62..645bd2ab6e897 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -177,6 +177,11 @@ unsafe impl Reflect for DynamicMap { &self.name } + #[inline] + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + fn any(&self) -> &dyn Any { self } diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 053193d1a4355..f9b8b76729726 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -55,6 +55,15 @@ pub unsafe trait Reflect: Any + Send + Sync { /// [type name]: std::any::type_name fn type_name(&self) -> &str; + /// Returns the [`TypeInfo`] of the underlying type. + /// + /// This generates a new [`TypeInfo`] on every call. If this method is called + /// frequently, consider using [`TypeRegistry::get_type_info`] to get a cached + /// instance instead. + /// + /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info + fn get_type_info(&self) -> TypeInfo; + /// Returns the value as a [`&dyn Any`][std::any::Any]. fn any(&self) -> &dyn Any; diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 9832d1973a06b..04088b9f04adf 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -327,6 +327,11 @@ unsafe impl Reflect for DynamicStruct { &self.name } + #[inline] + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn Any { self diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index d3cd889f815b1..5c876087a9d2a 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -259,6 +259,11 @@ unsafe impl Reflect for DynamicTuple { self.name() } + #[inline] + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn Any { self @@ -421,6 +426,10 @@ macro_rules! impl_reflect_tuple { std::any::type_name::() } + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + fn any(&self) -> &dyn Any { self } @@ -471,7 +480,7 @@ macro_rules! impl_reflect_tuple { } } - impl <$($name: Typed),*> Typed for ($($name,)*) { + impl <$($name: Reflect),*> Typed for ($($name,)*) { fn type_info() -> TypeInfo { let fields = [ $(UnnamedField::new::<$name>($index),)* diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index a7b2343c81154..e9f50c9dd8879 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -245,6 +245,11 @@ unsafe impl Reflect for DynamicTupleStruct { self.name.as_str() } + #[inline] + fn get_type_info(&self) -> TypeInfo { + ::type_info() + } + #[inline] fn any(&self) -> &dyn Any { self From 55445572da6705854493ea2d6cd615ee1cf6b782 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 18 May 2022 16:53:10 -0700 Subject: [PATCH 28/44] Renamed name -> type_name --- crates/bevy_reflect/src/type_registry.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 71100c7161e73..90d8b84d70148 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -4,6 +4,7 @@ use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use serde::Deserialize; use std::{any::TypeId, fmt::Debug, sync::Arc}; +use serde::de::Error; /// A registry of reflected types. #[derive(Default)] @@ -58,7 +59,7 @@ impl TypeRegistry { .insert(short_name, registration.type_id()); } self.full_name_to_id - .insert(registration.name().to_string(), registration.type_id()); + .insert(registration.type_name().to_string(), registration.type_id()); self.registrations .insert(registration.type_id(), registration); } @@ -265,7 +266,7 @@ impl TypeRegistration { /// Returns the [name] of the type. /// /// [name]: std::any::type_name - pub fn name(&self) -> &'static str { + pub fn type_name(&self) -> &'static str { self.type_info.id().type_name() } From 5d97ea5405e7bab8e24b9bab1200ef0c8ae4a1aa Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 18 May 2022 16:53:40 -0700 Subject: [PATCH 29/44] Formatting --- crates/bevy_reflect/src/map.rs | 5 +---- crates/bevy_reflect/src/struct_trait.rs | 3 +-- crates/bevy_reflect/src/type_registry.rs | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index fdfe11c849a7f..664209f154c4e 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -3,10 +3,7 @@ use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::{ - DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, - Typed, -}; +use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed}; /// An ordered mapping between [`Reflect`] values. /// diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index be072810c344a..3130b3d8a07bd 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,6 +1,5 @@ use crate::{ - DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeIdentity, - TypeInfo, Typed, + DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed, }; use bevy_utils::{Entry, HashMap}; use std::{any::Any, borrow::Cow, slice::Iter}; diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 90d8b84d70148..524469bc796ec 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -2,9 +2,9 @@ use crate::{Reflect, TypeInfo, Typed}; use bevy_utils::{HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use serde::de::Error; use serde::Deserialize; use std::{any::TypeId, fmt::Debug, sync::Arc}; -use serde::de::Error; /// A registry of reflected types. #[derive(Default)] From 43dda0afa22c4c23210ecd5f5760fd66e7fac377 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 18 May 2022 16:59:53 -0700 Subject: [PATCH 30/44] Remove unused import --- crates/bevy_reflect/src/type_registry.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 524469bc796ec..12dbf6a655254 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -2,7 +2,6 @@ use crate::{Reflect, TypeInfo, Typed}; use bevy_utils::{HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use serde::de::Error; use serde::Deserialize; use std::{any::TypeId, fmt::Debug, sync::Arc}; From 51e121409ee7d29fbfc4c343e9abbdb3249d0fbc Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Tue, 24 May 2022 23:24:48 -0700 Subject: [PATCH 31/44] Removed TypeIdentity Replaced with type_name() and type_id() in order to feel more Rusty --- crates/bevy_reflect/src/array.rs | 60 +++++++---- crates/bevy_reflect/src/fields.rs | 66 ++++++++---- crates/bevy_reflect/src/lib.rs | 111 ++++++++++---------- crates/bevy_reflect/src/list.rs | 58 ++++++++--- crates/bevy_reflect/src/map.rs | 76 ++++++++++---- crates/bevy_reflect/src/struct_trait.rs | 33 ++++-- crates/bevy_reflect/src/tuple.rs | 32 ++++-- crates/bevy_reflect/src/tuple_struct.rs | 34 +++++-- crates/bevy_reflect/src/type_info.rs | 124 +++++++++++++---------- crates/bevy_reflect/src/type_registry.rs | 4 +- 10 files changed, 387 insertions(+), 211 deletions(-) diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 9428584738834..be5887a89c0be 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -1,8 +1,6 @@ -use crate::{ - serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, - Typed, -}; +use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use serde::ser::SerializeSeq; +use std::any::TypeId; use std::{ any::Any, hash::{Hash, Hasher}, @@ -43,8 +41,10 @@ pub trait Array: Reflect { /// A container for compile-time array info #[derive(Clone, Debug)] pub struct ArrayInfo { - id: TypeIdentity, - item_id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, + item_type_name: &'static str, + item_type_id: TypeId, capacity: usize, } @@ -52,25 +52,51 @@ impl ArrayInfo { /// Create a new [`ArrayInfo`] pub fn new(capacity: usize) -> Self { Self { - id: TypeIdentity::of::(), - item_id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), + item_type_name: std::any::type_name::(), + item_type_id: TypeId::of::(), capacity, } } - /// The [`TypeIdentity`] of this array - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The compile-time capacity of the array. + pub fn capacity(&self) -> usize { + self.capacity } - /// The [`TypeIdentity`] of this array's item type - pub fn item(&self) -> &TypeIdentity { - &self.item_id + /// The [name] of the underlying type of the array. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name } - /// The compile-time capacity of this array - pub fn capacity(&self) -> usize { - self.capacity + /// The [`TypeId`] of the underlying type of the array. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type of the array. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } + + /// The [name] of the underlying item type. + /// + /// [name]: std::any::type_name + pub fn item_type_name(&self) -> &'static str { + &self.item_type_name + } + + /// The [`TypeId`] of the underlying item type. + pub fn item_type_id(&self) -> TypeId { + self.item_type_id + } + + /// Check if the given type matches the underlying item type. + pub fn item_is(&self) -> bool { + TypeId::of::() == self.item_type_id } } diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 662684a418b83..caba81c9cae35 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -1,66 +1,96 @@ -use crate::{Reflect, TypeIdentity}; +use crate::Reflect; +use std::any::{Any, TypeId}; use std::borrow::Cow; -/// The named field of a reflected struct +/// The named field of a reflected struct. #[derive(Clone, Debug)] pub struct NamedField { name: Cow<'static, str>, - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, } impl NamedField { - /// Create a new [`NamedField`] + /// Create a new [`NamedField`]. pub fn new(name: &str) -> Self { Self { name: Cow::Owned(name.into()), - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), } } - /// Create a new [`NamedField`] using a static string + /// Create a new [`NamedField`] using a static string. /// /// This helps save an allocation when the string has a static lifetime, such /// as when using [`std::any::type_name`]. pub fn static_new(name: &'static str) -> Self { Self { name: Cow::Borrowed(name), - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), } } - /// The name of the field + /// The name of the field. pub fn name(&self) -> &Cow<'static, str> { &self.name } - /// The [`TypeIdentity`] of the field - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The [name] of the underlying type of the field. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type of the field. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type of the field. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } } -/// The unnamed field of a reflected tuple or tuple struct +/// The unnamed field of a reflected tuple or tuple struct. #[derive(Clone, Debug)] pub struct UnnamedField { index: usize, - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, } impl UnnamedField { pub fn new(index: usize) -> Self { Self { index, - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), } } - /// Returns the index of the field + /// Returns the index of the field. pub fn index(&self) -> usize { self.index } - /// The [`TypeIdentity`] of the field - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The [name] of the underlying type of the field. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type of the field. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type of the field. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index a2ab8bd1bf4a6..d4399a341673b 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -482,19 +482,19 @@ mod tests { fn reflect_type_info() { // TypeInfo let info = i32::type_info(); - assert_eq!(std::any::type_name::(), info.id().type_name()); - assert_eq!(std::any::TypeId::of::(), info.id().type_id()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::TypeId::of::(), info.type_id()); // TypeInfo (unsized) assert_eq!( std::any::TypeId::of::(), - ::type_info().id().type_id() + ::type_info().type_id() ); // TypeInfo (instance) - let value: &dyn Reflect = &123; + let value: &dyn Reflect = &123_i32; let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // Struct #[derive(Reflect)] @@ -505,21 +505,21 @@ mod tests { let info = MyStruct::type_info(); if let TypeInfo::Struct(info) = info { - assert!(info.id().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), - info.field("foo").unwrap().id().type_name() + info.field("foo").unwrap().type_name() ); assert_eq!( std::any::TypeId::of::(), - info.field("foo").unwrap().id().type_id() + info.field("foo").unwrap().type_id() ); - assert!(info.field("foo").unwrap().id().is::()); + assert!(info.field("foo").unwrap().is::()); assert_eq!("foo", info.field("foo").unwrap().name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().id().type_name() + info.field_at(1).unwrap().type_name() ); } else { panic!("Expected `TypeInfo::Struct`"); @@ -527,7 +527,7 @@ mod tests { let value: &dyn Reflect = &MyStruct { foo: 123, bar: 321 }; let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // Struct (generic) #[derive(Reflect)] @@ -538,19 +538,19 @@ mod tests { let info = >::type_info(); if let TypeInfo::Struct(info) = info { - assert!(info.id().is::>()); + assert!(info.is::>()); assert_eq!( std::any::type_name::>(), - info.id().type_name() + info.type_name() ); assert_eq!( std::any::type_name::(), - info.field("foo").unwrap().id().type_name() + info.field("foo").unwrap().type_name() ); assert_eq!("foo", info.field("foo").unwrap().name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().id().type_name() + info.field_at(1).unwrap().type_name() ); } else { panic!("Expected `TypeInfo::Struct`"); @@ -561,7 +561,7 @@ mod tests { bar: 321, }; let info = value.get_type_info(); - assert!(info.id().is::>()); + assert!(info.is::>()); // Tuple Struct #[derive(Reflect)] @@ -569,34 +569,31 @@ mod tests { let info = MyTupleStruct::type_info(); if let TypeInfo::TupleStruct(info) = info { - assert!(info.id().is::()); - assert_eq!( - std::any::type_name::(), - info.id().type_name() - ); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().id().type_name() + info.field_at(1).unwrap().type_name() ); - assert!(info.field_at(1).unwrap().id().is::()); + assert!(info.field_at(1).unwrap().is::()); } else { panic!("Expected `TypeInfo::TupleStruct`"); } let value: &dyn Reflect = &MyTupleStruct(123, 321, MyStruct { foo: 123, bar: 321 }); let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // Tuple type MyTuple = (u32, f32, String); let info = MyTuple::type_info(); if let TypeInfo::Tuple(info) = info { - assert!(info.id().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!( std::any::type_name::(), - info.field_at(1).unwrap().id().type_name() + info.field_at(1).unwrap().type_name() ); } else { panic!("Expected `TypeInfo::Tuple`"); @@ -604,17 +601,17 @@ mod tests { let value: &dyn Reflect = &(123_u32, 1.23_f32, String::from("Hello!")); let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // List type MyList = Vec; let info = MyList::type_info(); if let TypeInfo::List(info) = info { - assert!(info.id().is::()); - assert!(info.item().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); - assert_eq!(std::any::type_name::(), info.item().type_name()); + assert!(info.is::()); + assert!(info.item_is::()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::type_name::(), info.item_type_name()); assert_eq!(None, info.capacity()); } else { panic!("Expected `TypeInfo::List`"); @@ -622,7 +619,7 @@ mod tests { let value: &dyn Reflect = &vec![123_usize]; let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // List (with capacity) #[cfg(feature = "smallvec")] @@ -631,13 +628,13 @@ mod tests { let info = MyListWithCapacity::type_info(); if let TypeInfo::List(info) = info { - assert!(info.id().is::()); - assert!(info.item().is::()); + assert!(info.is::()); + assert!(info.item_is::()); assert_eq!( std::any::type_name::(), - info.id().type_name() + info.type_name() ); - assert_eq!(std::any::type_name::(), info.item().type_name()); + assert_eq!(std::any::type_name::(), info.item_type_name()); assert_eq!(Some(2usize), info.capacity()); } else { panic!("Expected `TypeInfo::List`"); @@ -646,7 +643,7 @@ mod tests { let value: MyListWithCapacity = smallvec::smallvec![String::default(); 2]; let value: &dyn Reflect = &value; let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); } // Array @@ -654,10 +651,10 @@ mod tests { let info = MyArray::type_info(); if let TypeInfo::Array(info) = info { - assert!(info.id().is::()); - assert!(info.item().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); - assert_eq!(std::any::type_name::(), info.item().type_name()); + assert!(info.is::()); + assert!(info.item_is::()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::type_name::(), info.item_type_name()); assert_eq!(3, info.capacity()); } else { panic!("Expected `TypeInfo::Array`"); @@ -665,56 +662,56 @@ mod tests { let value: &dyn Reflect = &[1usize, 2usize, 3usize]; let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // Map type MyMap = HashMap; let info = MyMap::type_info(); if let TypeInfo::Map(info) = info { - assert!(info.id().is::()); - assert!(info.key().is::()); - assert!(info.value().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); - assert_eq!(std::any::type_name::(), info.key().type_name()); - assert_eq!(std::any::type_name::(), info.value().type_name()); + assert!(info.is::()); + assert!(info.key_is::()); + assert!(info.value_is::()); + assert_eq!(std::any::type_name::(), info.type_name()); + assert_eq!(std::any::type_name::(), info.key_type_name()); + assert_eq!(std::any::type_name::(), info.value_type_name()); } else { panic!("Expected `TypeInfo::Map`"); } let value: &dyn Reflect = &MyMap::new(); let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // Value type MyValue = String; let info = MyValue::type_info(); if let TypeInfo::Value(info) = info { - assert!(info.id().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); } else { panic!("Expected `TypeInfo::Value`"); } let value: &dyn Reflect = &String::from("Hello!"); let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); // Dynamic type MyDynamic = DynamicList; let info = MyDynamic::type_info(); if let TypeInfo::Dynamic(info) = info { - assert!(info.id().is::()); - assert_eq!(std::any::type_name::(), info.id().type_name()); + assert!(info.is::()); + assert_eq!(std::any::type_name::(), info.type_name()); } else { panic!("Expected `TypeInfo::Dynamic`"); } let value: &dyn Reflect = &DynamicList::default(); let info = value.get_type_info(); - assert!(info.id().is::()); + assert!(info.is::()); } #[test] diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index aaf3c7e20d188..337309dc61795 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,8 +1,8 @@ -use std::any::Any; +use std::any::{Any, TypeId}; use crate::{ serde::Serializable, Array, ArrayIter, DynamicArray, DynamicInfo, FromReflect, Reflect, - ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed, + ReflectMut, ReflectRef, TypeInfo, Typed, }; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. @@ -25,8 +25,10 @@ pub trait List: Reflect + Array { /// A container for compile-time list info #[derive(Clone, Debug)] pub struct ListInfo { - id: TypeIdentity, - item_id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, + item_type_name: &'static str, + item_type_id: TypeId, capacity: Option, } @@ -34,25 +36,51 @@ impl ListInfo { /// Create a new [`ListInfo`] pub fn new(capacity: Option) -> Self { Self { - id: TypeIdentity::of::(), - item_id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), + item_type_name: std::any::type_name::(), + item_type_id: TypeId::of::(), capacity, } } - /// The [`TypeIdentity`] of this list - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The compile-time capacity of the list, if any. + pub fn capacity(&self) -> Option { + self.capacity } - /// The [`TypeIdentity`] of this list's item type - pub fn item(&self) -> &TypeIdentity { - &self.item_id + /// The [type name] of the list. + /// + /// [type name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name } - /// The compile-time capacity of this list, if any - pub fn capacity(&self) -> Option { - self.capacity + /// The [`TypeId`] of the list. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the list type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } + + /// The [type name] of the list item. + /// + /// [type name]: std::any::type_name + pub fn item_type_name(&self) -> &'static str { + &self.item_type_name + } + + /// The [`TypeId`] of the list item. + pub fn item_type_id(&self) -> TypeId { + self.item_type_id + } + + /// Check if the given type matches the list item type. + pub fn item_is(&self) -> bool { + TypeId::of::() == self.item_type_id } } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 664209f154c4e..a64a8f0f32b9a 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -1,9 +1,9 @@ -use std::any::Any; +use std::any::{Any, TypeId}; use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed}; +use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; /// An ordered mapping between [`Reflect`] values. /// @@ -47,34 +47,76 @@ pub trait Map: Reflect { /// A container for compile-time map info #[derive(Clone, Debug)] pub struct MapInfo { - id: TypeIdentity, - key_id: TypeIdentity, - value_id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, + key_type_name: &'static str, + key_type_id: TypeId, + value_type_name: &'static str, + value_type_id: TypeId, } impl MapInfo { /// Create a new [`MapInfo`] pub fn new() -> Self { Self { - id: TypeIdentity::of::(), - key_id: TypeIdentity::of::(), - value_id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), + key_type_name: std::any::type_name::(), + key_type_id: TypeId::of::(), + value_type_name: std::any::type_name::(), + value_type_id: TypeId::of::(), } } - /// The [`TypeIdentity`] of this map - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } + + /// The [name] of the underlying key type. + /// + /// [name]: std::any::type_name + pub fn key_type_name(&self) -> &'static str { + &self.key_type_name + } + + /// The [`TypeId`] of the underlying key type. + pub fn key_type_id(&self) -> TypeId { + self.key_type_id + } + + /// Check if the given type matches the underlying key type. + pub fn key_is(&self) -> bool { + TypeId::of::() == self.key_type_id + } + + /// The [name] of the underlying value type. + /// + /// [name]: std::any::type_name + pub fn value_type_name(&self) -> &'static str { + &self.value_type_name } - /// The [`TypeIdentity`] of this map's key type - pub fn key(&self) -> &TypeIdentity { - &self.key_id + /// The [`TypeId`] of the underlying value type. + pub fn value_type_id(&self) -> TypeId { + self.value_type_id } - /// The [`TypeIdentity`] of this map's value type - pub fn value(&self) -> &TypeIdentity { - &self.value_id + /// Check if the given type matches the underlying value type. + pub fn value_is(&self) -> bool { + TypeId::of::() == self.value_type_id } } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 3130b3d8a07bd..c563db02bc5af 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,7 +1,6 @@ -use crate::{ - DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed, -}; +use crate::{DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use bevy_utils::{Entry, HashMap}; +use std::any::TypeId; use std::{any::Any, borrow::Cow, slice::Iter}; /// A reflected Rust regular struct type. @@ -65,7 +64,8 @@ pub trait Struct: Reflect { /// A container for compile-time struct info #[derive(Clone, Debug)] pub struct StructInfo { - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, fields: Box<[NamedField]>, field_indices: HashMap, usize>, } @@ -88,17 +88,13 @@ impl StructInfo { .collect::>(); Self { - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), fields: fields.to_vec().into_boxed_slice(), field_indices, } } - /// The [`TypeIdentity`] of this struct - pub fn id(&self) -> &TypeIdentity { - &self.id - } - /// Get a field with the given name pub fn field(&self, name: &str) -> Option<&NamedField> { self.field_indices @@ -125,6 +121,23 @@ impl StructInfo { pub fn field_len(&self) -> usize { self.fields.len() } + + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } } /// An iterator over the field values of a struct. diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 27d263557e3ae..ca743cb5f595e 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,9 +1,9 @@ use crate::{ DynamicInfo, FromReflect, FromType, GetTypeRegistration, Reflect, ReflectDeserialize, - ReflectMut, ReflectRef, TypeIdentity, TypeInfo, TypeRegistration, Typed, UnnamedField, + ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, UnnamedField, }; use serde::Deserialize; -use std::any::Any; +use std::any::{Any, TypeId}; use std::slice::Iter; /// A reflected Rust tuple. @@ -127,7 +127,8 @@ impl GetTupleField for dyn Tuple { /// A container for compile-time tuple info #[derive(Clone, Debug)] pub struct TupleInfo { - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, fields: Box<[UnnamedField]>, } @@ -140,16 +141,12 @@ impl TupleInfo { /// pub fn new(fields: &[UnnamedField]) -> Self { Self { - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), fields: fields.to_vec().into_boxed_slice(), } } - /// The [`TypeIdentity`] of this tuple - pub fn id(&self) -> &TypeIdentity { - &self.id - } - /// Get a field at the given index pub fn field_at(&self, index: usize) -> Option<&UnnamedField> { self.fields.get(index) @@ -164,6 +161,23 @@ impl TupleInfo { pub fn field_len(&self) -> usize { self.fields.len() } + + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } } /// A tuple which allows fields to be added at runtime. diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 5aa2449de7440..867a3913eaacd 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,7 +1,5 @@ -use crate::{ - DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeIdentity, TypeInfo, Typed, UnnamedField, -}; -use std::any::Any; +use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, UnnamedField}; +use std::any::{Any, TypeId}; use std::slice::Iter; /// A reflected Rust tuple struct. @@ -49,7 +47,8 @@ pub trait TupleStruct: Reflect { /// A container for compile-time tuple struct info #[derive(Clone, Debug)] pub struct TupleStructInfo { - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, fields: Box<[UnnamedField]>, } @@ -62,16 +61,12 @@ impl TupleStructInfo { /// pub fn new(fields: &[UnnamedField]) -> Self { Self { - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), fields: fields.to_vec().into_boxed_slice(), } } - /// The [`TypeIdentity`] of this struct - pub fn id(&self) -> &TypeIdentity { - &self.id - } - /// Get a field at the given index pub fn field_at(&self, index: usize) -> Option<&UnnamedField> { self.fields.get(index) @@ -86,6 +81,23 @@ impl TupleStructInfo { pub fn field_len(&self) -> usize { self.fields.len() } + + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } } /// An iterator over the field values of a tuple struct. diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 791581728b752..e152a424e0c1b 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -12,41 +12,6 @@ pub trait Typed: Reflect { fn type_info() -> TypeInfo; } -#[derive(Clone, Debug)] -/// Type information used to identify a given type, including its [name] and its [`TypeId`]. -/// -/// [name]: std::any::type_name -pub struct TypeIdentity(&'static str, TypeId); - -impl TypeIdentity { - /// Creates a new [`TypeIdentity`] with the given type name and [`TypeId`] - pub const fn new(name: &'static str, type_id: TypeId) -> Self { - Self(name, type_id) - } - - /// Creates a new [`TypeIdentity`] for the given type - pub fn of() -> Self { - Self(std::any::type_name::(), TypeId::of::()) - } - - /// The [name] of this type - /// - /// [name]: std::any::type_name - pub fn type_name(&self) -> &'static str { - self.0 - } - - /// The [`TypeId`] of this type - pub fn type_id(&self) -> TypeId { - self.1 - } - - /// Check if the given type matches this type - pub fn is(&self) -> bool { - TypeId::of::() == self.1 - } -} - /// Compile-time type information for various reflected types #[derive(Debug, Clone)] pub enum TypeInfo { @@ -64,37 +29,72 @@ pub enum TypeInfo { } impl TypeInfo { - /// The [`TypeIdentity`] of the reflected type - pub fn id(&self) -> &TypeIdentity { + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { match self { - Self::Struct(info) => info.id(), - Self::TupleStruct(info) => info.id(), - Self::Tuple(info) => info.id(), - Self::List(info) => info.id(), - Self::Array(info) => info.id(), - Self::Map(info) => info.id(), - Self::Value(info) => info.id(), - Self::Dynamic(info) => info.id(), + Self::Struct(info) => info.type_id(), + Self::TupleStruct(info) => info.type_id(), + Self::Tuple(info) => info.type_id(), + Self::List(info) => info.type_id(), + Self::Array(info) => info.type_id(), + Self::Map(info) => info.type_id(), + Self::Value(info) => info.type_id(), + Self::Dynamic(info) => info.type_id(), } } + + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + 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::Value(info) => info.type_name(), + Self::Dynamic(info) => info.type_name(), + } + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id() + } } /// A container for compile-time info related to general value types, including primitives #[derive(Debug, Clone)] pub struct ValueInfo { - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, } impl ValueInfo { pub fn new() -> Self { Self { - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), } } - /// The [`TypeIdentity`] of this value - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } } @@ -108,18 +108,32 @@ impl ValueInfo { /// [`DynamicList`]: crate::DynamicList #[derive(Debug, Clone)] pub struct DynamicInfo { - id: TypeIdentity, + type_name: &'static str, + type_id: TypeId, } impl DynamicInfo { pub fn new() -> Self { Self { - id: TypeIdentity::of::(), + type_name: std::any::type_name::(), + type_id: TypeId::of::(), } } - /// The [`TypeIdentity`] of this dynamic value - pub fn id(&self) -> &TypeIdentity { - &self.id + /// The [name] of the underlying type. + /// + /// [name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + &self.type_name + } + + /// The [`TypeId`] of the underlying type. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the underlying type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id } } diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 12dbf6a655254..7efe24e9d3597 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -210,7 +210,7 @@ impl TypeRegistration { /// [`TypeId`]: std::any::TypeId #[inline] pub fn type_id(&self) -> TypeId { - self.type_info.id().type_id() + self.type_info.type_id() } /// Returns a reference to the value of type `T` in this registration's type @@ -266,7 +266,7 @@ impl TypeRegistration { /// /// [name]: std::any::type_name pub fn type_name(&self) -> &'static str { - self.type_info.id().type_name() + self.type_info.type_name() } /// Calculates the short name of a type. From 4c0040acad83dcbeb940f86fa06f3bc6d67b410b Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Tue, 24 May 2022 23:31:07 -0700 Subject: [PATCH 32/44] Change doc wording --- crates/bevy_reflect/src/array.rs | 16 ++++++++-------- crates/bevy_reflect/src/fields.rs | 16 ++++++++-------- crates/bevy_reflect/src/map.rs | 24 ++++++++++++------------ crates/bevy_reflect/src/struct_trait.rs | 8 ++++---- crates/bevy_reflect/src/tuple.rs | 8 ++++---- crates/bevy_reflect/src/tuple_struct.rs | 8 ++++---- crates/bevy_reflect/src/type_info.rs | 16 ++++++++-------- 7 files changed, 48 insertions(+), 48 deletions(-) diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index be5887a89c0be..7d63af0d1b7c3 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -65,36 +65,36 @@ impl ArrayInfo { self.capacity } - /// The [name] of the underlying type of the array. + /// The [type name] of the array. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type of the array. + /// The [`TypeId`] of the array. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type of the array. + /// Check if the given type matches the array type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } - /// The [name] of the underlying item type. + /// The [type name] of the array item. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn item_type_name(&self) -> &'static str { &self.item_type_name } - /// The [`TypeId`] of the underlying item type. + /// The [`TypeId`] of the array item. pub fn item_type_id(&self) -> TypeId { self.item_type_id } - /// Check if the given type matches the underlying item type. + /// Check if the given type matches the array item type. pub fn item_is(&self) -> bool { TypeId::of::() == self.item_type_id } diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index caba81c9cae35..4f8c0b525d645 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -37,19 +37,19 @@ impl NamedField { &self.name } - /// The [name] of the underlying type of the field. + /// The [type name] of the field. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type of the field. + /// The [`TypeId`] of the field. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type of the field. + /// Check if the given type matches the field type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } @@ -77,19 +77,19 @@ impl UnnamedField { self.index } - /// The [name] of the underlying type of the field. + /// The [type name] of the field. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type of the field. + /// The [`TypeId`] of the field. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type of the field. + /// Check if the given type matches the field type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index a64a8f0f32b9a..a95f29a5787a0 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -68,53 +68,53 @@ impl MapInfo { } } - /// The [name] of the underlying type. + /// The [type name] of the map. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type. + /// The [`TypeId`] of the map. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type. + /// Check if the given type matches the map type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } - /// The [name] of the underlying key type. + /// The [type name] of the key. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn key_type_name(&self) -> &'static str { &self.key_type_name } - /// The [`TypeId`] of the underlying key type. + /// The [`TypeId`] of the key. pub fn key_type_id(&self) -> TypeId { self.key_type_id } - /// Check if the given type matches the underlying key type. + /// Check if the given type matches the key type. pub fn key_is(&self) -> bool { TypeId::of::() == self.key_type_id } - /// The [name] of the underlying value type. + /// The [type name] of the value. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn value_type_name(&self) -> &'static str { &self.value_type_name } - /// The [`TypeId`] of the underlying value type. + /// The [`TypeId`] of the value. pub fn value_type_id(&self) -> TypeId { self.value_type_id } - /// Check if the given type matches the underlying value type. + /// Check if the given type matches the value type. pub fn value_is(&self) -> bool { TypeId::of::() == self.value_type_id } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index c563db02bc5af..e6c951fa2faae 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -122,19 +122,19 @@ impl StructInfo { self.fields.len() } - /// The [name] of the underlying type. + /// The [type name] of the struct. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type. + /// The [`TypeId`] of the struct. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type. + /// Check if the given type matches the struct type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index ca743cb5f595e..8b4029496f520 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -162,19 +162,19 @@ impl TupleInfo { self.fields.len() } - /// The [name] of the underlying type. + /// The [type name] of the tuple. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type. + /// The [`TypeId`] of the tuple. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type. + /// Check if the given type matches the tuple type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 867a3913eaacd..70875b80f1698 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -82,19 +82,19 @@ impl TupleStructInfo { self.fields.len() } - /// The [name] of the underlying type. + /// The [type name] of the tuple struct. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type. + /// The [`TypeId`] of the tuple struct. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type. + /// Check if the given type matches the tuple struct type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index e152a424e0c1b..8f983c8c65fd1 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -80,19 +80,19 @@ impl ValueInfo { } } - /// The [name] of the underlying type. + /// The [type name] of the value. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type. + /// The [`TypeId`] of the value. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type. + /// Check if the given type matches the value type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } @@ -120,19 +120,19 @@ impl DynamicInfo { } } - /// The [name] of the underlying type. + /// The [type name] of the dynamic value. /// - /// [name]: std::any::type_name + /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { &self.type_name } - /// The [`TypeId`] of the underlying type. + /// The [`TypeId`] of the dynamic value. pub fn type_id(&self) -> TypeId { self.type_id } - /// Check if the given type matches the underlying type. + /// Check if the given type matches the dynamic value type. pub fn is(&self) -> bool { TypeId::of::() == self.type_id } From c3c54cbfd5c779a9b553f20b3b9feb8b40b9b314 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Tue, 24 May 2022 23:33:46 -0700 Subject: [PATCH 33/44] Combine constructors --- .../bevy_reflect_derive/src/impls.rs | 2 +- crates/bevy_reflect/src/fields.rs | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs index e75c465fc1adc..435972c8b6847 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs @@ -181,7 +181,7 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { impl #impl_generics #bevy_reflect_path::Typed for #struct_name #ty_generics #where_clause { fn type_info() -> #bevy_reflect_path::TypeInfo { let fields: [#bevy_reflect_path::NamedField; #field_count] = [ - #(#bevy_reflect_path::NamedField::static_new::<#field_types>(#field_names),)* + #(#bevy_reflect_path::NamedField::new::<#field_types, _>(#field_names),)* ]; let info = #bevy_reflect_path::StructInfo::new::(&fields); #bevy_reflect_path::TypeInfo::Struct(info) diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 4f8c0b525d645..6100d36f0e642 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -12,21 +12,9 @@ pub struct NamedField { impl NamedField { /// Create a new [`NamedField`]. - pub fn new(name: &str) -> Self { + pub fn new>>(name: TName) -> Self { Self { - name: Cow::Owned(name.into()), - type_name: std::any::type_name::(), - type_id: TypeId::of::(), - } - } - - /// Create a new [`NamedField`] using a static string. - /// - /// This helps save an allocation when the string has a static lifetime, such - /// as when using [`std::any::type_name`]. - pub fn static_new(name: &'static str) -> Self { - Self { - name: Cow::Borrowed(name), + name: name.into(), type_name: std::any::type_name::(), type_id: TypeId::of::(), } From a877911bce960f5d1ba2425267be8105d038fa2d Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Thu, 26 May 2022 00:26:41 -0700 Subject: [PATCH 34/44] Return static TypeInfo from Typed::type_info() --- crates/bevy_reflect/Cargo.toml | 1 + .../bevy_reflect_derive/src/impls.rs | 104 ++++++++---- crates/bevy_reflect/src/array.rs | 8 +- crates/bevy_reflect/src/impls/smallvec.rs | 10 +- crates/bevy_reflect/src/impls/std.rs | 29 ++-- crates/bevy_reflect/src/lib.rs | 1 + crates/bevy_reflect/src/list.rs | 8 +- crates/bevy_reflect/src/map.rs | 8 +- crates/bevy_reflect/src/reflect.rs | 8 +- crates/bevy_reflect/src/struct_trait.rs | 8 +- crates/bevy_reflect/src/tuple.rs | 25 +-- crates/bevy_reflect/src/tuple_struct.rs | 8 +- crates/bevy_reflect/src/type_info.rs | 2 +- crates/bevy_reflect/src/type_registry.rs | 10 +- crates/bevy_reflect/src/utility.rs | 148 ++++++++++++++++++ 15 files changed, 302 insertions(+), 76 deletions(-) create mode 100644 crates/bevy_reflect/src/utility.rs diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index 8d74f36495520..c96b605e4b7d4 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -22,6 +22,7 @@ erased-serde = "0.3" downcast-rs = "1.2" parking_lot = "0.11.0" thiserror = "1.0" +once_cell = "1.11" serde = "1" smallvec = { version = "1.6", features = ["serde", "union", "const_generics"], optional = true } glam = { version = "0.20.0", features = ["serde"], optional = true } diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs index 435972c8b6847..3227d5442f6c4 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs @@ -52,12 +52,27 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { } }); + let typed_impl = impl_typed( + struct_name, + derive_data.generics(), + quote! { + let fields: [#bevy_reflect_path::NamedField; #field_count] = [ + #(#bevy_reflect_path::NamedField::new::<#field_types, _>(#field_names),)* + ]; + let info = #bevy_reflect_path::StructInfo::new::(&fields); + #bevy_reflect_path::TypeInfo::Struct(info) + }, + bevy_reflect_path, + ); + let get_type_registration_impl = derive_data.get_type_registration(); let (impl_generics, ty_generics, where_clause) = derive_data.generics().split_for_impl(); TokenStream::from(quote! { #get_type_registration_impl + #typed_impl + impl #impl_generics #bevy_reflect_path::Struct for #struct_name #ty_generics #where_clause { fn field(&self, name: &str) -> Option<&dyn #bevy_reflect_path::Reflect> { match name { @@ -118,7 +133,7 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { } #[inline] - fn get_type_info(&self) -> #bevy_reflect_path::TypeInfo { + fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { ::type_info() } @@ -177,16 +192,6 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { #serialize_fn } - - impl #impl_generics #bevy_reflect_path::Typed for #struct_name #ty_generics #where_clause { - fn type_info() -> #bevy_reflect_path::TypeInfo { - let fields: [#bevy_reflect_path::NamedField; #field_count] = [ - #(#bevy_reflect_path::NamedField::new::<#field_types, _>(#field_names),)* - ]; - let info = #bevy_reflect_path::StructInfo::new::(&fields); - #bevy_reflect_path::TypeInfo::Struct(info) - } - } }) } @@ -220,10 +225,25 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream } }); + let typed_impl = impl_typed( + struct_name, + derive_data.generics(), + quote! { + let fields: [#bevy_reflect_path::UnnamedField; #field_count] = [ + #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_indices),)* + ]; + let info = #bevy_reflect_path::TupleStructInfo::new::(&fields); + #bevy_reflect_path::TypeInfo::TupleStruct(info) + }, + bevy_reflect_path, + ); + let (impl_generics, ty_generics, where_clause) = derive_data.generics().split_for_impl(); TokenStream::from(quote! { #get_type_registration_impl + #typed_impl + impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name #ty_generics #where_clause { fn field(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { match index { @@ -263,7 +283,7 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream } #[inline] - fn get_type_info(&self) -> #bevy_reflect_path::TypeInfo { + fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { ::type_info() } @@ -321,16 +341,6 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream #serialize_fn } - - impl #impl_generics #bevy_reflect_path::Typed for #struct_name #ty_generics #where_clause { - fn type_info() -> #bevy_reflect_path::TypeInfo { - let fields: [#bevy_reflect_path::UnnamedField; #field_count] = [ - #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_indices),)* - ]; - let info = #bevy_reflect_path::TupleStructInfo::new::(&fields); - #bevy_reflect_path::TypeInfo::TupleStruct(info) - } - } }) } @@ -346,10 +356,22 @@ pub(crate) fn impl_value( let serialize_fn = reflect_traits.get_serialize_impl(bevy_reflect_path); let partial_eq_fn = reflect_traits.get_partial_eq_impl(bevy_reflect_path); + let typed_impl = impl_typed( + type_name, + generics, + quote! { + let info = #bevy_reflect_path::ValueInfo::new::(); + #bevy_reflect_path::TypeInfo::Value(info) + }, + bevy_reflect_path, + ); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); TokenStream::from(quote! { #get_type_registration_impl + #typed_impl + // SAFE: any and any_mut both return self unsafe impl #impl_generics #bevy_reflect_path::Reflect for #type_name #ty_generics #where_clause { #[inline] @@ -358,7 +380,7 @@ pub(crate) fn impl_value( } #[inline] - fn get_type_info(&self) -> #bevy_reflect_path::TypeInfo { + fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { ::type_info() } @@ -417,12 +439,40 @@ pub(crate) fn impl_value( #serialize_fn } + }) +} +fn impl_typed( + type_name: &Ident, + generics: &Generics, + generator: proc_macro2::TokenStream, + bevy_reflect_path: &Path, +) -> proc_macro2::TokenStream { + let is_generic = !generics.params.is_empty(); + + let static_generator = if is_generic { + quote! { + static CELL: #bevy_reflect_path::utility::TypeInfoCell = #bevy_reflect_path::utility::TypeInfoCell::generic(); + CELL.get_or_insert::(|| { + #generator + }) + } + } else { + quote! { + static CELL: #bevy_reflect_path::utility::TypeInfoCell = #bevy_reflect_path::utility::TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| { + #generator + }) + } + }; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + quote! { impl #impl_generics #bevy_reflect_path::Typed for #type_name #ty_generics #where_clause { - fn type_info() -> #bevy_reflect_path::TypeInfo { - let info = #bevy_reflect_path::ValueInfo::new::(); - #bevy_reflect_path::TypeInfo::Value(info) + fn type_info() -> &'static #bevy_reflect_path::TypeInfo { + #static_generator } } - }) + } } diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 7d63af0d1b7c3..1193a99021eaf 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -1,3 +1,4 @@ +use crate::utility::TypeInfoCell; use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use serde::ser::SerializeSeq; use std::any::TypeId; @@ -153,7 +154,7 @@ unsafe impl Reflect for DynamicArray { } #[inline] - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -254,8 +255,9 @@ impl Array for DynamicArray { } impl Typed for DynamicArray { - fn type_info() -> TypeInfo { - TypeInfo::Dynamic(DynamicInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 2f506eb33da7f..c3ce2ee660969 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,6 +1,7 @@ use smallvec::SmallVec; use std::any::Any; +use crate::utility::{TypeInfoCell, TypeInfoGenericCell}; use crate::{ Array, ArrayIter, FromReflect, List, ListInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, }; @@ -63,7 +64,7 @@ where std::any::type_name::() } - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -113,8 +114,11 @@ impl Typed for SmallVec where T::Item: FromReflect + Clone, { - fn type_info() -> TypeInfo { - TypeInfo::List(ListInfo::new::(Some(T::size()))) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::generic(); + CELL.get_or_insert::(|| { + TypeInfo::List(ListInfo::new::(Some(T::size()))) + }) } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index d6f35be61b214..c7625a2954293 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -5,6 +5,7 @@ use crate::{ ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, ValueInfo, }; +use crate::utility::TypeInfoCell; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; use serde::{Deserialize, Serialize}; @@ -110,7 +111,7 @@ unsafe impl Reflect for Vec { std::any::type_name::() } - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -165,8 +166,9 @@ unsafe impl Reflect for Vec { } impl Typed for Vec { - fn type_info() -> TypeInfo { - TypeInfo::List(ListInfo::new::(None)) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::generic(); + CELL.get_or_insert::(|| TypeInfo::List(ListInfo::new::(None))) } } @@ -238,7 +240,7 @@ unsafe impl Reflect for HashMap { std::any::type_name::() } - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -293,8 +295,9 @@ unsafe impl Reflect for HashMap { } impl Typed for HashMap { - fn type_info() -> TypeInfo { - TypeInfo::Map(MapInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::generic(); + CELL.get_or_insert::(|| TypeInfo::Map(MapInfo::new::())) } } @@ -358,7 +361,7 @@ unsafe impl Reflect for [T; N] { std::any::type_name::() } - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -439,8 +442,9 @@ impl FromReflect for [T; N] { } impl Typed for [T; N] { - fn type_info() -> TypeInfo { - TypeInfo::Array(ArrayInfo::new::(N)) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::generic(); + CELL.get_or_insert::(|| TypeInfo::Array(ArrayInfo::new::(N))) } } @@ -488,7 +492,7 @@ unsafe impl Reflect for Cow<'static, str> { std::any::type_name::() } - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -556,8 +560,9 @@ unsafe impl Reflect for Cow<'static, str> { } impl Typed for Cow<'static, str> { - fn type_info() -> TypeInfo { - TypeInfo::Value(ValueInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Value(ValueInfo::new::())) } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index d4399a341673b..2bb42190db4b8 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -28,6 +28,7 @@ mod impls { pub mod serde; pub mod std_traits; +pub mod utility; pub mod prelude { pub use crate::std_traits::*; diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 337309dc61795..0fe5087cdc2ec 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,5 +1,6 @@ use std::any::{Any, TypeId}; +use crate::utility::TypeInfoCell; use crate::{ serde::Serializable, Array, ArrayIter, DynamicArray, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, @@ -176,7 +177,7 @@ unsafe impl Reflect for DynamicList { } #[inline] - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -240,8 +241,9 @@ unsafe impl Reflect for DynamicList { } impl Typed for DynamicList { - fn type_info() -> TypeInfo { - TypeInfo::Dynamic(DynamicInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index a95f29a5787a0..8624b9c771e04 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use bevy_utils::{Entry, HashMap}; +use crate::utility::TypeInfoCell; use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; /// An ordered mapping between [`Reflect`] values. @@ -217,7 +218,7 @@ unsafe impl Reflect for DynamicMap { } #[inline] - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -274,8 +275,9 @@ unsafe impl Reflect for DynamicMap { } impl Typed for DynamicMap { - fn type_info() -> TypeInfo { - TypeInfo::Dynamic(DynamicInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 047295753b857..d9eeb71362d33 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -3,6 +3,7 @@ use crate::{ }; use std::{any::Any, fmt::Debug}; +use crate::utility::TypeInfoCell; pub use bevy_utils::AHasher as ReflectHasher; /// An immutable enumeration of "kinds" of reflected type. @@ -62,7 +63,7 @@ pub unsafe trait Reflect: Any + Send + Sync { /// instance instead. /// /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info - fn get_type_info(&self) -> TypeInfo; + fn get_type_info(&self) -> &'static TypeInfo; /// Returns the value as a [`&dyn Any`][std::any::Any]. fn any(&self) -> &dyn Any; @@ -182,8 +183,9 @@ impl Debug for dyn Reflect { } impl Typed for dyn Reflect { - fn type_info() -> TypeInfo { - TypeInfo::Value(ValueInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Value(ValueInfo::new::())) } } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index e6c951fa2faae..fb13ae5ef07dd 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,3 +1,4 @@ +use crate::utility::TypeInfoCell; use crate::{DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use bevy_utils::{Entry, HashMap}; use std::any::TypeId; @@ -340,7 +341,7 @@ unsafe impl Reflect for DynamicStruct { } #[inline] - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -403,8 +404,9 @@ unsafe impl Reflect for DynamicStruct { } impl Typed for DynamicStruct { - fn type_info() -> TypeInfo { - TypeInfo::Dynamic(DynamicInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 8b4029496f520..f08d3330c863a 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,3 +1,4 @@ +use crate::utility::TypeInfoCell; use crate::{ DynamicInfo, FromReflect, FromType, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, UnnamedField, @@ -273,7 +274,7 @@ unsafe impl Reflect for DynamicTuple { } #[inline] - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -327,8 +328,9 @@ unsafe impl Reflect for DynamicTuple { } impl Typed for DynamicTuple { - fn type_info() -> TypeInfo { - TypeInfo::Dynamic(DynamicInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } @@ -431,7 +433,7 @@ macro_rules! impl_reflect_tuple { std::any::type_name::() } - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -478,12 +480,15 @@ macro_rules! impl_reflect_tuple { } impl <$($name: Reflect),*> Typed for ($($name,)*) { - fn type_info() -> TypeInfo { - let fields = [ - $(UnnamedField::new::<$name>($index),)* - ]; - let info = TupleInfo::new::(&fields); - TypeInfo::Tuple(info) + fn type_info() -> &'static TypeInfo { + static CELL: $crate::utility::TypeInfoCell = $crate::utility::TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| { + let fields = [ + $(UnnamedField::new::<$name>($index),)* + ]; + let info = TupleInfo::new::(&fields); + TypeInfo::Tuple(info) + }) } } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 70875b80f1698..5da08f778689a 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,3 +1,4 @@ +use crate::utility::TypeInfoCell; use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, UnnamedField}; use std::any::{Any, TypeId}; use std::slice::Iter; @@ -257,7 +258,7 @@ unsafe impl Reflect for DynamicTupleStruct { } #[inline] - fn get_type_info(&self) -> TypeInfo { + fn get_type_info(&self) -> &'static TypeInfo { ::type_info() } @@ -319,8 +320,9 @@ unsafe impl Reflect for DynamicTupleStruct { } impl Typed for DynamicTupleStruct { - fn type_info() -> TypeInfo { - TypeInfo::Dynamic(DynamicInfo::new::()) + fn type_info() -> &'static TypeInfo { + static CELL: TypeInfoCell = TypeInfoCell::non_generic(); + CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 8f983c8c65fd1..dab00871a8cd4 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -9,7 +9,7 @@ use std::any::{Any, TypeId}; /// [0]: crate::TypeRegistration::of pub trait Typed: Reflect { /// Returns the compile-time info for the underlying type - fn type_info() -> TypeInfo; + fn type_info() -> &'static TypeInfo; } /// Compile-time type information for various reflected types diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 7efe24e9d3597..4c8b3e2e39581 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -155,7 +155,7 @@ impl TypeRegistry { /// Returns the [`TypeInfo`] associated with the given `TypeId`. /// /// If the specified type has not been registered, returns `None`. - pub fn get_type_info(&self, type_id: TypeId) -> Option<&TypeInfo> { + pub fn get_type_info(&self, type_id: TypeId) -> Option<&'static TypeInfo> { self.get(type_id) .map(|registration| registration.type_info()) } @@ -201,7 +201,7 @@ impl TypeRegistryArc { pub struct TypeRegistration { short_name: String, data: HashMap>, - type_info: TypeInfo, + type_info: &'static TypeInfo, } impl TypeRegistration { @@ -234,8 +234,8 @@ impl TypeRegistration { } /// Returns a reference to the registration's [`TypeInfo`] - pub fn type_info(&self) -> &TypeInfo { - &self.type_info + pub fn type_info(&self) -> &'static TypeInfo { + self.type_info } /// Inserts an instance of `T` into this registration's type data. @@ -323,7 +323,7 @@ impl Clone for TypeRegistration { TypeRegistration { data, short_name: self.short_name.clone(), - type_info: self.type_info.clone(), + type_info: self.type_info, } } } diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs new file mode 100644 index 0000000000000..1b408a203401a --- /dev/null +++ b/crates/bevy_reflect/src/utility.rs @@ -0,0 +1,148 @@ +//! Helpers for working with Bevy reflection. + +use crate::TypeInfo; +use bevy_utils::HashMap; +use once_cell::race::OnceBox; +use parking_lot::RwLock; +use std::any::{Any, TypeId}; + +/// A container for [`TypeInfo`], allowing instances to be stored statically. +/// +/// Under the hood, this manages a [`once_cell`] for either of the two possible types: +/// `Generic` and `NonGeneric`. +/// +/// ## Non-Generic +/// +/// For non-generic types, [`TypeInfoCell`] should be initialized via the [`non_generic`] +/// method. This should be much more performant than the generic alternative, so favor +/// this variant whenever possible. +/// +/// ``` +/// # use std::any::Any; +/// # use bevy_reflect::{Reflect, ReflectMut, ReflectRef, Typed, TypeInfo, ValueInfo}; +/// use bevy_reflect::utility::TypeInfoCell; +/// +/// struct Foo; +/// +/// impl Typed for Foo { +/// fn type_info() -> &'static TypeInfo { +/// static CELL: TypeInfoCell = TypeInfoCell::non_generic(); +/// CELL.get_or_insert::(|| { +/// let info = ValueInfo::new::(); +/// TypeInfo::Value(info) +/// }) +/// } +/// } +/// # +/// # unsafe impl Reflect for Foo { +/// # fn type_name(&self) -> &str { todo!() } +/// # fn get_type_info(&self) -> &'static TypeInfo { todo!() } +/// # fn any(&self) -> &dyn Any { todo!() } +/// # fn any_mut(&mut self) -> &mut dyn Any { 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) -> Result<(), Box> { todo!() } +/// # fn reflect_ref(&self) -> ReflectRef { todo!() } +/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() } +/// # fn clone_value(&self) -> Box { todo!() } +/// # } +/// ``` +/// +/// ## Generic +/// +/// For generic types, [`TypeInfoCell`] should be initialized via the [`generic`] +/// method. This will store multiple instances of [`TypeInfo`], accessible by [`TypeId`]. +/// +/// This allows `Foo` to use the same [`TypeInfoCell`] for monomorphized type. +/// +/// ``` +/// # use std::any::Any; +/// # use std::marker::PhantomData; +/// # use bevy_reflect::{Reflect, ReflectMut, ReflectRef, Typed, TypeInfo, ValueInfo}; +/// use bevy_reflect::utility::TypeInfoCell; +/// +/// struct Foo(PhantomData); +/// +/// impl Typed for Foo { +/// fn type_info() -> &'static TypeInfo { +/// static CELL: TypeInfoCell = TypeInfoCell::generic(); +/// CELL.get_or_insert::(|| { +/// let info = ValueInfo::new::(); +/// TypeInfo::Value(info) +/// }) +/// } +/// } +/// # +/// # unsafe impl Reflect for Foo { +/// # fn type_name(&self) -> &str { todo!() } +/// # fn get_type_info(&self) -> &'static TypeInfo { todo!() } +/// # fn any(&self) -> &dyn Any { todo!() } +/// # fn any_mut(&mut self) -> &mut dyn Any { 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) -> Result<(), Box> { todo!() } +/// # fn reflect_ref(&self) -> ReflectRef { todo!() } +/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() } +/// # fn clone_value(&self) -> Box { todo!() } +/// # } +/// ``` +/// +/// [`once_cell`]: https://docs.rs/once_cell/latest/once_cell/ +/// [`non_generic`]: TypeInfoCell::non_generic +/// [`generic`]: TypeInfoCell::generic +pub struct TypeInfoCell(TypeInfoCellType); + +impl TypeInfoCell { + /// Initialize a [`TypeInfoCell`] for non-generic types. + pub const fn non_generic() -> Self { + Self(TypeInfoCellType::NonGeneric(OnceBox::new())) + } + + /// Initialize a [`TypeInfoCell`] for generic types. + pub const fn generic() -> Self { + Self(TypeInfoCellType::Generic(OnceBox::new())) + } + + /// Returns a reference to the [`TypeInfo`] stored in the cell. + /// + /// If there is no [`TypeInfo`] found, a new one will be generated from the given function. + /// + /// # Generics + /// + /// Generic types, such as `Vec`, store a mapping of [`TypeIds`] to [`TypeInfos`]. This + /// method will then return the correct [`TypeInfo`] reference for the given type `T`. + /// + /// [`TypeIds`]: std::any::TypeId + /// [`TypeInfos`]: TypeInfo + pub fn get_or_insert(&self, f: F) -> &TypeInfo + where + T: Any + ?Sized, + F: FnOnce() -> TypeInfo, + { + match &self.0 { + TypeInfoCellType::NonGeneric(once) => once.get_or_init(|| Box::new(f())), + TypeInfoCellType::Generic(once) => { + let type_id = TypeId::of::(); + let mapping = once.get_or_init(|| Box::new(RwLock::default())); + if let Some(info) = mapping.read().get(&type_id) { + return info; + } + + mapping.write().entry(type_id).or_insert_with(|| { + // We leak here in order to obtain a `&'static` reference. + // Otherwise, we won't be able to return a reference due to the `RwLock`. + // This should be okay, though, since we expect it to remain statically + // available over the course of the application. + Box::leak(Box::new(f())) + }) + } + } + } +} + +enum TypeInfoCellType { + NonGeneric(OnceBox), + Generic(OnceBox>>), +} From 63c284f85eac21703697198a493dd19bef53aca4 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Thu, 26 May 2022 00:45:33 -0700 Subject: [PATCH 35/44] Remove extraneous import --- crates/bevy_reflect/src/impls/smallvec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index c3ce2ee660969..da8b4f48841c1 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,7 +1,7 @@ use smallvec::SmallVec; use std::any::Any; -use crate::utility::{TypeInfoCell, TypeInfoGenericCell}; +use crate::utility::TypeInfoCell; use crate::{ Array, ArrayIter, FromReflect, List, ListInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, }; From aa5178e7736a6f8252e10e543e52722107649d3f Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Thu, 26 May 2022 17:08:44 -0700 Subject: [PATCH 36/44] Fix clippy warnings --- crates/bevy_reflect/src/array.rs | 4 ++-- crates/bevy_reflect/src/fields.rs | 4 ++-- crates/bevy_reflect/src/list.rs | 4 ++-- crates/bevy_reflect/src/map.rs | 6 +++--- crates/bevy_reflect/src/struct_trait.rs | 2 +- crates/bevy_reflect/src/tuple.rs | 2 +- crates/bevy_reflect/src/tuple_struct.rs | 2 +- crates/bevy_reflect/src/type_info.rs | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 1193a99021eaf..aac72fb09cd41 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -70,7 +70,7 @@ impl ArrayInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the array. @@ -87,7 +87,7 @@ impl ArrayInfo { /// /// [type name]: std::any::type_name pub fn item_type_name(&self) -> &'static str { - &self.item_type_name + self.item_type_name } /// The [`TypeId`] of the array item. diff --git a/crates/bevy_reflect/src/fields.rs b/crates/bevy_reflect/src/fields.rs index 6100d36f0e642..21dc9ec5f75e2 100644 --- a/crates/bevy_reflect/src/fields.rs +++ b/crates/bevy_reflect/src/fields.rs @@ -29,7 +29,7 @@ impl NamedField { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the field. @@ -69,7 +69,7 @@ impl UnnamedField { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the field. diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 0fe5087cdc2ec..2cba576f9a055 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -54,7 +54,7 @@ impl ListInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the list. @@ -71,7 +71,7 @@ impl ListInfo { /// /// [type name]: std::any::type_name pub fn item_type_name(&self) -> &'static str { - &self.item_type_name + self.item_type_name } /// The [`TypeId`] of the list item. diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 8624b9c771e04..99a877cacab07 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -73,7 +73,7 @@ impl MapInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the map. @@ -90,7 +90,7 @@ impl MapInfo { /// /// [type name]: std::any::type_name pub fn key_type_name(&self) -> &'static str { - &self.key_type_name + self.key_type_name } /// The [`TypeId`] of the key. @@ -107,7 +107,7 @@ impl MapInfo { /// /// [type name]: std::any::type_name pub fn value_type_name(&self) -> &'static str { - &self.value_type_name + self.value_type_name } /// The [`TypeId`] of the value. diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index fb13ae5ef07dd..47b5676de3891 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -127,7 +127,7 @@ impl StructInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the struct. diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index f08d3330c863a..7529eda018a68 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -167,7 +167,7 @@ impl TupleInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the tuple. diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 5da08f778689a..6a60c9f184e14 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -87,7 +87,7 @@ impl TupleStructInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the tuple struct. diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index dab00871a8cd4..70201b957c665 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -84,7 +84,7 @@ impl ValueInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the value. @@ -124,7 +124,7 @@ impl DynamicInfo { /// /// [type name]: std::any::type_name pub fn type_name(&self) -> &'static str { - &self.type_name + self.type_name } /// The [`TypeId`] of the dynamic value. From e87c24b10c2fbc64d1a77cb2ddb589ba875ccd94 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Mon, 30 May 2022 15:08:12 -0700 Subject: [PATCH 37/44] Fix incorrect non-generic TypeInfoCell --- crates/bevy_reflect/src/tuple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 2b50614d51f6b..f41f7898d50c0 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -514,7 +514,7 @@ macro_rules! impl_reflect_tuple { impl <$($name: Reflect),*> Typed for ($($name,)*) { fn type_info() -> &'static TypeInfo { - static CELL: $crate::utility::TypeInfoCell = $crate::utility::TypeInfoCell::non_generic(); + static CELL: $crate::utility::TypeInfoCell = $crate::utility::TypeInfoCell::generic(); CELL.get_or_insert::(|| { let fields = [ $(UnnamedField::new::<$name>($index),)* From 1e7cbd8e0c8f76759c51f87b2821a1b824e5de63 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Mon, 30 May 2022 15:09:07 -0700 Subject: [PATCH 38/44] Use TypeInfo to default trait methods --- .../bevy_reflect_derive/src/impls.rs | 43 +-------- crates/bevy_reflect/src/struct_trait.rs | 95 ++++++++++++++++--- crates/bevy_reflect/src/tuple.rs | 28 ++++-- crates/bevy_reflect/src/tuple_struct.rs | 19 +++- 4 files changed, 121 insertions(+), 64 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs index e6f0dff24519c..3b89fff014f48 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs @@ -36,8 +36,6 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { .active_fields() .map(|field| field.data.ty.clone()) .collect::>(); - let field_count = field_idents.len(); - let field_indices = (0..field_count).collect::>(); let hash_fn = derive_data.traits().get_hash_impl(bevy_reflect_path); let serialize_fn = derive_data.traits().get_serialize_impl(bevy_reflect_path); @@ -57,7 +55,7 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { struct_name, derive_data.generics(), quote! { - let fields: [#bevy_reflect_path::NamedField; #field_count] = [ + let fields = [ #(#bevy_reflect_path::NamedField::new::<#field_types, _>(#field_names),)* ]; let info = #bevy_reflect_path::StructInfo::new::(&fields); @@ -89,31 +87,6 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { } } - fn field_at(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { - match index { - #(#field_indices => Some(&self.#field_idents),)* - _ => None, - } - } - - fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> { - match index { - #(#field_indices => Some(&mut self.#field_idents),)* - _ => None, - } - } - - fn name_at(&self, index: usize) -> Option<&str> { - match index { - #(#field_indices => Some(#field_names),)* - _ => None, - } - } - - fn field_len(&self) -> usize { - #field_count - } - fn iter_fields(&self) -> #bevy_reflect_path::FieldIter { #bevy_reflect_path::FieldIter::new(self) } @@ -212,8 +185,6 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream .active_fields() .map(|field| field.data.ty.clone()) .collect::>(); - let field_count = field_idents.len(); - let field_indices = (0..field_count).collect::>(); let hash_fn = derive_data.traits().get_hash_impl(bevy_reflect_path); let serialize_fn = derive_data.traits().get_serialize_impl(bevy_reflect_path); @@ -233,8 +204,8 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream struct_name, derive_data.generics(), quote! { - let fields: [#bevy_reflect_path::UnnamedField; #field_count] = [ - #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_indices),)* + let fields = [ + #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_idents),)* ]; let info = #bevy_reflect_path::TupleStructInfo::new::(&fields); #bevy_reflect_path::TypeInfo::TupleStruct(info) @@ -251,22 +222,18 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name #ty_generics #where_clause { fn field(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { match index { - #(#field_indices => Some(&self.#field_idents),)* + #(#field_idents => Some(&self.#field_idents),)* _ => None, } } fn field_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> { match index { - #(#field_indices => Some(&mut self.#field_idents),)* + #(#field_idents => Some(&mut self.#field_idents),)* _ => None, } } - fn field_len(&self) -> usize { - #field_count - } - fn iter_fields(&self) -> #bevy_reflect_path::TupleStructFieldIter { #bevy_reflect_path::TupleStructFieldIter::new(self) } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 5af797b25dc80..ca9fdcfdd4fc1 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,6 +1,7 @@ use crate::utility::TypeInfoCell; use crate::{DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use bevy_utils::{Entry, HashMap}; +use std::borrow::Borrow; use std::fmt::{Debug, Formatter}; use std::{ any::{Any, TypeId}, @@ -45,25 +46,91 @@ pub trait Struct: Reflect { /// `&mut dyn Reflect`. fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>; - /// Returns a reference to the value of the field with index `index` as a - /// `&dyn Reflect`. - fn field_at(&self, index: usize) -> Option<&dyn Reflect>; - - /// Returns a mutable reference to the value of the field with index `index` - /// as a `&mut dyn Reflect`. - fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; - - /// Returns the name of the field with index `index`. - fn name_at(&self, index: usize) -> Option<&str>; - - /// Returns the number of fields in the struct. - fn field_len(&self) -> usize; - /// Returns an iterator over the values of the struct's fields. fn iter_fields(&self) -> FieldIter; /// Clones the struct into a [`DynamicStruct`]. fn clone_dynamic(&self) -> DynamicStruct; + + /// Returns the number of fields in the struct. + /// + /// # Panics + /// + /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not + /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions + /// include [`DynamicStruct`] which uses its own implementation of this method to + /// prevent the panic. + fn field_len(&self) -> usize { + if let TypeInfo::Struct(info) = self.get_type_info() { + info.field_len() + } else { + panic!( + "tuple `{:?}` is not `TypeInfo::Struct`", + std::any::type_name::() + ); + } + } + + /// Returns the name of the field with index `index`. + /// + /// # Panics + /// + /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not + /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions + /// include [`DynamicStruct`] which uses its own implementation of this method to + /// prevent the panic. + fn name_at(&self, index: usize) -> Option<&str> { + if let TypeInfo::Struct(info) = self.get_type_info() { + info.field_at(index).map(|field| field.name().borrow()) + } else { + panic!( + "tuple `{:?}` is not `TypeInfo::Struct`", + std::any::type_name::() + ); + } + } + + /// Returns a reference to the value of the field with index `index` as a + /// `&dyn Reflect`. + /// + /// # Panics + /// + /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not + /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions + /// include [`DynamicStruct`] which uses its own implementation of this method to + /// prevent the panic. + fn field_at(&self, index: usize) -> Option<&dyn Reflect> { + if let TypeInfo::Struct(info) = self.get_type_info() { + let name = info.field_at(index)?.name(); + self.field(name) + } else { + panic!( + "tuple `{:?}` is not `TypeInfo::Struct`", + std::any::type_name::() + ); + } + } + + /// Returns a mutable reference to the value of the field with index `index` + /// as a `&mut dyn Reflect`. + /// + /// # Panics + /// + /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not + /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions + /// include [`DynamicStruct`] which uses its own implementation of this method to + /// prevent the panic. + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + if let TypeInfo::Struct(info) = self.get_type_info() { + let name = info.field_at(index)?.name(); + self.field_mut(name) + } else { + panic!( + "tuple `{:?}` is not `TypeInfo::Struct`", + std::any::type_name::() + ); + } + } } /// A container for compile-time struct info diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index f41f7898d50c0..1ffa75da61fdc 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -35,14 +35,30 @@ pub trait Tuple: Reflect { /// as a `&mut dyn Reflect`. fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; - /// Returns the number of fields in the tuple. - fn field_len(&self) -> usize; - /// Returns an iterator over the values of the tuple's fields. fn iter_fields(&self) -> TupleFieldIter; /// Clones the struct into a [`DynamicTuple`]. fn clone_dynamic(&self) -> DynamicTuple; + + /// Returns the number of fields in the tuple. + /// + /// # Panics + /// + /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not + /// [`TypeInfo::Tuple`]— which should almost never be the case. Notable exceptions + /// include [`DynamicTuple`] which uses its own implementation of this method to + /// prevent the panic. + fn field_len(&self) -> usize { + if let TypeInfo::Tuple(info) = self.get_type_info() { + info.field_len() + } else { + panic!( + "tuple `{:?}` is not `TypeInfo::Tuple`", + std::any::type_name::() + ); + } + } } /// An iterator over the field values of a tuple. @@ -432,12 +448,6 @@ macro_rules! impl_reflect_tuple { } } - #[inline] - fn field_len(&self) -> usize { - let indices: &[usize] = &[$($index as usize),*]; - indices.len() - } - #[inline] fn iter_fields(&self) -> TupleFieldIter { TupleFieldIter { diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index ba4b593e1e881..cd2934e3b9a4c 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -36,14 +36,27 @@ pub trait TupleStruct: Reflect { /// as a `&mut dyn Reflect`. fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; - /// Returns the number of fields in the tuple struct. - fn field_len(&self) -> usize; - /// Returns an iterator over the values of the tuple struct's fields. fn iter_fields(&self) -> TupleStructFieldIter; /// Clones the struct into a [`DynamicTupleStruct`]. fn clone_dynamic(&self) -> DynamicTupleStruct; + + /// Returns the number of fields in the tuple struct. + /// + /// # Panics + /// + /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not + /// [`TypeInfo::TupleStruct`]— which should almost never be the case. Notable exceptions + /// include [`DynamicTupleStruct`] which uses its own implementation of this method to + /// prevent the panic. + fn field_len(&self) -> usize { + if let TypeInfo::TupleStruct(info) = self.get_type_info() { + info.field_len() + } else { + 0 + } + } } /// A container for compile-time tuple struct info From ee38b7607636378a0e7e648496495a8a4d598f58 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Fri, 3 Jun 2022 22:53:05 -0700 Subject: [PATCH 39/44] Improve docs --- crates/bevy_reflect/src/array.rs | 9 +- crates/bevy_reflect/src/list.rs | 4 +- crates/bevy_reflect/src/map.rs | 4 +- crates/bevy_reflect/src/reflect.rs | 7 +- crates/bevy_reflect/src/struct_trait.rs | 14 ++-- crates/bevy_reflect/src/tuple.rs | 10 +-- crates/bevy_reflect/src/tuple_struct.rs | 10 +-- crates/bevy_reflect/src/type_info.rs | 104 +++++++++++++++++++++--- crates/bevy_reflect/src/utility.rs | 7 +- 9 files changed, 130 insertions(+), 39 deletions(-) diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index a0c7c84e392e3..946533b86e77d 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -38,7 +38,7 @@ pub trait Array: Reflect { } } -/// A container for compile-time array info +/// A container for compile-time array info. #[derive(Clone, Debug)] pub struct ArrayInfo { type_name: &'static str, @@ -49,7 +49,12 @@ pub struct ArrayInfo { } impl ArrayInfo { - /// Create a new [`ArrayInfo`] + /// Create a new [`ArrayInfo`]. + /// + /// # Arguments + /// + /// * `capacity`: The maximum capacity of the underlying array. + /// pub fn new(capacity: usize) -> Self { Self { type_name: std::any::type_name::(), diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index e85bdcd04ffdc..77cf3eebf36ac 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -24,7 +24,7 @@ pub trait List: Reflect + Array { } } -/// A container for compile-time list info +/// A container for compile-time list info. #[derive(Clone, Debug)] pub struct ListInfo { type_name: &'static str, @@ -35,7 +35,7 @@ pub struct ListInfo { } impl ListInfo { - /// Create a new [`ListInfo`] + /// Create a new [`ListInfo`]. pub fn new(capacity: Option) -> Self { Self { type_name: std::any::type_name::(), diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 7d9a9654d5b4c..53c865e8bf007 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -46,7 +46,7 @@ pub trait Map: Reflect { fn clone_dynamic(&self) -> DynamicMap; } -/// A container for compile-time map info +/// A container for compile-time map info. #[derive(Clone, Debug)] pub struct MapInfo { type_name: &'static str, @@ -58,7 +58,7 @@ pub struct MapInfo { } impl MapInfo { - /// Create a new [`MapInfo`] + /// Create a new [`MapInfo`]. pub fn new() -> Self { Self { type_name: std::any::type_name::(), diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 5aa8dff07fa6d..2fb49c5a05163 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -59,9 +59,10 @@ pub unsafe trait Reflect: Any + Send + Sync { /// Returns the [`TypeInfo`] of the underlying type. /// - /// This generates a new [`TypeInfo`] on every call. If this method is called - /// frequently, consider using [`TypeRegistry::get_type_info`] to get a cached - /// instance instead. + /// This method is great if you have an instance of a type or a `dyn Reflect`, + /// and want to access its [`TypeInfo`]. However, if this method is to be called + /// frequently, consider using [`TypeRegistry::get_type_info`] as it can be more + /// performant for such use cases. /// /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info fn get_type_info(&self) -> &'static TypeInfo; diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index ca9fdcfdd4fc1..123c46bcd48cc 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -133,7 +133,7 @@ pub trait Struct: Reflect { } } -/// A container for compile-time struct info +/// A container for compile-time struct info. #[derive(Clone, Debug)] pub struct StructInfo { type_name: &'static str, @@ -143,7 +143,7 @@ pub struct StructInfo { } impl StructInfo { - /// Create a new [`StructInfo`] + /// Create a new [`StructInfo`]. /// /// # Arguments /// @@ -167,29 +167,29 @@ impl StructInfo { } } - /// Get a field with the given name + /// Get the field with the given name. pub fn field(&self, name: &str) -> Option<&NamedField> { self.field_indices .get(name) .map(|index| &self.fields[*index]) } - /// Get a field at the given index + /// Get the field at the given index. pub fn field_at(&self, index: usize) -> Option<&NamedField> { self.fields.get(index) } - /// Get the index of a field with the given name + /// Get the index of the field with the given name. pub fn index_of(&self, name: &str) -> Option { self.field_indices.get(name).copied() } - /// Iterate over the fields of this struct + /// Iterate over the fields of this struct. pub fn iter(&self) -> Iter<'_, NamedField> { self.fields.iter() } - /// The total number of fields in this struct + /// The total number of fields in this struct. pub fn field_len(&self) -> usize { self.fields.len() } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 1ffa75da61fdc..80f0cc445fd84 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -142,7 +142,7 @@ impl GetTupleField for dyn Tuple { } } -/// A container for compile-time tuple info +/// A container for compile-time tuple info. #[derive(Clone, Debug)] pub struct TupleInfo { type_name: &'static str, @@ -151,7 +151,7 @@ pub struct TupleInfo { } impl TupleInfo { - /// Create a new [`TupleInfo`] + /// Create a new [`TupleInfo`]. /// /// # Arguments /// @@ -165,17 +165,17 @@ impl TupleInfo { } } - /// Get a field at the given index + /// Get the field at the given index. pub fn field_at(&self, index: usize) -> Option<&UnnamedField> { self.fields.get(index) } - /// Iterate over the fields of this tuple + /// Iterate over the fields of this tuple. pub fn iter(&self) -> Iter<'_, UnnamedField> { self.fields.iter() } - /// The total number of fields in this tuple + /// The total number of fields in this tuple. pub fn field_len(&self) -> usize { self.fields.len() } diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index cd2934e3b9a4c..2a3401a605117 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -59,7 +59,7 @@ pub trait TupleStruct: Reflect { } } -/// A container for compile-time tuple struct info +/// A container for compile-time tuple struct info. #[derive(Clone, Debug)] pub struct TupleStructInfo { type_name: &'static str, @@ -68,7 +68,7 @@ pub struct TupleStructInfo { } impl TupleStructInfo { - /// Create a new [`TupleStructInfo`] + /// Create a new [`TupleStructInfo`]. /// /// # Arguments /// @@ -82,17 +82,17 @@ impl TupleStructInfo { } } - /// Get a field at the given index + /// Get the field at the given index. pub fn field_at(&self, index: usize) -> Option<&UnnamedField> { self.fields.get(index) } - /// Iterate over the fields of this struct + /// Iterate over the fields of this struct. pub fn iter(&self) -> Iter<'_, UnnamedField> { self.fields.iter() } - /// The total number of fields in this struct + /// The total number of fields in this struct. pub fn field_len(&self) -> usize { self.fields.len() } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 70201b957c665..ea9b4f3ca150f 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -1,18 +1,95 @@ use crate::{ArrayInfo, ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo}; use std::any::{Any, TypeId}; -/// A static accessor to compile-time type information +/// A static accessor to compile-time type information. /// -/// This is used by the `#[derive(Reflect)]` macro to generate an implementation -/// of [`TypeInfo`] to pass to register via [`TypeRegistration::of`][0]. +/// This trait is automatically implemented by the `#[derive(Reflect)]` macro +/// and allows type information to be processed without an instance of that type. /// -/// [0]: crate::TypeRegistration::of +/// # Implementing +/// +/// While it is recommended to leave implementing this trait to the `#[derive(Reflect)]` macro, +/// it is possible to implement this trait manually. If a manual implementation is needed, +/// you _must_ ensure that the information you provide is correct, otherwise various systems that +/// rely on this trait may fail in unexpected ways. +/// +/// Implementors may have difficulty in generating a reference to [`TypeInfo`] with a static +/// lifetime. Luckily, this crate comes with a utility struct, [`TypeInfoCell`], to make +/// generating these statics much simpler. +/// +/// # Example +/// +/// ``` +/// # use std::any::Any; +/// # use bevy_reflect::{NamedField, Reflect, ReflectMut, ReflectRef, StructInfo, TypeInfo, ValueInfo}; +/// # use bevy_reflect::utility::TypeInfoCell; +/// use bevy_reflect::Typed; +/// +/// struct MyStruct { +/// foo: usize, +/// bar: (f32, f32) +/// } +/// +/// impl Typed for MyStruct { +/// fn type_info() -> &'static TypeInfo { +/// static CELL: TypeInfoCell = TypeInfoCell::non_generic(); +/// CELL.get_or_insert::(|| { +/// let fields = [ +/// NamedField::new::("foo"), +/// NamedField::new::<(f32, f32), _>("bar"), +/// ]; +/// let info = StructInfo::new::(&fields); +/// TypeInfo::Struct(info) +/// }) +/// } +/// } +/// +/// # +/// # unsafe impl Reflect for MyStruct { +/// # fn type_name(&self) -> &str { todo!() } +/// # fn get_type_info(&self) -> &'static TypeInfo { todo!() } +/// # fn any(&self) -> &dyn Any { todo!() } +/// # fn any_mut(&mut self) -> &mut dyn Any { 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) -> Result<(), Box> { todo!() } +/// # fn reflect_ref(&self) -> ReflectRef { todo!() } +/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() } +/// # fn clone_value(&self) -> Box { todo!() } +/// # } +/// ``` +/// +/// [`TypeInfoCell`]: crate::utility::TypeInfoCell pub trait Typed: Reflect { - /// Returns the compile-time info for the underlying type + /// Returns the compile-time [info] for the underlying type. + /// + /// [info]: TypeInfo fn type_info() -> &'static TypeInfo; } -/// Compile-time type information for various reflected types +/// Compile-time type information for various reflected types. +/// +/// Generally, for any given type, this value can be retrieved one of three ways: +/// +/// 1. [`Typed::type_info`] +/// 2. [`Reflect::get_type_info`] +/// 3. [`TypeRegistry::get_type_info`] +/// +/// 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_type_info`]. +/// Lastly, if all you have is a [`TypeId`] or [type name], 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 +/// it can be more performant. This is because those other methods may require attaining a lock on +/// the static [`TypeInfo`], while the registry simply checks a map. +/// +/// [`Reflect::get_type_info`]: crate::Reflect::get_type_info +/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info +/// [`TypeId`]: std::any::TypeId +/// [type name]: std::any::type_name #[derive(Debug, Clone)] pub enum TypeInfo { Struct(StructInfo), @@ -22,9 +99,9 @@ pub enum TypeInfo { Array(ArrayInfo), Map(MapInfo), Value(ValueInfo), - /// Type information for "dynamic" types whose metadata can't be known at compile-time + /// Type information for "dynamic" types whose metadata can't be known at compile-time. /// - /// This includes structs like [`DynamicStruct`](crate::DynamicStruct) and [`DynamicList`](crate::DynamicList) + /// This includes structs like [`DynamicStruct`](crate::DynamicStruct) and [`DynamicList`](crate::DynamicList). Dynamic(DynamicInfo), } @@ -65,7 +142,14 @@ impl TypeInfo { } } -/// A container for compile-time info related to general value types, including primitives +/// A container for compile-time info related to general value types, including primitives. +/// +/// This typically represents a type which cannot be broken down any further. This is often +/// due to technical reasons (or by definition), but it can also be a purposeful choice. +/// +/// For example, [`i32`] cannot be broken down any further, so it is represented by a [`ValueInfo`]. +/// And while [`String`] itself is a struct, it's fields are private, so we don't really treat +/// 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, @@ -98,7 +182,7 @@ impl ValueInfo { } } -/// A container for compile-time info related to general Bevy's _dynamic_ types, including primitives. +/// A container for compile-time info related to Bevy's _dynamic_ types, including primitives. /// /// This is functionally the same as [`ValueInfo`], however, semantically it refers to dynamic /// types such as [`DynamicStruct`], [`DynamicTuple`], [`DynamicList`], etc. diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs index 1b408a203401a..d67d788864412 100644 --- a/crates/bevy_reflect/src/utility.rs +++ b/crates/bevy_reflect/src/utility.rs @@ -13,7 +13,7 @@ use std::any::{Any, TypeId}; /// /// ## Non-Generic /// -/// For non-generic types, [`TypeInfoCell`] should be initialized via the [`non_generic`] +/// For non-generic impls, [`TypeInfoCell`] should be initialized via the [`non_generic`] /// method. This should be much more performant than the generic alternative, so favor /// this variant whenever possible. /// @@ -51,10 +51,11 @@ use std::any::{Any, TypeId}; /// /// ## Generic /// -/// For generic types, [`TypeInfoCell`] should be initialized via the [`generic`] +/// For generic impls, [`TypeInfoCell`] should be initialized via the [`generic`] /// method. This will store multiple instances of [`TypeInfo`], accessible by [`TypeId`]. /// -/// This allows `Foo` to use the same [`TypeInfoCell`] for monomorphized type. +/// This allows `Foo` to use the same [`TypeInfoCell`] for monomorphized type. The same +/// applies to blanket impls. /// /// ``` /// # use std::any::Any; From f8b4d07e14c3858d0e9c4c3eb4c5023baa160201 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Fri, 3 Jun 2022 22:55:55 -0700 Subject: [PATCH 40/44] Remove ListInfo capacity --- crates/bevy_reflect/src/impls/smallvec.rs | 4 +--- crates/bevy_reflect/src/impls/std.rs | 2 +- crates/bevy_reflect/src/lib.rs | 2 -- crates/bevy_reflect/src/list.rs | 9 +-------- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index da8b4f48841c1..facd6a45d0bb4 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -116,9 +116,7 @@ where { fn type_info() -> &'static TypeInfo { static CELL: TypeInfoCell = TypeInfoCell::generic(); - CELL.get_or_insert::(|| { - TypeInfo::List(ListInfo::new::(Some(T::size()))) - }) + CELL.get_or_insert::(|| TypeInfo::List(ListInfo::new::())) } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 75e61b5eeefd8..5d2a0e1e9cdee 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -168,7 +168,7 @@ unsafe impl Reflect for Vec { impl Typed for Vec { fn type_info() -> &'static TypeInfo { static CELL: TypeInfoCell = TypeInfoCell::generic(); - CELL.get_or_insert::(|| TypeInfo::List(ListInfo::new::(None))) + CELL.get_or_insert::(|| TypeInfo::List(ListInfo::new::())) } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 4528bc391aca2..5078b17e1eeea 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -675,7 +675,6 @@ mod tests { assert!(info.item_is::()); assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::type_name::(), info.item_type_name()); - assert_eq!(None, info.capacity()); } else { panic!("Expected `TypeInfo::List`"); } @@ -698,7 +697,6 @@ mod tests { info.type_name() ); assert_eq!(std::any::type_name::(), info.item_type_name()); - assert_eq!(Some(2usize), info.capacity()); } else { panic!("Expected `TypeInfo::List`"); } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 77cf3eebf36ac..d0d2f9de26525 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -31,26 +31,19 @@ pub struct ListInfo { type_id: TypeId, item_type_name: &'static str, item_type_id: TypeId, - capacity: Option, } impl ListInfo { /// Create a new [`ListInfo`]. - pub fn new(capacity: Option) -> Self { + pub fn new() -> Self { Self { type_name: std::any::type_name::(), type_id: TypeId::of::(), item_type_name: std::any::type_name::(), item_type_id: TypeId::of::(), - capacity, } } - /// The compile-time capacity of the list, if any. - pub fn capacity(&self) -> Option { - self.capacity - } - /// The [type name] of the list. /// /// [type name]: std::any::type_name From 38b261100336cf17040b48cea425d7ca4806bec2 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Fri, 3 Jun 2022 22:58:46 -0700 Subject: [PATCH 41/44] Replace list capacity references --- crates/bevy_reflect/src/lib.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 5078b17e1eeea..5519b8031841c 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -683,28 +683,25 @@ mod tests { let info = value.get_type_info(); assert!(info.is::()); - // List (with capacity) + // List (SmallVec) #[cfg(feature = "smallvec")] { - type MyListWithCapacity = smallvec::SmallVec<[String; 2]>; + type MySmallVec = smallvec::SmallVec<[String; 2]>; - let info = MyListWithCapacity::type_info(); + let info = MySmallVec::type_info(); if let TypeInfo::List(info) = info { - assert!(info.is::()); + assert!(info.is::()); assert!(info.item_is::()); - assert_eq!( - std::any::type_name::(), - info.type_name() - ); + assert_eq!(std::any::type_name::(), info.type_name()); assert_eq!(std::any::type_name::(), info.item_type_name()); } else { panic!("Expected `TypeInfo::List`"); } - let value: MyListWithCapacity = smallvec::smallvec![String::default(); 2]; + let value: MySmallVec = smallvec::smallvec![String::default(); 2]; let value: &dyn Reflect = &value; let info = value.get_type_info(); - assert!(info.is::()); + assert!(info.is::()); } // Array From 16b7938822da0df45128245e719e9afed67bbd65 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 8 Jun 2022 18:09:55 -0700 Subject: [PATCH 42/44] Revert "Use TypeInfo to default trait methods" This reverts commit 1e7cbd8e0c8f76759c51f87b2821a1b824e5de63. --- .../bevy_reflect_derive/src/impls.rs | 43 ++++++++- crates/bevy_reflect/src/struct_trait.rs | 95 +++---------------- crates/bevy_reflect/src/tuple.rs | 28 ++---- crates/bevy_reflect/src/tuple_struct.rs | 19 +--- 4 files changed, 64 insertions(+), 121 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs index 3b89fff014f48..e6f0dff24519c 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs @@ -36,6 +36,8 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { .active_fields() .map(|field| field.data.ty.clone()) .collect::>(); + let field_count = field_idents.len(); + let field_indices = (0..field_count).collect::>(); let hash_fn = derive_data.traits().get_hash_impl(bevy_reflect_path); let serialize_fn = derive_data.traits().get_serialize_impl(bevy_reflect_path); @@ -55,7 +57,7 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { struct_name, derive_data.generics(), quote! { - let fields = [ + let fields: [#bevy_reflect_path::NamedField; #field_count] = [ #(#bevy_reflect_path::NamedField::new::<#field_types, _>(#field_names),)* ]; let info = #bevy_reflect_path::StructInfo::new::(&fields); @@ -87,6 +89,31 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream { } } + fn field_at(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { + match index { + #(#field_indices => Some(&self.#field_idents),)* + _ => None, + } + } + + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> { + match index { + #(#field_indices => Some(&mut self.#field_idents),)* + _ => None, + } + } + + fn name_at(&self, index: usize) -> Option<&str> { + match index { + #(#field_indices => Some(#field_names),)* + _ => None, + } + } + + fn field_len(&self) -> usize { + #field_count + } + fn iter_fields(&self) -> #bevy_reflect_path::FieldIter { #bevy_reflect_path::FieldIter::new(self) } @@ -185,6 +212,8 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream .active_fields() .map(|field| field.data.ty.clone()) .collect::>(); + let field_count = field_idents.len(); + let field_indices = (0..field_count).collect::>(); let hash_fn = derive_data.traits().get_hash_impl(bevy_reflect_path); let serialize_fn = derive_data.traits().get_serialize_impl(bevy_reflect_path); @@ -204,8 +233,8 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream struct_name, derive_data.generics(), quote! { - let fields = [ - #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_idents),)* + let fields: [#bevy_reflect_path::UnnamedField; #field_count] = [ + #(#bevy_reflect_path::UnnamedField::new::<#field_types>(#field_indices),)* ]; let info = #bevy_reflect_path::TupleStructInfo::new::(&fields); #bevy_reflect_path::TypeInfo::TupleStruct(info) @@ -222,18 +251,22 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name #ty_generics #where_clause { fn field(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> { match index { - #(#field_idents => Some(&self.#field_idents),)* + #(#field_indices => Some(&self.#field_idents),)* _ => None, } } fn field_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> { match index { - #(#field_idents => Some(&mut self.#field_idents),)* + #(#field_indices => Some(&mut self.#field_idents),)* _ => None, } } + fn field_len(&self) -> usize { + #field_count + } + fn iter_fields(&self) -> #bevy_reflect_path::TupleStructFieldIter { #bevy_reflect_path::TupleStructFieldIter::new(self) } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 123c46bcd48cc..57f4d3b6e6de6 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,7 +1,6 @@ use crate::utility::TypeInfoCell; use crate::{DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use bevy_utils::{Entry, HashMap}; -use std::borrow::Borrow; use std::fmt::{Debug, Formatter}; use std::{ any::{Any, TypeId}, @@ -46,91 +45,25 @@ pub trait Struct: Reflect { /// `&mut dyn Reflect`. fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>; - /// Returns an iterator over the values of the struct's fields. - fn iter_fields(&self) -> FieldIter; - - /// Clones the struct into a [`DynamicStruct`]. - fn clone_dynamic(&self) -> DynamicStruct; - - /// Returns the number of fields in the struct. - /// - /// # Panics - /// - /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not - /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions - /// include [`DynamicStruct`] which uses its own implementation of this method to - /// prevent the panic. - fn field_len(&self) -> usize { - if let TypeInfo::Struct(info) = self.get_type_info() { - info.field_len() - } else { - panic!( - "tuple `{:?}` is not `TypeInfo::Struct`", - std::any::type_name::() - ); - } - } - - /// Returns the name of the field with index `index`. - /// - /// # Panics - /// - /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not - /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions - /// include [`DynamicStruct`] which uses its own implementation of this method to - /// prevent the panic. - fn name_at(&self, index: usize) -> Option<&str> { - if let TypeInfo::Struct(info) = self.get_type_info() { - info.field_at(index).map(|field| field.name().borrow()) - } else { - panic!( - "tuple `{:?}` is not `TypeInfo::Struct`", - std::any::type_name::() - ); - } - } - /// Returns a reference to the value of the field with index `index` as a /// `&dyn Reflect`. - /// - /// # Panics - /// - /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not - /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions - /// include [`DynamicStruct`] which uses its own implementation of this method to - /// prevent the panic. - fn field_at(&self, index: usize) -> Option<&dyn Reflect> { - if let TypeInfo::Struct(info) = self.get_type_info() { - let name = info.field_at(index)?.name(); - self.field(name) - } else { - panic!( - "tuple `{:?}` is not `TypeInfo::Struct`", - std::any::type_name::() - ); - } - } + fn field_at(&self, index: usize) -> Option<&dyn Reflect>; /// Returns a mutable reference to the value of the field with index `index` /// as a `&mut dyn Reflect`. - /// - /// # Panics - /// - /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not - /// [`TypeInfo::Struct`]— which should almost never be the case. Notable exceptions - /// include [`DynamicStruct`] which uses its own implementation of this method to - /// prevent the panic. - fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { - if let TypeInfo::Struct(info) = self.get_type_info() { - let name = info.field_at(index)?.name(); - self.field_mut(name) - } else { - panic!( - "tuple `{:?}` is not `TypeInfo::Struct`", - std::any::type_name::() - ); - } - } + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; + + /// Returns the name of the field with index `index`. + fn name_at(&self, index: usize) -> Option<&str>; + + /// Returns the number of fields in the struct. + fn field_len(&self) -> usize; + + /// Returns an iterator over the values of the struct's fields. + fn iter_fields(&self) -> FieldIter; + + /// Clones the struct into a [`DynamicStruct`]. + fn clone_dynamic(&self) -> DynamicStruct; } /// A container for compile-time struct info. diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index 80f0cc445fd84..c6acfffd72001 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -35,30 +35,14 @@ pub trait Tuple: Reflect { /// as a `&mut dyn Reflect`. fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; + /// Returns the number of fields in the tuple. + fn field_len(&self) -> usize; + /// Returns an iterator over the values of the tuple's fields. fn iter_fields(&self) -> TupleFieldIter; /// Clones the struct into a [`DynamicTuple`]. fn clone_dynamic(&self) -> DynamicTuple; - - /// Returns the number of fields in the tuple. - /// - /// # Panics - /// - /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not - /// [`TypeInfo::Tuple`]— which should almost never be the case. Notable exceptions - /// include [`DynamicTuple`] which uses its own implementation of this method to - /// prevent the panic. - fn field_len(&self) -> usize { - if let TypeInfo::Tuple(info) = self.get_type_info() { - info.field_len() - } else { - panic!( - "tuple `{:?}` is not `TypeInfo::Tuple`", - std::any::type_name::() - ); - } - } } /// An iterator over the field values of a tuple. @@ -448,6 +432,12 @@ macro_rules! impl_reflect_tuple { } } + #[inline] + fn field_len(&self) -> usize { + let indices: &[usize] = &[$($index as usize),*]; + indices.len() + } + #[inline] fn iter_fields(&self) -> TupleFieldIter { TupleFieldIter { diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 2a3401a605117..f7606caf7b03d 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -36,27 +36,14 @@ pub trait TupleStruct: Reflect { /// as a `&mut dyn Reflect`. fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; + /// Returns the number of fields in the tuple struct. + fn field_len(&self) -> usize; + /// Returns an iterator over the values of the tuple struct's fields. fn iter_fields(&self) -> TupleStructFieldIter; /// Clones the struct into a [`DynamicTupleStruct`]. fn clone_dynamic(&self) -> DynamicTupleStruct; - - /// Returns the number of fields in the tuple struct. - /// - /// # Panics - /// - /// Panics if the [`TypeInfo`] returned by [`Reflect::get_type_info()`] is not - /// [`TypeInfo::TupleStruct`]— which should almost never be the case. Notable exceptions - /// include [`DynamicTupleStruct`] which uses its own implementation of this method to - /// prevent the panic. - fn field_len(&self) -> usize { - if let TypeInfo::TupleStruct(info) = self.get_type_info() { - info.field_len() - } else { - 0 - } - } } /// A container for compile-time tuple struct info. From c0495e5ded1957ada847cd0e5e5d543d24aaa04f Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 8 Jun 2022 19:04:06 -0700 Subject: [PATCH 43/44] Split up TypeInfoCell Split TypeInfoCell into GenericTypeInfoCell and NonGenericTypeInfoCell --- .../bevy_reflect_derive/src/impls.rs | 6 +- crates/bevy_reflect/src/array.rs | 6 +- crates/bevy_reflect/src/impls/smallvec.rs | 4 +- crates/bevy_reflect/src/impls/std.rs | 12 +- crates/bevy_reflect/src/list.rs | 6 +- crates/bevy_reflect/src/map.rs | 6 +- crates/bevy_reflect/src/reflect.rs | 6 +- crates/bevy_reflect/src/struct_trait.rs | 6 +- crates/bevy_reflect/src/tuple.rs | 8 +- crates/bevy_reflect/src/tuple_struct.rs | 6 +- crates/bevy_reflect/src/type_info.rs | 12 +- crates/bevy_reflect/src/utility.rs | 135 +++++++++--------- 12 files changed, 103 insertions(+), 110 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs index e6f0dff24519c..95b8d6f0ac751 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls.rs @@ -461,15 +461,15 @@ fn impl_typed( let static_generator = if is_generic { quote! { - static CELL: #bevy_reflect_path::utility::TypeInfoCell = #bevy_reflect_path::utility::TypeInfoCell::generic(); + static CELL: #bevy_reflect_path::utility::GenericTypeInfoCell = #bevy_reflect_path::utility::GenericTypeInfoCell::new(); CELL.get_or_insert::(|| { #generator }) } } else { quote! { - static CELL: #bevy_reflect_path::utility::TypeInfoCell = #bevy_reflect_path::utility::TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| { + static CELL: #bevy_reflect_path::utility::NonGenericTypeInfoCell = #bevy_reflect_path::utility::NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| { #generator }) } diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 946533b86e77d..8b9989a212158 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -1,4 +1,4 @@ -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; use crate::{serde::Serializable, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use std::{ any::{Any, TypeId}, @@ -260,8 +260,8 @@ impl Array for DynamicArray { impl Typed for DynamicArray { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index facd6a45d0bb4..2ab1f97869c1e 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,7 +1,7 @@ use smallvec::SmallVec; use std::any::Any; -use crate::utility::TypeInfoCell; +use crate::utility::GenericTypeInfoCell; use crate::{ Array, ArrayIter, FromReflect, List, ListInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, }; @@ -115,7 +115,7 @@ where T::Item: FromReflect + Clone, { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::generic(); + static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); CELL.get_or_insert::(|| TypeInfo::List(ListInfo::new::())) } } diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 5d2a0e1e9cdee..03a57c4a03034 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -5,7 +5,7 @@ use crate::{ ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, ValueInfo, }; -use crate::utility::TypeInfoCell; +use crate::utility::{GenericTypeInfoCell, NonGenericTypeInfoCell}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_utils::{Duration, HashMap, HashSet}; use serde::{Deserialize, Serialize}; @@ -167,7 +167,7 @@ unsafe impl Reflect for Vec { impl Typed for Vec { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::generic(); + static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); CELL.get_or_insert::(|| TypeInfo::List(ListInfo::new::())) } } @@ -296,7 +296,7 @@ unsafe impl Reflect for HashMap { impl Typed for HashMap { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::generic(); + static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); CELL.get_or_insert::(|| TypeInfo::Map(MapInfo::new::())) } } @@ -443,7 +443,7 @@ impl FromReflect for [T; N] { impl Typed for [T; N] { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::generic(); + static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); CELL.get_or_insert::(|| TypeInfo::Array(ArrayInfo::new::(N))) } } @@ -549,8 +549,8 @@ unsafe impl Reflect for Cow<'static, str> { impl Typed for Cow<'static, str> { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Value(ValueInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::())) } } diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index d0d2f9de26525..66d3816707adb 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,7 +1,7 @@ use std::any::{Any, TypeId}; use std::fmt::{Debug, Formatter}; -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; use crate::{ serde::Serializable, Array, ArrayIter, DynamicArray, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, @@ -248,8 +248,8 @@ impl Debug for DynamicList { impl Typed for DynamicList { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 53c865e8bf007..88f0f63a1c85f 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -4,7 +4,7 @@ use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; /// An ordered mapping between [`Reflect`] values. @@ -289,8 +289,8 @@ impl Debug for DynamicMap { impl Typed for DynamicMap { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 2fb49c5a05163..a0da96c189e5f 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -4,7 +4,7 @@ use crate::{ }; use std::{any::Any, fmt::Debug}; -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; pub use bevy_utils::AHasher as ReflectHasher; /// An immutable enumeration of "kinds" of reflected type. @@ -205,8 +205,8 @@ impl Debug for dyn Reflect { impl Typed for dyn Reflect { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Value(ValueInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::())) } } diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index 57f4d3b6e6de6..ac06e4a5b0469 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,4 +1,4 @@ -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; use crate::{DynamicInfo, NamedField, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed}; use bevy_utils::{Entry, HashMap}; use std::fmt::{Debug, Formatter}; @@ -421,8 +421,8 @@ impl Debug for DynamicStruct { impl Typed for DynamicStruct { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index c6acfffd72001..bab117e5e5d6a 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,4 +1,4 @@ -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; use crate::{ DynamicInfo, FromReflect, FromType, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, UnnamedField, @@ -336,8 +336,8 @@ unsafe impl Reflect for DynamicTuple { impl Typed for DynamicTuple { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } @@ -514,7 +514,7 @@ macro_rules! impl_reflect_tuple { impl <$($name: Reflect),*> Typed for ($($name,)*) { fn type_info() -> &'static TypeInfo { - static CELL: $crate::utility::TypeInfoCell = $crate::utility::TypeInfoCell::generic(); + static CELL: $crate::utility::GenericTypeInfoCell = $crate::utility::GenericTypeInfoCell::new(); CELL.get_or_insert::(|| { let fields = [ $(UnnamedField::new::<$name>($index),)* diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index f7606caf7b03d..e3a8afa8a8bb6 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,4 +1,4 @@ -use crate::utility::TypeInfoCell; +use crate::utility::NonGenericTypeInfoCell; use crate::{DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, UnnamedField}; use std::any::{Any, TypeId}; use std::fmt::{Debug, Formatter}; @@ -334,8 +334,8 @@ impl Debug for DynamicTupleStruct { impl Typed for DynamicTupleStruct { fn type_info() -> &'static TypeInfo { - static CELL: TypeInfoCell = TypeInfoCell::non_generic(); - CELL.get_or_insert::(|| TypeInfo::Dynamic(DynamicInfo::new::())) + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) } } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index ea9b4f3ca150f..2d1d1f5327525 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -14,15 +14,15 @@ use std::any::{Any, TypeId}; /// rely on this trait may fail in unexpected ways. /// /// Implementors may have difficulty in generating a reference to [`TypeInfo`] with a static -/// lifetime. Luckily, this crate comes with a utility struct, [`TypeInfoCell`], to make -/// generating these statics much simpler. +/// lifetime. Luckily, this crate comes with some [utility] structs, to make generating these +/// statics much simpler. /// /// # Example /// /// ``` /// # use std::any::Any; /// # use bevy_reflect::{NamedField, Reflect, ReflectMut, ReflectRef, StructInfo, TypeInfo, ValueInfo}; -/// # use bevy_reflect::utility::TypeInfoCell; +/// # use bevy_reflect::utility::NonGenericTypeInfoCell; /// use bevy_reflect::Typed; /// /// struct MyStruct { @@ -32,8 +32,8 @@ use std::any::{Any, TypeId}; /// /// impl Typed for MyStruct { /// fn type_info() -> &'static TypeInfo { -/// static CELL: TypeInfoCell = TypeInfoCell::non_generic(); -/// CELL.get_or_insert::(|| { +/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); +/// CELL.get_or_set(|| { /// let fields = [ /// NamedField::new::("foo"), /// NamedField::new::<(f32, f32), _>("bar"), @@ -60,7 +60,7 @@ use std::any::{Any, TypeId}; /// # } /// ``` /// -/// [`TypeInfoCell`]: crate::utility::TypeInfoCell +/// [utility]: crate::utility pub trait Typed: Reflect { /// Returns the compile-time [info] for the underlying type. /// diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs index d67d788864412..222e94fe19214 100644 --- a/crates/bevy_reflect/src/utility.rs +++ b/crates/bevy_reflect/src/utility.rs @@ -8,28 +8,28 @@ use std::any::{Any, TypeId}; /// A container for [`TypeInfo`], allowing instances to be stored statically. /// -/// Under the hood, this manages a [`once_cell`] for either of the two possible types: -/// `Generic` and `NonGeneric`. +/// This is specifically meant for use with _non_-generic types. If your type _is_ generic, +/// then use [`GenericTypeInfoCell`] instead. Otherwise, it will not take into account all +/// monomorphizations of your type. /// -/// ## Non-Generic -/// -/// For non-generic impls, [`TypeInfoCell`] should be initialized via the [`non_generic`] -/// method. This should be much more performant than the generic alternative, so favor -/// this variant whenever possible. +/// ## Example /// /// ``` /// # use std::any::Any; -/// # use bevy_reflect::{Reflect, ReflectMut, ReflectRef, Typed, TypeInfo, ValueInfo}; -/// use bevy_reflect::utility::TypeInfoCell; +/// # use bevy_reflect::{NamedField, Reflect, ReflectMut, ReflectRef, StructInfo, Typed, TypeInfo}; +/// use bevy_reflect::utility::NonGenericTypeInfoCell; /// -/// struct Foo; +/// struct Foo { +/// bar: i32 +/// } /// /// impl Typed for Foo { /// fn type_info() -> &'static TypeInfo { -/// static CELL: TypeInfoCell = TypeInfoCell::non_generic(); -/// CELL.get_or_insert::(|| { -/// let info = ValueInfo::new::(); -/// TypeInfo::Value(info) +/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); +/// CELL.get_or_set(|| { +/// let fields = [NamedField::new::("bar")]; +/// let info = StructInfo::new::(&fields); +/// TypeInfo::Struct(info) /// }) /// } /// } @@ -48,29 +48,48 @@ use std::any::{Any, TypeId}; /// # fn clone_value(&self) -> Box { todo!() } /// # } /// ``` +pub struct NonGenericTypeInfoCell(OnceBox); + +impl NonGenericTypeInfoCell { + /// Initialize a [`NonGenericTypeInfoCell`] for non-generic impls. + pub const fn new() -> Self { + Self(OnceBox::new()) + } + + /// Returns a reference to the [`TypeInfo`] stored in the cell. + /// + /// If there is no [`TypeInfo`] found, a new one will be generated from the given function. + /// + /// [`TypeInfos`]: TypeInfo + pub fn get_or_set(&self, f: F) -> &TypeInfo + where + F: FnOnce() -> TypeInfo, + { + self.0.get_or_init(|| Box::new(f())) + } +} + +/// A container for [`TypeInfo`], allowing instances to be stored statically. /// -/// ## Generic -/// -/// For generic impls, [`TypeInfoCell`] should be initialized via the [`generic`] -/// method. This will store multiple instances of [`TypeInfo`], accessible by [`TypeId`]. +/// This is specifically meant for use with generic types. If your type isn't generic, +/// then use [`NonGenericTypeInfoCell`] instead as it should be much more performant. /// -/// This allows `Foo` to use the same [`TypeInfoCell`] for monomorphized type. The same -/// applies to blanket impls. +/// ## Example /// /// ``` /// # use std::any::Any; -/// # use std::marker::PhantomData; -/// # use bevy_reflect::{Reflect, ReflectMut, ReflectRef, Typed, TypeInfo, ValueInfo}; -/// use bevy_reflect::utility::TypeInfoCell; +/// # use bevy_reflect::{Reflect, ReflectMut, ReflectRef, TupleStructInfo, Typed, TypeInfo, UnnamedField}; +/// use bevy_reflect::utility::GenericTypeInfoCell; /// -/// struct Foo(PhantomData); +/// struct Foo(T); /// /// impl Typed for Foo { /// fn type_info() -> &'static TypeInfo { -/// static CELL: TypeInfoCell = TypeInfoCell::generic(); +/// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); /// CELL.get_or_insert::(|| { -/// let info = ValueInfo::new::(); -/// TypeInfo::Value(info) +/// let fields = [UnnamedField::new::(0)]; +/// let info = TupleStructInfo::new::(&fields); +/// TypeInfo::TupleStruct(info) /// }) /// } /// } @@ -89,61 +108,35 @@ use std::any::{Any, TypeId}; /// # fn clone_value(&self) -> Box { todo!() } /// # } /// ``` -/// -/// [`once_cell`]: https://docs.rs/once_cell/latest/once_cell/ -/// [`non_generic`]: TypeInfoCell::non_generic -/// [`generic`]: TypeInfoCell::generic -pub struct TypeInfoCell(TypeInfoCellType); - -impl TypeInfoCell { - /// Initialize a [`TypeInfoCell`] for non-generic types. - pub const fn non_generic() -> Self { - Self(TypeInfoCellType::NonGeneric(OnceBox::new())) - } +pub struct GenericTypeInfoCell(OnceBox>>); - /// Initialize a [`TypeInfoCell`] for generic types. - pub const fn generic() -> Self { - Self(TypeInfoCellType::Generic(OnceBox::new())) +impl GenericTypeInfoCell { + /// Initialize a [`GenericTypeInfoCell`] for generic impls. + pub const fn new() -> Self { + Self(OnceBox::new()) } /// Returns a reference to the [`TypeInfo`] stored in the cell. /// + /// This method will then return the correct [`TypeInfo`] reference for the given type `T`. /// If there is no [`TypeInfo`] found, a new one will be generated from the given function. - /// - /// # Generics - /// - /// Generic types, such as `Vec`, store a mapping of [`TypeIds`] to [`TypeInfos`]. This - /// method will then return the correct [`TypeInfo`] reference for the given type `T`. - /// - /// [`TypeIds`]: std::any::TypeId - /// [`TypeInfos`]: TypeInfo pub fn get_or_insert(&self, f: F) -> &TypeInfo where T: Any + ?Sized, F: FnOnce() -> TypeInfo, { - match &self.0 { - TypeInfoCellType::NonGeneric(once) => once.get_or_init(|| Box::new(f())), - TypeInfoCellType::Generic(once) => { - let type_id = TypeId::of::(); - let mapping = once.get_or_init(|| Box::new(RwLock::default())); - if let Some(info) = mapping.read().get(&type_id) { - return info; - } - - mapping.write().entry(type_id).or_insert_with(|| { - // We leak here in order to obtain a `&'static` reference. - // Otherwise, we won't be able to return a reference due to the `RwLock`. - // This should be okay, though, since we expect it to remain statically - // available over the course of the application. - Box::leak(Box::new(f())) - }) - } + let type_id = TypeId::of::(); + let mapping = self.0.get_or_init(|| Box::new(RwLock::default())); + if let Some(info) = mapping.read().get(&type_id) { + return info; } - } -} -enum TypeInfoCellType { - NonGeneric(OnceBox), - Generic(OnceBox>>), + mapping.write().entry(type_id).or_insert_with(|| { + // We leak here in order to obtain a `&'static` reference. + // Otherwise, we won't be able to return a reference due to the `RwLock`. + // This should be okay, though, since we expect it to remain statically + // available over the course of the application. + Box::leak(Box::new(f())) + }) + } } From 0fc6b648dfaf7f257f9903445b990589e9c491a3 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 8 Jun 2022 19:07:52 -0700 Subject: [PATCH 44/44] Change wording in docs --- crates/bevy_reflect/src/utility.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs index 222e94fe19214..a597539afdb02 100644 --- a/crates/bevy_reflect/src/utility.rs +++ b/crates/bevy_reflect/src/utility.rs @@ -6,7 +6,7 @@ use once_cell::race::OnceBox; use parking_lot::RwLock; use std::any::{Any, TypeId}; -/// A container for [`TypeInfo`], allowing instances to be stored statically. +/// A container for [`TypeInfo`] over non-generic types, allowing instances to be stored statically. /// /// This is specifically meant for use with _non_-generic types. If your type _is_ generic, /// then use [`GenericTypeInfoCell`] instead. Otherwise, it will not take into account all @@ -51,7 +51,7 @@ use std::any::{Any, TypeId}; pub struct NonGenericTypeInfoCell(OnceBox); impl NonGenericTypeInfoCell { - /// Initialize a [`NonGenericTypeInfoCell`] for non-generic impls. + /// Initialize a [`NonGenericTypeInfoCell`] for non-generic types. pub const fn new() -> Self { Self(OnceBox::new()) } @@ -69,7 +69,7 @@ impl NonGenericTypeInfoCell { } } -/// A container for [`TypeInfo`], allowing instances to be stored statically. +/// A container for [`TypeInfo`] over generic types, allowing instances to be stored statically. /// /// This is specifically meant for use with generic types. If your type isn't generic, /// then use [`NonGenericTypeInfoCell`] instead as it should be much more performant. @@ -111,7 +111,7 @@ impl NonGenericTypeInfoCell { pub struct GenericTypeInfoCell(OnceBox>>); impl GenericTypeInfoCell { - /// Initialize a [`GenericTypeInfoCell`] for generic impls. + /// Initialize a [`GenericTypeInfoCell`] for generic types. pub const fn new() -> Self { Self(OnceBox::new()) }