Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - bevy_reflect: Add statically available type info for reflected types #4042

Closed
wants to merge 53 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ed5e997
Added TypeInfo
MrGVSV Feb 26, 2022
bfcfa25
Added tests
MrGVSV Feb 26, 2022
190dbc2
Fix clippy warnings
MrGVSV Feb 26, 2022
ea49152
Formatting
MrGVSV Feb 26, 2022
0ec2270
Apply suggestions from code review
MrGVSV Feb 26, 2022
b0dfaa9
Added relevant TypeIds to info structs
MrGVSV Feb 27, 2022
23e276a
Formatting
MrGVSV Feb 27, 2022
83c5e6e
Added convenience methods to TypeInfo
MrGVSV Feb 27, 2022
81c1298
Added Typed trait
MrGVSV Mar 5, 2022
8ad235c
Formatting
MrGVSV Mar 5, 2022
e9f39cf
Impl Typed for dyn Reflect
MrGVSV Mar 5, 2022
ad786ad
Formatting
MrGVSV Mar 5, 2022
a5ca84d
Replaced Cow<'static, str> with &'static str
MrGVSV Mar 5, 2022
f8e57a9
Store fields as Box<[T]>
MrGVSV Mar 5, 2022
fea5343
Added documentation for DynamicInfo
MrGVSV Mar 5, 2022
091e5e8
Added TypeIdentity
MrGVSV Mar 5, 2022
8cf5029
Integrated TypeIdentity across type info structs
MrGVSV Mar 5, 2022
9cbaf28
Fixed doc error
MrGVSV Mar 6, 2022
f6cbb1d
Remove duplicated data
MrGVSV Mar 8, 2022
55e023b
Removed unnecessary methods
MrGVSV Mar 8, 2022
000c327
Clarify comments
MrGVSV Mar 8, 2022
097b1f2
Added static_new method to create field with static str
MrGVSV Mar 8, 2022
d1ddb1f
Use the cow
MrGVSV Mar 8, 2022
4fcc07f
Merge branch 'main' into reflect-type-info
MrGVSV Apr 27, 2022
1f89001
Merge branch 'main' into reflect-type-info
MrGVSV May 9, 2022
018a125
Merge branch 'main' into reflect-type-info
MrGVSV May 11, 2022
8d93a67
Merge branch 'main' into reflect-type-info
MrGVSV May 13, 2022
be284d6
Merge branch 'reflect-type-info' of https://github.com/MrGVSV/bevy in…
MrGVSV May 13, 2022
ab8d022
Resolve merge conflict
MrGVSV May 13, 2022
9a41c85
Formatting
MrGVSV May 13, 2022
16d3ab6
Fix doc wording
MrGVSV May 13, 2022
ea9d34b
Add Reflect::get_type_info
MrGVSV May 18, 2022
d2f8f9f
Merge branch 'main' into reflect-type-info
MrGVSV May 18, 2022
5544557
Renamed name -> type_name
MrGVSV May 18, 2022
5d97ea5
Formatting
MrGVSV May 18, 2022
43dda0a
Remove unused import
MrGVSV May 18, 2022
51e1214
Removed TypeIdentity
MrGVSV May 25, 2022
4c0040a
Change doc wording
MrGVSV May 25, 2022
c3c54cb
Combine constructors
MrGVSV May 25, 2022
a877911
Return static TypeInfo from Typed::type_info()
MrGVSV May 26, 2022
63c284f
Remove extraneous import
MrGVSV May 26, 2022
aa5178e
Fix clippy warnings
MrGVSV May 27, 2022
c18cf5c
Merge branch 'main' into reflect-type-info
MrGVSV May 30, 2022
e87c24b
Fix incorrect non-generic TypeInfoCell
MrGVSV May 30, 2022
1e7cbd8
Use TypeInfo to default trait methods
MrGVSV May 30, 2022
87f1069
Merge branch 'main' into reflect-type-info
MrGVSV May 30, 2022
ee38b76
Improve docs
MrGVSV Jun 4, 2022
f8b4d07
Remove ListInfo capacity
MrGVSV Jun 4, 2022
38b2611
Replace list capacity references
MrGVSV Jun 4, 2022
16b7938
Revert "Use TypeInfo to default trait methods"
MrGVSV Jun 9, 2022
c0495e5
Split up TypeInfoCell
MrGVSV Jun 9, 2022
0fc6b64
Change wording in docs
MrGVSV Jun 9, 2022
6ddb85a
Merge remote-tracking branch 'origin/main' into pr/MrGVSV/4042-1
cart Jun 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_reflect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
100 changes: 100 additions & 0 deletions crates/bevy_reflect/bevy_reflect_derive/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream {
.unwrap_or_else(|| Member::Unnamed(Index::from(field.index)))
})
.collect::<Vec<_>>();
let field_types = derive_data
.active_fields()
.map(|field| field.data.ty.clone())
.collect::<Vec<_>>();
let field_count = field_idents.len();
let field_indices = (0..field_count).collect::<Vec<usize>>();

Expand All @@ -49,12 +53,27 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream {
});
let debug_fn = derive_data.traits().get_debug_impl();

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::<Self>(&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 {
Expand Down Expand Up @@ -114,6 +133,11 @@ pub(crate) fn impl_struct(derive_data: &ReflectDeriveData) -> TokenStream {
std::any::type_name::<Self>()
}

#[inline]
fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo {
<Self as #bevy_reflect_path::Typed>::type_info()
}

#[inline]
fn any(&self) -> &dyn std::any::Any {
self
Expand Down Expand Up @@ -184,6 +208,10 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream
.active_fields()
.map(|field| Member::Unnamed(Index::from(field.index)))
.collect::<Vec<_>>();
let field_types = derive_data
.active_fields()
.map(|field| field.data.ty.clone())
.collect::<Vec<_>>();
let field_count = field_idents.len();
let field_indices = (0..field_count).collect::<Vec<usize>>();

Expand All @@ -201,10 +229,25 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream
});
let debug_fn = derive_data.traits().get_debug_impl();

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::<Self>(&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 {
Expand Down Expand Up @@ -243,6 +286,11 @@ pub(crate) fn impl_tuple_struct(derive_data: &ReflectDeriveData) -> TokenStream
std::any::type_name::<Self>()
}

#[inline]
fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo {
<Self as #bevy_reflect_path::Typed>::type_info()
}

#[inline]
fn any(&self) -> &dyn std::any::Any {
self
Expand Down Expand Up @@ -315,17 +363,34 @@ pub(crate) fn impl_value(
let partial_eq_fn = reflect_traits.get_partial_eq_impl(bevy_reflect_path);
let debug_fn = reflect_traits.get_debug_impl();

let typed_impl = impl_typed(
type_name,
generics,
quote! {
let info = #bevy_reflect_path::ValueInfo::new::<Self>();
#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]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}

#[inline]
fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo {
<Self as #bevy_reflect_path::Typed>::type_info()
}

#[inline]
fn any(&self) -> &dyn std::any::Any {
self
Expand Down Expand Up @@ -385,3 +450,38 @@ pub(crate) fn impl_value(
}
})
}

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::GenericTypeInfoCell = #bevy_reflect_path::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| {
#generator
})
}
} else {
quote! {
static CELL: #bevy_reflect_path::utility::NonGenericTypeInfoCell = #bevy_reflect_path::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(|| {
#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() -> &'static #bevy_reflect_path::TypeInfo {
#static_generator
}
}
}
}
86 changes: 84 additions & 2 deletions crates/bevy_reflect/src/array.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
use crate::{
serde::Serializable, utility::NonGenericTypeInfoCell, DynamicInfo, Reflect, ReflectMut,
ReflectRef, TypeInfo, Typed,
};
use std::{
any::Any,
any::{Any, TypeId},
fmt::Debug,
hash::{Hash, Hasher},
};
Expand Down Expand Up @@ -37,6 +40,73 @@ pub trait Array: Reflect {
}
}

/// A container for compile-time array info.
#[derive(Clone, Debug)]
pub struct ArrayInfo {
type_name: &'static str,
type_id: TypeId,
item_type_name: &'static str,
item_type_id: TypeId,
capacity: usize,
}

impl ArrayInfo {
/// Create a new [`ArrayInfo`].
///
/// # Arguments
///
/// * `capacity`: The maximum capacity of the underlying array.
///
pub fn new<TArray: Array, TItem: Reflect>(capacity: usize) -> Self {
Self {
type_name: std::any::type_name::<TArray>(),
type_id: TypeId::of::<TArray>(),
item_type_name: std::any::type_name::<TItem>(),
item_type_id: TypeId::of::<TItem>(),
capacity,
}
}

/// The compile-time capacity of the array.
pub fn capacity(&self) -> usize {
self.capacity
}

/// The [type name] of the array.
///
/// [type name]: std::any::type_name
pub fn type_name(&self) -> &'static str {
self.type_name
}

/// 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 [type name] of the array item.
///
/// [type name]: std::any::type_name
pub fn item_type_name(&self) -> &'static str {
self.item_type_name
}

/// 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
}
}

/// A fixed-size list of reflected values.
///
/// This differs from [`DynamicList`] in that the size of the [`DynamicArray`]
Expand Down Expand Up @@ -89,6 +159,11 @@ unsafe impl Reflect for DynamicArray {
self.name.as_str()
}

#[inline]
fn get_type_info(&self) -> &'static TypeInfo {
<Self as Typed>::type_info()
}

#[inline]
fn any(&self) -> &dyn Any {
self
Expand Down Expand Up @@ -185,6 +260,13 @@ impl Array for DynamicArray {
}
}

impl Typed for DynamicArray {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::<Self>()))
}
}

/// An iterator over an [`Array`].
pub struct ArrayIter<'a> {
pub(crate) array: &'a dyn Array,
Expand Down
84 changes: 84 additions & 0 deletions crates/bevy_reflect/src/fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use crate::Reflect;
use std::any::{Any, TypeId};
use std::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,
}

impl NamedField {
/// Create a new [`NamedField`].
pub fn new<T: Reflect, TName: Into<Cow<'static, str>>>(name: TName) -> Self {
Self {
name: name.into(),
type_name: std::any::type_name::<T>(),
type_id: TypeId::of::<T>(),
}
}

/// The name of the field.
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}

/// The [type name] of the field.
///
/// [type name]: std::any::type_name
pub fn type_name(&self) -> &'static str {
self.type_name
}

/// 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 unnamed field of a reflected tuple or tuple struct.
#[derive(Clone, Debug)]
pub struct UnnamedField {
index: usize,
type_name: &'static str,
type_id: TypeId,
}

impl UnnamedField {
pub fn new<T: Reflect>(index: usize) -> Self {
Self {
index,
type_name: std::any::type_name::<T>(),
type_id: TypeId::of::<T>(),
}
}

/// Returns the index of the field.
pub fn index(&self) -> usize {
self.index
}

/// The [type name] of the field.
///
/// [type name]: std::any::type_name
pub fn type_name(&self) -> &'static str {
self.type_name
}

/// 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
}
}
Loading