bevy_reflect: Add Type type (#14838)

# Objective

Closes #7622.

I was working on adding support for reflecting generic functions and
found that I wanted to use an argument's `TypeId` for hashing and
comparison, but its `TypePath` for debugging and error messaging.

While I could just keep them separate, place them in a tuple or a local
struct or something, I think I see an opportunity to make a dedicate
type for this.

Additionally, we can use this type to clean up some duplication amongst
the type info structs in a manner similar to #7622.

## Solution

Added the `Type` type. This should be seen as the most basic
representation of a type apart from `TypeId`. It stores both the
`TypeId` of the type as well as its `TypePathTable`.

The `Hash` and `PartialEq` implementations rely on the `TypeId`, while
the `Debug` implementation relies on the `TypePath`.

This makes it especially useful as a key in a `HashMap` since we get the
speed of the `TypeId` hashing/comparisons with the readability of
`TypePath`.

With this type, we're able to reduce the duplication across the type
info structs by removing individual fields for `TypeId` and
`TypePathTable`, replacing them with a single `Type` field. Similarly,
we can remove many duplicate methods and replace it with a macro that
delegates to the stored `Type`.

### Caveats

It should be noted that this type is currently 3x larger than `TypeId`.
On my machine, it's 48 bytes compared to `TypeId`'s 16. While this
doesn't matter for `TypeInfo` since it would contain that data
regardless, it is something to keep in mind when using elsewhere.

## Testing

All tests should pass as normal:

```
cargo test --package bevy_reflect
```

---

## Showcase

`bevy_reflect` now exports a `Type` struct. This type contains both the
`TypeId` and the `TypePathTable` of the given type, allowing it to be
used like `TypeId` but have the debuggability of `TypePath`.

```rust
// We can create this for any type implementing `TypePath`:
let ty = Type::of::<String>();

// It has `Hash` and `Eq` impls powered by `TypeId`, making it useful for maps:
let mut map = HashMap::<Type, i32>::new();
map.insert(ty, 25);

// And it has a human-readable `Debug` representation:
let debug = format!("{:?}", map);
assert_eq!(debug, "{alloc::string::String: 25}");
```

## Migration Guide

Certain type info structs now only return their item types as `Type`
instead of exposing direct methods on them.

The following methods have been removed:

- `ArrayInfo::item_type_path_table`
- `ArrayInfo::item_type_id`
- `ArrayInfo::item_is`
- `ListInfo::item_type_path_table`
- `ListInfo::item_type_id`
- `ListInfo::item_is`
- `SetInfo::value_type_path_table`
- `SetInfo::value_type_id`
- `SetInfo::value_is`
- `MapInfo::key_type_path_table`
- `MapInfo::key_type_id`
- `MapInfo::key_is`
- `MapInfo::value_type_path_table`
- `MapInfo::value_type_id`
- `MapInfo::value_is`

Instead, access the `Type` directly using one of the new methods:

- `ArrayInfo::item_ty`
- `ListInfo::item_ty`
- `SetInfo::value_ty`
- `MapInfo::key_ty`
- `MapInfo::value_ty`

For example:

```rust
// BEFORE
let type_id = array_info.item_type_id();

// AFTER
let type_id = array_info.item_ty().id();
```
This commit is contained in:
Gino Valente 2024-08-25 10:57:07 -07:00 committed by GitHub
parent f9d7a2ca02
commit 3892adcb47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 343 additions and 513 deletions

View File

@ -1,10 +1,11 @@
use crate::type_info::impl_type_methods;
use crate::{ use crate::{
self as bevy_reflect, utility::reflect_hasher, ApplyError, MaybeTyped, PartialReflect, Reflect, self as bevy_reflect, utility::reflect_hasher, ApplyError, MaybeTyped, PartialReflect, Reflect,
ReflectKind, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
}; };
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use std::{ use std::{
any::{Any, TypeId}, any::Any,
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
hash::{Hash, Hasher}, hash::{Hash, Hasher},
}; };
@ -77,11 +78,9 @@ pub trait Array: PartialReflect {
/// A container for compile-time array info. /// A container for compile-time array info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ArrayInfo { pub struct ArrayInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
item_info: fn() -> Option<&'static TypeInfo>, item_info: fn() -> Option<&'static TypeInfo>,
item_type_path: TypePathTable, item_ty: Type,
item_type_id: TypeId,
capacity: usize, capacity: usize,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
@ -98,11 +97,9 @@ impl ArrayInfo {
capacity: usize, capacity: usize,
) -> Self { ) -> Self {
Self { Self {
type_path: TypePathTable::of::<TArray>(), ty: Type::of::<TArray>(),
type_id: TypeId::of::<TArray>(),
item_info: TItem::maybe_type_info, item_info: TItem::maybe_type_info,
item_type_path: TypePathTable::of::<TItem>(), item_ty: Type::of::<TItem>(),
item_type_id: TypeId::of::<TItem>(),
capacity, capacity,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
@ -120,32 +117,7 @@ impl ArrayInfo {
self.capacity self.capacity
} }
/// A representation of the type path of the array. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the array.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the array.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the array type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The [`TypeInfo`] of the array item. /// The [`TypeInfo`] of the array item.
/// ///
@ -155,21 +127,11 @@ impl ArrayInfo {
(self.item_info)() (self.item_info)()
} }
/// A representation of the type path of the array item. /// The [type] of the array item.
/// ///
/// Provides dynamic access to all methods on [`TypePath`]. /// [type]: Type
pub fn item_type_path_table(&self) -> &TypePathTable { pub fn item_ty(&self) -> Type {
&self.item_type_path self.item_ty
}
/// The [`TypeId`] of the array item.
pub fn item_type_id(&self) -> TypeId {
self.item_type_id
}
/// Check if the given type matches the array item type.
pub fn item_is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.item_type_id
} }
/// The docstring of this array, if any. /// The docstring of this array, if any.

View File

@ -1,7 +1,7 @@
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes}; use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::{DynamicEnum, PartialReflect, TypePath, TypePathTable, VariantInfo, VariantType}; use crate::type_info::impl_type_methods;
use crate::{DynamicEnum, PartialReflect, Type, TypePath, VariantInfo, VariantType};
use bevy_utils::HashMap; use bevy_utils::HashMap;
use std::any::{Any, TypeId};
use std::slice::Iter; use std::slice::Iter;
use std::sync::Arc; use std::sync::Arc;
@ -135,8 +135,7 @@ pub trait Enum: PartialReflect {
/// A container for compile-time enum info, used by [`TypeInfo`](crate::TypeInfo). /// A container for compile-time enum info, used by [`TypeInfo`](crate::TypeInfo).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct EnumInfo { pub struct EnumInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
variants: Box<[VariantInfo]>, variants: Box<[VariantInfo]>,
variant_names: Box<[&'static str]>, variant_names: Box<[&'static str]>,
variant_indices: HashMap<&'static str, usize>, variant_indices: HashMap<&'static str, usize>,
@ -162,8 +161,7 @@ impl EnumInfo {
let variant_names = variants.iter().map(VariantInfo::name).collect(); let variant_names = variants.iter().map(VariantInfo::name).collect();
Self { Self {
type_path: TypePathTable::of::<TEnum>(), ty: Type::of::<TEnum>(),
type_id: TypeId::of::<TEnum>(),
variants: variants.to_vec().into_boxed_slice(), variants: variants.to_vec().into_boxed_slice(),
variant_names, variant_names,
variant_indices, variant_indices,
@ -231,32 +229,7 @@ impl EnumInfo {
self.variants.len() self.variants.len()
} }
/// A representation of the type path of the value. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the value.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the enum.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the enum type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this enum, if any. /// The docstring of this enum, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]

View File

@ -1,6 +1,6 @@
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes}; use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::{MaybeTyped, PartialReflect, TypeInfo, TypePath, TypePathTable}; use crate::type_info::impl_type_methods;
use std::any::{Any, TypeId}; use crate::{MaybeTyped, PartialReflect, Type, TypeInfo, TypePath};
use std::sync::Arc; use std::sync::Arc;
/// The named field of a reflected struct. /// The named field of a reflected struct.
@ -8,8 +8,7 @@ use std::sync::Arc;
pub struct NamedField { pub struct NamedField {
name: &'static str, name: &'static str,
type_info: fn() -> Option<&'static TypeInfo>, type_info: fn() -> Option<&'static TypeInfo>,
type_path: TypePathTable, ty: Type,
type_id: TypeId,
custom_attributes: Arc<CustomAttributes>, custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
@ -21,8 +20,7 @@ impl NamedField {
Self { Self {
name, name,
type_info: T::maybe_type_info, type_info: T::maybe_type_info,
type_path: TypePathTable::of::<T>(), ty: Type::of::<T>(),
type_id: TypeId::of::<T>(),
custom_attributes: Arc::new(CustomAttributes::default()), custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
@ -57,32 +55,7 @@ impl NamedField {
(self.type_info)() (self.type_info)()
} }
/// A representation of the type path of the field. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the field.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the field.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the field type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this field, if any. /// The docstring of this field, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
@ -98,8 +71,7 @@ impl NamedField {
pub struct UnnamedField { pub struct UnnamedField {
index: usize, index: usize,
type_info: fn() -> Option<&'static TypeInfo>, type_info: fn() -> Option<&'static TypeInfo>,
type_path: TypePathTable, ty: Type,
type_id: TypeId,
custom_attributes: Arc<CustomAttributes>, custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
@ -110,8 +82,7 @@ impl UnnamedField {
Self { Self {
index, index,
type_info: T::maybe_type_info, type_info: T::maybe_type_info,
type_path: TypePathTable::of::<T>(), ty: Type::of::<T>(),
type_id: TypeId::of::<T>(),
custom_attributes: Arc::new(CustomAttributes::default()), custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
@ -146,32 +117,7 @@ impl UnnamedField {
(self.type_info)() (self.type_info)()
} }
/// A representation of the type path of the field. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the field.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the field.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the field type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this field, if any. /// The docstring of this field, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]

View File

@ -1,7 +1,8 @@
use alloc::borrow::Cow; use alloc::borrow::Cow;
use crate::func::args::{GetOwnership, Ownership}; use crate::func::args::{GetOwnership, Ownership};
use crate::TypePath; use crate::type_info::impl_type_methods;
use crate::{Type, TypePath};
/// Type information for an [`Arg`] used in a [`DynamicFunction`] or [`DynamicFunctionMut`]. /// Type information for an [`Arg`] used in a [`DynamicFunction`] or [`DynamicFunctionMut`].
/// ///
@ -16,10 +17,10 @@ pub struct ArgInfo {
name: Option<Cow<'static, str>>, name: Option<Cow<'static, str>>,
/// The ownership of the argument. /// The ownership of the argument.
ownership: Ownership, ownership: Ownership,
/// The [type path] of the argument. /// The [type] of the argument.
/// ///
/// [type path]: TypePath::type_path /// [type]: Type
type_path: &'static str, ty: Type,
} }
impl ArgInfo { impl ArgInfo {
@ -31,7 +32,7 @@ impl ArgInfo {
index, index,
name: None, name: None,
ownership: T::ownership(), ownership: T::ownership(),
type_path: T::type_path(), ty: Type::of::<T>(),
} }
} }
@ -72,12 +73,7 @@ impl ArgInfo {
self.ownership self.ownership
} }
/// The [type path] of the argument. impl_type_methods!(ty);
///
/// [type path]: TypePath::type_path
pub fn type_path(&self) -> &'static str {
self.type_path
}
/// Get an ID representing the argument. /// Get an ID representing the argument.
/// ///

View File

@ -3,7 +3,8 @@ use alloc::borrow::Cow;
use bevy_utils::all_tuples; use bevy_utils::all_tuples;
use crate::func::args::{ArgInfo, GetOwnership, Ownership}; use crate::func::args::{ArgInfo, GetOwnership, Ownership};
use crate::TypePath; use crate::type_info::impl_type_methods;
use crate::{Type, TypePath};
/// Type information for a [`DynamicFunction`] or [`DynamicFunctionMut`]. /// Type information for a [`DynamicFunction`] or [`DynamicFunctionMut`].
/// ///
@ -140,7 +141,7 @@ impl FunctionInfo {
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut /// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReturnInfo { pub struct ReturnInfo {
type_path: &'static str, ty: Type,
ownership: Ownership, ownership: Ownership,
} }
@ -148,17 +149,14 @@ impl ReturnInfo {
/// Create a new [`ReturnInfo`] representing the given type, `T`. /// Create a new [`ReturnInfo`] representing the given type, `T`.
pub fn new<T: TypePath + GetOwnership>() -> Self { pub fn new<T: TypePath + GetOwnership>() -> Self {
Self { Self {
type_path: T::type_path(), ty: Type::of::<T>(),
ownership: T::ownership(), ownership: T::ownership(),
} }
} }
/// The type path of the return type. impl_type_methods!(ty);
pub fn type_path(&self) -> &'static str {
self.type_path
}
/// The ownership of the return type. /// The ownership of this type.
pub fn ownership(&self) -> Ownership { pub fn ownership(&self) -> Ownership {
self.ownership self.ownership
} }

View File

@ -1719,10 +1719,10 @@ mod tests {
let info = MyList::type_info().as_list().unwrap(); let info = MyList::type_info().as_list().unwrap();
assert!(info.is::<MyList>()); assert!(info.is::<MyList>());
assert!(info.item_is::<usize>()); assert!(info.item_ty().is::<usize>());
assert!(info.item_info().unwrap().is::<usize>()); assert!(info.item_info().unwrap().is::<usize>());
assert_eq!(MyList::type_path(), info.type_path()); assert_eq!(MyList::type_path(), info.type_path());
assert_eq!(usize::type_path(), info.item_type_path_table().path()); assert_eq!(usize::type_path(), info.item_ty().path());
let value: &dyn Reflect = &vec![123_usize]; let value: &dyn Reflect = &vec![123_usize];
let info = value.get_represented_type_info().unwrap(); let info = value.get_represented_type_info().unwrap();
@ -1735,10 +1735,10 @@ mod tests {
let info = MySmallVec::type_info().as_list().unwrap(); let info = MySmallVec::type_info().as_list().unwrap();
assert!(info.is::<MySmallVec>()); assert!(info.is::<MySmallVec>());
assert!(info.item_is::<String>()); assert!(info.item_ty().is::<String>());
assert!(info.item_info().unwrap().is::<String>()); assert!(info.item_info().unwrap().is::<String>());
assert_eq!(MySmallVec::type_path(), info.type_path()); assert_eq!(MySmallVec::type_path(), info.type_path());
assert_eq!(String::type_path(), info.item_type_path_table().path()); assert_eq!(String::type_path(), info.item_ty().path());
let value: MySmallVec = smallvec::smallvec![String::default(); 2]; let value: MySmallVec = smallvec::smallvec![String::default(); 2];
let value: &dyn Reflect = &value; let value: &dyn Reflect = &value;
@ -1751,10 +1751,10 @@ mod tests {
let info = MyArray::type_info().as_array().unwrap(); let info = MyArray::type_info().as_array().unwrap();
assert!(info.is::<MyArray>()); assert!(info.is::<MyArray>());
assert!(info.item_is::<usize>()); assert!(info.item_ty().is::<usize>());
assert!(info.item_info().unwrap().is::<usize>()); assert!(info.item_info().unwrap().is::<usize>());
assert_eq!(MyArray::type_path(), info.type_path()); assert_eq!(MyArray::type_path(), info.type_path());
assert_eq!(usize::type_path(), info.item_type_path_table().path()); assert_eq!(usize::type_path(), info.item_ty().path());
assert_eq!(3, info.capacity()); assert_eq!(3, info.capacity());
let value: &dyn Reflect = &[1usize, 2usize, 3usize]; let value: &dyn Reflect = &[1usize, 2usize, 3usize];
@ -1779,13 +1779,10 @@ mod tests {
let info = MyCowSlice::type_info().as_list().unwrap(); let info = MyCowSlice::type_info().as_list().unwrap();
assert!(info.is::<MyCowSlice>()); assert!(info.is::<MyCowSlice>());
assert!(info.item_is::<u8>()); assert!(info.item_ty().is::<u8>());
assert!(info.item_info().unwrap().is::<u8>()); assert!(info.item_info().unwrap().is::<u8>());
assert_eq!(std::any::type_name::<MyCowSlice>(), info.type_path()); assert_eq!(std::any::type_name::<MyCowSlice>(), info.type_path());
assert_eq!( assert_eq!(std::any::type_name::<u8>(), info.item_ty().path());
std::any::type_name::<u8>(),
info.item_type_path_table().path()
);
let value: &dyn Reflect = &Cow::<'static, [u8]>::Owned(vec![0, 1, 2, 3]); let value: &dyn Reflect = &Cow::<'static, [u8]>::Owned(vec![0, 1, 2, 3]);
let info = value.get_represented_type_info().unwrap(); let info = value.get_represented_type_info().unwrap();
@ -1797,13 +1794,13 @@ mod tests {
let info = MyMap::type_info().as_map().unwrap(); let info = MyMap::type_info().as_map().unwrap();
assert!(info.is::<MyMap>()); assert!(info.is::<MyMap>());
assert!(info.key_is::<usize>()); assert!(info.key_ty().is::<usize>());
assert!(info.value_is::<f32>()); assert!(info.value_ty().is::<f32>());
assert!(info.key_info().unwrap().is::<usize>()); assert!(info.key_info().unwrap().is::<usize>());
assert!(info.value_info().unwrap().is::<f32>()); assert!(info.value_info().unwrap().is::<f32>());
assert_eq!(MyMap::type_path(), info.type_path()); assert_eq!(MyMap::type_path(), info.type_path());
assert_eq!(usize::type_path(), info.key_type_path_table().path()); assert_eq!(usize::type_path(), info.key_ty().path());
assert_eq!(f32::type_path(), info.value_type_path_table().path()); assert_eq!(f32::type_path(), info.value_ty().path());
let value: &dyn Reflect = &MyMap::new(); let value: &dyn Reflect = &MyMap::new();
let info = value.get_represented_type_info().unwrap(); let info = value.get_represented_type_info().unwrap();

View File

@ -1,13 +1,14 @@
use std::any::{Any, TypeId}; use std::any::Any;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use crate::type_info::impl_type_methods;
use crate::utility::reflect_hasher; use crate::utility::reflect_hasher;
use crate::{ use crate::{
self as bevy_reflect, ApplyError, FromReflect, MaybeTyped, PartialReflect, Reflect, self as bevy_reflect, ApplyError, FromReflect, MaybeTyped, PartialReflect, Reflect,
ReflectKind, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
}; };
/// A trait used to power [list-like] operations via [reflection]. /// A trait used to power [list-like] operations via [reflection].
@ -108,11 +109,9 @@ pub trait List: PartialReflect {
/// A container for compile-time list info. /// A container for compile-time list info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ListInfo { pub struct ListInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
item_info: fn() -> Option<&'static TypeInfo>, item_info: fn() -> Option<&'static TypeInfo>,
item_type_path: TypePathTable, item_ty: Type,
item_type_id: TypeId,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
} }
@ -121,11 +120,9 @@ impl ListInfo {
/// Create a new [`ListInfo`]. /// Create a new [`ListInfo`].
pub fn new<TList: List + TypePath, TItem: FromReflect + MaybeTyped + TypePath>() -> Self { pub fn new<TList: List + TypePath, TItem: FromReflect + MaybeTyped + TypePath>() -> Self {
Self { Self {
type_path: TypePathTable::of::<TList>(), ty: Type::of::<TList>(),
type_id: TypeId::of::<TList>(),
item_info: TItem::maybe_type_info, item_info: TItem::maybe_type_info,
item_type_path: TypePathTable::of::<TItem>(), item_ty: Type::of::<TItem>(),
item_type_id: TypeId::of::<TItem>(),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
} }
@ -137,32 +134,7 @@ impl ListInfo {
Self { docs, ..self } Self { docs, ..self }
} }
/// A representation of the type path of the list. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the list.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the list.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the list type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The [`TypeInfo`] of the list item. /// The [`TypeInfo`] of the list item.
/// ///
@ -172,21 +144,11 @@ impl ListInfo {
(self.item_info)() (self.item_info)()
} }
/// A representation of the type path of the list item. /// The [type] of the list item.
/// ///
/// Provides dynamic access to all methods on [`TypePath`]. /// [type]: Type
pub fn item_type_path_table(&self) -> &TypePathTable { pub fn item_ty(&self) -> Type {
&self.item_type_path self.item_ty
}
/// 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<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.item_type_id
} }
/// The docstring of this list, if any. /// The docstring of this list, if any.

View File

@ -1,12 +1,12 @@
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use bevy_utils::{Entry, HashMap}; use bevy_utils::{Entry, HashMap};
use crate::type_info::impl_type_methods;
use crate::{ use crate::{
self as bevy_reflect, ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, self as bevy_reflect, ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
}; };
/// A trait used to power [map-like] operations via [reflection]. /// A trait used to power [map-like] operations via [reflection].
@ -97,14 +97,11 @@ pub trait Map: PartialReflect {
/// A container for compile-time map info. /// A container for compile-time map info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapInfo { pub struct MapInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
key_info: fn() -> Option<&'static TypeInfo>, key_info: fn() -> Option<&'static TypeInfo>,
key_type_path: TypePathTable, key_ty: Type,
key_type_id: TypeId,
value_info: fn() -> Option<&'static TypeInfo>, value_info: fn() -> Option<&'static TypeInfo>,
value_type_path: TypePathTable, value_ty: Type,
value_type_id: TypeId,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
} }
@ -117,14 +114,11 @@ impl MapInfo {
TValue: Reflect + MaybeTyped + TypePath, TValue: Reflect + MaybeTyped + TypePath,
>() -> Self { >() -> Self {
Self { Self {
type_path: TypePathTable::of::<TMap>(), ty: Type::of::<TMap>(),
type_id: TypeId::of::<TMap>(),
key_info: TKey::maybe_type_info, key_info: TKey::maybe_type_info,
key_type_path: TypePathTable::of::<TKey>(), key_ty: Type::of::<TKey>(),
key_type_id: TypeId::of::<TKey>(),
value_info: TValue::maybe_type_info, value_info: TValue::maybe_type_info,
value_type_path: TypePathTable::of::<TValue>(), value_ty: Type::of::<TValue>(),
value_type_id: TypeId::of::<TValue>(),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
} }
@ -136,32 +130,7 @@ impl MapInfo {
Self { docs, ..self } Self { docs, ..self }
} }
/// A representation of the type path of the map. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the map.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the map.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the map type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The [`TypeInfo`] of the key type. /// The [`TypeInfo`] of the key type.
/// ///
@ -171,21 +140,11 @@ impl MapInfo {
(self.key_info)() (self.key_info)()
} }
/// A representation of the type path of the key type. /// The [type] of the key type.
/// ///
/// Provides dynamic access to all methods on [`TypePath`]. /// [type]: Type
pub fn key_type_path_table(&self) -> &TypePathTable { pub fn key_ty(&self) -> Type {
&self.key_type_path self.key_ty
}
/// The [`TypeId`] of the key.
pub fn key_type_id(&self) -> TypeId {
self.key_type_id
}
/// Check if the given type matches the key type.
pub fn key_is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.key_type_id
} }
/// The [`TypeInfo`] of the value type. /// The [`TypeInfo`] of the value type.
@ -196,21 +155,11 @@ impl MapInfo {
(self.value_info)() (self.value_info)()
} }
/// A representation of the type path of the value type. /// The [type] of the value type.
/// ///
/// Provides dynamic access to all methods on [`TypePath`]. /// [type]: Type
pub fn value_type_path_table(&self) -> &TypePathTable { pub fn value_ty(&self) -> Type {
&self.value_type_path self.value_ty
}
/// The [`TypeId`] of the value.
pub fn value_type_id(&self) -> TypeId {
self.value_type_id
}
/// Check if the given type matches the value type.
pub fn value_is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.value_type_id
} }
/// The docstring of this map, if any. /// The docstring of this map, if any.

View File

@ -730,8 +730,8 @@ impl<'a, 'de> Visitor<'de> for ArrayVisitor<'a> {
{ {
let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default()); let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default());
let registration = get_registration( let registration = get_registration(
self.array_info.item_type_id(), self.array_info.item_ty().id(),
self.array_info.item_type_path_table().path(), self.array_info.item_ty().path(),
self.registry, self.registry,
)?; )?;
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer { while let Some(value) = seq.next_element_seed(TypedReflectDeserializer {
@ -770,8 +770,8 @@ impl<'a, 'de> Visitor<'de> for ListVisitor<'a> {
{ {
let mut list = DynamicList::default(); let mut list = DynamicList::default();
let registration = get_registration( let registration = get_registration(
self.list_info.item_type_id(), self.list_info.item_ty().id(),
self.list_info.item_type_path_table().path(), self.list_info.item_ty().path(),
self.registry, self.registry,
)?; )?;
while let Some(value) = seq.next_element_seed(TypedReflectDeserializer { while let Some(value) = seq.next_element_seed(TypedReflectDeserializer {
@ -802,13 +802,13 @@ impl<'a, 'de> Visitor<'de> for MapVisitor<'a> {
{ {
let mut dynamic_map = DynamicMap::default(); let mut dynamic_map = DynamicMap::default();
let key_registration = get_registration( let key_registration = get_registration(
self.map_info.key_type_id(), self.map_info.key_ty().id(),
self.map_info.key_type_path_table().path(), self.map_info.key_ty().path(),
self.registry, self.registry,
)?; )?;
let value_registration = get_registration( let value_registration = get_registration(
self.map_info.value_type_id(), self.map_info.value_ty().id(),
self.map_info.value_type_path_table().path(), self.map_info.value_ty().path(),
self.registry, self.registry,
)?; )?;
while let Some(key) = map.next_key_seed(TypedReflectDeserializer { while let Some(key) = map.next_key_seed(TypedReflectDeserializer {
@ -844,8 +844,8 @@ impl<'a, 'de> Visitor<'de> for SetVisitor<'a> {
{ {
let mut dynamic_set = DynamicSet::default(); let mut dynamic_set = DynamicSet::default();
let value_registration = get_registration( let value_registration = get_registration(
self.set_info.value_type_id(), self.set_info.value_ty().id(),
self.set_info.value_type_path_table().path(), self.set_info.value_ty().path(),
self.registry, self.registry,
)?; )?;
while let Some(value) = set.next_element_seed(TypedReflectDeserializer { while let Some(value) = set.next_element_seed(TypedReflectDeserializer {

View File

@ -1,13 +1,13 @@
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use bevy_utils::hashbrown::hash_table::OccupiedEntry as HashTableOccupiedEntry; use bevy_utils::hashbrown::hash_table::OccupiedEntry as HashTableOccupiedEntry;
use bevy_utils::hashbrown::HashTable; use bevy_utils::hashbrown::HashTable;
use crate::type_info::impl_type_methods;
use crate::{ use crate::{
self as bevy_reflect, hash_error, ApplyError, PartialReflect, Reflect, ReflectKind, ReflectMut, self as bevy_reflect, hash_error, ApplyError, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
}; };
/// A trait used to power [set-like] operations via [reflection]. /// A trait used to power [set-like] operations via [reflection].
@ -82,10 +82,8 @@ pub trait Set: PartialReflect {
/// A container for compile-time set info. /// A container for compile-time set info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SetInfo { pub struct SetInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId, value_ty: Type,
value_type_path: TypePathTable,
value_type_id: TypeId,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
} }
@ -94,10 +92,8 @@ impl SetInfo {
/// Create a new [`SetInfo`]. /// Create a new [`SetInfo`].
pub fn new<TSet: Set + TypePath, TValue: Reflect + TypePath>() -> Self { pub fn new<TSet: Set + TypePath, TValue: Reflect + TypePath>() -> Self {
Self { Self {
type_path: TypePathTable::of::<TSet>(), ty: Type::of::<TSet>(),
type_id: TypeId::of::<TSet>(), value_ty: Type::of::<TValue>(),
value_type_path: TypePathTable::of::<TValue>(),
value_type_id: TypeId::of::<TValue>(),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
} }
@ -109,48 +105,13 @@ impl SetInfo {
Self { docs, ..self } Self { docs, ..self }
} }
/// A representation of the type path of the set. impl_type_methods!(ty);
/// The [type] of the value.
/// ///
/// Provides dynamic access to all methods on [`TypePath`]. /// [type]: Type
pub fn type_path_table(&self) -> &TypePathTable { pub fn value_ty(&self) -> Type {
&self.type_path self.value_ty
}
/// The [stable, full type path] of the set.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the set.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the set type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// A representation of the type path of the value type.
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn value_type_path_table(&self) -> &TypePathTable {
&self.value_type_path
}
/// The [`TypeId`] of the value.
pub fn value_type_id(&self) -> TypeId {
self.value_type_id
}
/// Check if the given type matches the value type.
pub fn value_is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.value_type_id
} }
/// The docstring of this set, if any. /// The docstring of this set, if any.

View File

@ -1,17 +1,14 @@
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes}; use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::type_info::impl_type_methods;
use crate::{ use crate::{
self as bevy_reflect, ApplyError, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut, self as bevy_reflect, ApplyError, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
}; };
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use bevy_utils::HashMap; use bevy_utils::HashMap;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::sync::Arc; use std::sync::Arc;
use std::{ use std::{borrow::Cow, slice::Iter};
any::{Any, TypeId},
borrow::Cow,
slice::Iter,
};
/// A trait used to power [struct-like] operations via [reflection]. /// A trait used to power [struct-like] operations via [reflection].
/// ///
@ -78,8 +75,7 @@ pub trait Struct: PartialReflect {
/// A container for compile-time named struct info. /// A container for compile-time named struct info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StructInfo { pub struct StructInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
fields: Box<[NamedField]>, fields: Box<[NamedField]>,
field_names: Box<[&'static str]>, field_names: Box<[&'static str]>,
field_indices: HashMap<&'static str, usize>, field_indices: HashMap<&'static str, usize>,
@ -105,8 +101,7 @@ impl StructInfo {
let field_names = fields.iter().map(NamedField::name).collect(); let field_names = fields.iter().map(NamedField::name).collect();
Self { Self {
type_path: TypePathTable::of::<T>(), ty: Type::of::<T>(),
type_id: TypeId::of::<T>(),
fields: fields.to_vec().into_boxed_slice(), fields: fields.to_vec().into_boxed_slice(),
field_names, field_names,
field_indices, field_indices,
@ -162,32 +157,7 @@ impl StructInfo {
self.fields.len() self.fields.len()
} }
/// A representation of the type path of the struct. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the struct.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the struct.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the struct type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this struct, if any. /// The docstring of this struct, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]

View File

@ -1,13 +1,14 @@
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use bevy_utils::all_tuples; use bevy_utils::all_tuples;
use crate::type_info::impl_type_methods;
use crate::{ use crate::{
self as bevy_reflect, utility::GenericTypePathCell, ApplyError, FromReflect, self as bevy_reflect, utility::GenericTypePathCell, ApplyError, FromReflect,
GetTypeRegistration, MaybeTyped, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, GetTypeRegistration, MaybeTyped, Reflect, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo,
TypePath, TypeRegistration, TypeRegistry, Typed, UnnamedField, TypePath, TypeRegistration, TypeRegistry, Typed, UnnamedField,
}; };
use crate::{PartialReflect, ReflectKind, TypePathTable}; use crate::{PartialReflect, ReflectKind};
use std::any::{Any, TypeId}; use std::any::Any;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::slice::Iter; use std::slice::Iter;
@ -139,8 +140,7 @@ impl GetTupleField for dyn Tuple {
/// A container for compile-time tuple info. /// A container for compile-time tuple info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TupleInfo { pub struct TupleInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
fields: Box<[UnnamedField]>, fields: Box<[UnnamedField]>,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
@ -155,8 +155,7 @@ impl TupleInfo {
/// ///
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self { pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
Self { Self {
type_path: TypePathTable::of::<T>(), ty: Type::of::<T>(),
type_id: TypeId::of::<T>(),
fields: fields.to_vec().into_boxed_slice(), fields: fields.to_vec().into_boxed_slice(),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
@ -184,32 +183,7 @@ impl TupleInfo {
self.fields.len() self.fields.len()
} }
/// A representation of the type path of the tuple. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the tuple.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the tuple.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the tuple type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this tuple, if any. /// The docstring of this tuple, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]

View File

@ -1,11 +1,11 @@
use bevy_reflect_derive::impl_type_path; use bevy_reflect_derive::impl_type_path;
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes}; use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::type_info::impl_type_methods;
use crate::{ use crate::{
self as bevy_reflect, ApplyError, DynamicTuple, PartialReflect, Reflect, ReflectKind, self as bevy_reflect, ApplyError, DynamicTuple, PartialReflect, Reflect, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, Tuple, TypeInfo, TypePath, TypePathTable, UnnamedField, ReflectMut, ReflectOwned, ReflectRef, Tuple, Type, TypeInfo, TypePath, UnnamedField,
}; };
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::slice::Iter; use std::slice::Iter;
use std::sync::Arc; use std::sync::Arc;
@ -58,8 +58,7 @@ pub trait TupleStruct: PartialReflect {
/// A container for compile-time tuple struct info. /// A container for compile-time tuple struct info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TupleStructInfo { pub struct TupleStructInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
fields: Box<[UnnamedField]>, fields: Box<[UnnamedField]>,
custom_attributes: Arc<CustomAttributes>, custom_attributes: Arc<CustomAttributes>,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
@ -75,8 +74,7 @@ impl TupleStructInfo {
/// ///
pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self { pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
Self { Self {
type_path: TypePathTable::of::<T>(), ty: Type::of::<T>(),
type_id: TypeId::of::<T>(),
fields: fields.to_vec().into_boxed_slice(), fields: fields.to_vec().into_boxed_slice(),
custom_attributes: Arc::new(CustomAttributes::default()), custom_attributes: Arc::new(CustomAttributes::default()),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
@ -113,32 +111,7 @@ impl TupleStructInfo {
self.fields.len() self.fields.len()
} }
/// A representation of the type path of the struct. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the struct.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the tuple struct.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the tuple struct type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this struct, if any. /// The docstring of this struct, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]

View File

@ -3,8 +3,10 @@ use crate::{
DynamicTupleStruct, EnumInfo, ListInfo, MapInfo, PartialReflect, Reflect, ReflectKind, SetInfo, DynamicTupleStruct, EnumInfo, ListInfo, MapInfo, PartialReflect, Reflect, ReflectKind, SetInfo,
StructInfo, TupleInfo, TupleStructInfo, TypePath, TypePathTable, StructInfo, TupleInfo, TupleStructInfo, TypePath, TypePathTable,
}; };
use core::fmt::Formatter;
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash;
use thiserror::Error; use thiserror::Error;
/// A static accessor to compile-time type information. /// A static accessor to compile-time type information.
@ -178,36 +180,33 @@ pub enum TypeInfo {
} }
impl TypeInfo { impl TypeInfo {
/// The underlying Rust [type].
///
/// [type]: Type
pub fn ty(&self) -> &Type {
match self {
Self::Struct(info) => info.ty(),
Self::TupleStruct(info) => info.ty(),
Self::Tuple(info) => info.ty(),
Self::List(info) => info.ty(),
Self::Array(info) => info.ty(),
Self::Map(info) => info.ty(),
Self::Set(info) => info.ty(),
Self::Enum(info) => info.ty(),
Self::Value(info) => info.ty(),
}
}
/// The [`TypeId`] of the underlying type. /// The [`TypeId`] of the underlying type.
pub fn type_id(&self) -> TypeId { pub fn type_id(&self) -> TypeId {
match self { self.ty().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::Set(info) => info.type_id(),
Self::Enum(info) => info.type_id(),
Self::Value(info) => info.type_id(),
}
} }
/// A representation of the type path of the underlying type. /// A representation of the type path of the underlying type.
/// ///
/// Provides dynamic access to all methods on [`TypePath`]. /// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable { pub fn type_path_table(&self) -> &TypePathTable {
match self { self.ty().type_path_table()
Self::Struct(info) => info.type_path_table(),
Self::TupleStruct(info) => info.type_path_table(),
Self::Tuple(info) => info.type_path_table(),
Self::List(info) => info.type_path_table(),
Self::Array(info) => info.type_path_table(),
Self::Map(info) => info.type_path_table(),
Self::Set(info) => info.type_path_table(),
Self::Enum(info) => info.type_path_table(),
Self::Value(info) => info.type_path_table(),
}
} }
/// The [stable, full type path] of the underlying type. /// The [stable, full type path] of the underlying type.
@ -217,12 +216,16 @@ impl TypeInfo {
/// [stable, full type path]: TypePath /// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table /// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str { pub fn type_path(&self) -> &'static str {
self.type_path_table().path() self.ty().path()
} }
/// Check if the given type matches the underlying type. /// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
pub fn is<T: Any>(&self) -> bool { pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id() self.ty().is::<T>()
} }
/// The docstring of the underlying type, if any. /// The docstring of the underlying type, if any.
@ -287,6 +290,199 @@ impl TypeInfo {
impl_cast_method!(as_value: Value => ValueInfo); impl_cast_method!(as_value: Value => ValueInfo);
} }
/// The base representation of a Rust type.
///
/// When possible, it is recommended to use [`&'static TypeInfo`] instead of this
/// as it provides more information as well as being smaller
/// (since a reference only takes the same number of bytes as a `usize`).
///
/// However, where a static reference to [`TypeInfo`] is not possible,
/// such as with trait objects and other types that can't implement [`Typed`],
/// this type can be used instead.
///
/// It only requires that the type implements [`TypePath`].
///
/// And unlike [`TypeInfo`], this type implements [`Copy`], [`Eq`], and [`Hash`],
/// making it useful as a key type.
///
/// It's especially helpful when compared to [`TypeId`] as it can provide the
/// actual [type path] when debugging, while still having the same performance
/// as hashing/comparing [`TypeId`] directly—at the cost of a little more memory.
///
/// # Examples
///
/// ```
/// use bevy_reflect::{Type, TypePath};
///
/// fn assert_char<T: ?Sized + TypePath>(t: &T) -> Result<(), String> {
/// let ty = Type::of::<T>();
/// if Type::of::<char>() == ty {
/// Ok(())
/// } else {
/// Err(format!("expected `char`, got `{}`", ty.path()))
/// }
/// }
///
/// assert_eq!(
/// assert_char(&'a'),
/// Ok(())
/// );
/// assert_eq!(
/// assert_char(&String::from("Hello, world!")),
/// Err(String::from("expected `char`, got `alloc::string::String`"))
/// );
/// ```
///
/// [`&'static TypeInfo`]: TypeInfo
#[derive(Copy, Clone)]
pub struct Type {
type_path_table: TypePathTable,
type_id: TypeId,
}
impl Type {
/// Create a new [`Type`] from a type that implements [`TypePath`].
pub fn of<T: TypePath + ?Sized>() -> Self {
Self {
type_path_table: TypePathTable::of::<T>(),
type_id: TypeId::of::<T>(),
}
}
/// Returns the [`TypeId`] of the type.
pub fn id(&self) -> TypeId {
self.type_id
}
/// See [`TypePath::type_path`].
pub fn path(&self) -> &'static str {
self.type_path_table.path()
}
/// See [`TypePath::short_type_path`].
pub fn short_path(&self) -> &'static str {
self.type_path_table.short_path()
}
/// See [`TypePath::type_ident`].
pub fn ident(&self) -> Option<&'static str> {
self.type_path_table.ident()
}
/// See [`TypePath::crate_name`].
pub fn crate_name(&self) -> Option<&'static str> {
self.type_path_table.crate_name()
}
/// See [`TypePath::module_path`].
pub fn module_path(&self) -> Option<&'static str> {
self.type_path_table.module_path()
}
/// A representation of the type path of this.
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path_table
}
/// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
}
/// This implementation will only output the [type path] of the type.
///
/// If you need to include the [`TypeId`] in the output,
/// you can access it through [`Type::id`].
///
/// [type path]: TypePath
impl Debug for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.type_path_table.path())
}
}
impl Eq for Type {}
/// This implementation purely relies on the [`TypeId`] of the type,
/// and not on the [type path].
///
/// [type path]: TypePath
impl PartialEq for Type {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.type_id == other.type_id
}
}
/// This implementation purely relies on the [`TypeId`] of the type,
/// and not on the [type path].
///
/// [type path]: TypePath
impl Hash for Type {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.type_id.hash(state);
}
}
macro_rules! impl_type_methods {
($field:ident) => {
/// The underlying Rust [type].
///
/// [type]: crate::type_info::Type
pub fn ty(&self) -> &$crate::type_info::Type {
&self.$field
}
/// The [`TypeId`] of this type.
///
/// [`TypeId`]: std::any::TypeId
pub fn type_id(&self) -> ::std::any::TypeId {
self.$field.id()
}
/// The [stable, full type path] of this type.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.$field.path()
}
/// A representation of the type path of this type.
///
/// Provides dynamic access to all methods on [`TypePath`].
///
/// [`TypePath`]: crate::type_path::TypePath
pub fn type_path_table(&self) -> &$crate::type_path::TypePathTable {
&self.$field.type_path_table()
}
/// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
///
/// [`TypeId`]: std::any::TypeId
/// [`TypePath`]: crate::type_path::TypePath
pub fn is<T: ::std::any::Any>(&self) -> bool {
self.$field.is::<T>()
}
};
}
pub(crate) use impl_type_methods;
/// 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 /// This typically represents a type which cannot be broken down any further. This is often
@ -297,8 +493,7 @@ impl TypeInfo {
/// it _as_ a struct. It therefore makes more sense to represent it as a [`ValueInfo`]. /// it _as_ a struct. It therefore makes more sense to represent it as a [`ValueInfo`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ValueInfo { pub struct ValueInfo {
type_path: TypePathTable, ty: Type,
type_id: TypeId,
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Option<&'static str>, docs: Option<&'static str>,
} }
@ -306,8 +501,7 @@ pub struct ValueInfo {
impl ValueInfo { impl ValueInfo {
pub fn new<T: Reflect + TypePath + ?Sized>() -> Self { pub fn new<T: Reflect + TypePath + ?Sized>() -> Self {
Self { Self {
type_path: TypePathTable::of::<T>(), ty: Type::of::<T>(),
type_id: TypeId::of::<T>(),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: None, docs: None,
} }
@ -319,32 +513,7 @@ impl ValueInfo {
Self { docs: doc, ..self } Self { docs: doc, ..self }
} }
/// A representation of the type path of the value. impl_type_methods!(ty);
///
/// Provides dynamic access to all methods on [`TypePath`].
pub fn type_path_table(&self) -> &TypePathTable {
&self.type_path
}
/// The [stable, full type path] of the value.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str {
self.type_path_table().path()
}
/// The [`TypeId`] of the value.
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Check if the given type matches the value type.
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id
}
/// The docstring of this dynamic value, if any. /// The docstring of this dynamic value, if any.
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]