Skip to content

Commit 096611b

Browse files
committed
Add automatic reflection registration
1 parent f62bdc3 commit 096611b

File tree

10 files changed

+218
-18
lines changed

10 files changed

+218
-18
lines changed

crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ impl<'a> ReflectMeta<'a> {
247247
&self.bevy_reflect_path,
248248
self.traits.idents(),
249249
self.generics,
250+
None::<std::iter::Empty<&Type>>,
250251
)
251252
}
252253
}
@@ -259,12 +260,12 @@ impl<'a> ReflectStruct<'a> {
259260

260261
/// Get an iterator over the active fields.
261262
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
262-
self.fields.iter().filter(|field| !field.attrs.ignore)
263+
self.fields().iter().filter(|field| !field.attrs.ignore)
263264
}
264265

265266
/// Get an iterator over the ignored fields.
266267
pub fn ignored_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
267-
self.fields.iter().filter(|field| field.attrs.ignore)
268+
self.fields().iter().filter(|field| field.attrs.ignore)
268269
}
269270

270271
/// Get a collection of all active types.
@@ -273,10 +274,20 @@ impl<'a> ReflectStruct<'a> {
273274
}
274275

275276
/// The complete set of fields in this struct.
276-
#[allow(dead_code)]
277277
pub fn fields(&self) -> &[StructField<'a>] {
278278
&self.fields
279279
}
280+
281+
/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
282+
pub fn get_type_registration(&self) -> proc_macro2::TokenStream {
283+
crate::registration::impl_get_type_registration(
284+
self.meta.type_name,
285+
&self.meta.bevy_reflect_path,
286+
self.meta.traits.idents(),
287+
self.meta.generics,
288+
Some(self.active_types()),
289+
)
290+
}
280291
}
281292

282293
impl<'a> ReflectEnum<'a> {
@@ -309,4 +320,35 @@ impl<'a> ReflectEnum<'a> {
309320
pub fn variants(&self) -> &[EnumVariant<'a>] {
310321
&self.variants
311322
}
323+
324+
/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
325+
pub fn get_type_registration(&self) -> proc_macro2::TokenStream {
326+
crate::registration::impl_get_type_registration(
327+
self.meta.type_name,
328+
&self.meta.bevy_reflect_path,
329+
self.meta.traits.idents(),
330+
self.meta.generics,
331+
Some(
332+
self.active_variants()
333+
.flat_map(|variant| variant.active_fields())
334+
.map(|field| &field.data.ty),
335+
),
336+
)
337+
}
338+
}
339+
340+
impl<'a> EnumVariant<'a> {
341+
/// The complete set of fields in this variant.
342+
pub fn fields(&self) -> &[StructField<'a>] {
343+
match &self.fields {
344+
EnumVariantFields::Named(fields) => fields,
345+
EnumVariantFields::Unnamed(fields) => fields,
346+
EnumVariantFields::Unit => &[],
347+
}
348+
}
349+
350+
/// Get an iterator over the active fields in this variant.
351+
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
352+
self.fields().iter().filter(|field| !field.attrs.ignore)
353+
}
312354
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
6464
bevy_reflect_path,
6565
);
6666

67-
let get_type_registration_impl = reflect_enum.meta().get_type_registration();
67+
let get_type_registration_impl = reflect_enum.get_type_registration();
6868
let (impl_generics, ty_generics, where_clause) =
6969
reflect_enum.meta().generics().split_for_impl();
7070

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
6464
bevy_reflect_path,
6565
);
6666

67-
let get_type_registration_impl = reflect_struct.meta().get_type_registration();
67+
let get_type_registration_impl = reflect_struct.get_type_registration();
6868
let (impl_generics, ty_generics, where_clause) =
6969
reflect_struct.meta().generics().split_for_impl();
7070

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syn::{Index, Member};
88
pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
99
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
1010
let struct_name = reflect_struct.meta().type_name();
11-
let get_type_registration_impl = reflect_struct.meta().get_type_registration();
11+
let get_type_registration_impl = reflect_struct.get_type_registration();
1212

1313
let field_idents = reflect_struct
1414
.active_fields()

crates/bevy_reflect/bevy_reflect_derive/src/registration.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@
22
33
use proc_macro2::Ident;
44
use quote::quote;
5-
use syn::{Generics, Path};
5+
use syn::{Generics, Path, Type};
66

77
/// Creates the `GetTypeRegistration` impl for the given type data.
8-
pub(crate) fn impl_get_type_registration(
8+
pub(crate) fn impl_get_type_registration<'a>(
99
type_name: &Ident,
1010
bevy_reflect_path: &Path,
1111
registration_data: &[Ident],
1212
generics: &Generics,
13+
type_dependencies: Option<impl Iterator<Item = &'a Type>>,
1314
) -> proc_macro2::TokenStream {
15+
let type_deps_fn = type_dependencies.map(|deps| {
16+
quote! {
17+
fn register_type_dependencies(registry: &mut #bevy_reflect_path::__macro_exports::TypeRegistry) {
18+
#(registry.try_register::<#deps>();)*
19+
}
20+
}
21+
});
22+
1423
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
1524
quote! {
1625
#[allow(unused_mut)]
@@ -21,6 +30,8 @@ pub(crate) fn impl_get_type_registration(
2130
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());)*
2231
registration
2332
}
33+
34+
#type_deps_fn
2435
}
2536
}
2637
}

crates/bevy_reflect/src/enums/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ mod tests {
340340
#[test]
341341
fn enum_should_allow_generics() {
342342
#[derive(Reflect, Debug, PartialEq)]
343-
enum TestEnum<T: FromReflect> {
343+
enum TestEnum<T: FromReflect + GetTypeRegistration> {
344344
A,
345345
B(T),
346346
C { value: T },

crates/bevy_reflect/src/impls/std.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{self as bevy_reflect, ReflectFromPtr};
1+
use crate::{self as bevy_reflect, ReflectFromPtr, TypeRegistry};
22
use crate::{
33
map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum, DynamicMap, Enum,
44
EnumInfo, FromReflect, FromType, GetTypeRegistration, List, ListInfo, Map, MapInfo, MapIter,
@@ -195,12 +195,16 @@ impl<T: FromReflect> Typed for Vec<T> {
195195
}
196196
}
197197

198-
impl<T: FromReflect> GetTypeRegistration for Vec<T> {
198+
impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for Vec<T> {
199199
fn get_type_registration() -> TypeRegistration {
200200
let mut registration = TypeRegistration::of::<Vec<T>>();
201201
registration.insert::<ReflectFromPtr>(FromType::<Vec<T>>::from_type());
202202
registration
203203
}
204+
205+
fn register_type_dependencies(registry: &mut TypeRegistry) {
206+
registry.try_register::<T>();
207+
}
204208
}
205209

206210
impl<T: FromReflect> FromReflect for Vec<T> {
@@ -346,14 +350,19 @@ impl<K: FromReflect + Eq + Hash, V: FromReflect> Typed for HashMap<K, V> {
346350

347351
impl<K, V> GetTypeRegistration for HashMap<K, V>
348352
where
349-
K: FromReflect + Eq + Hash,
350-
V: FromReflect,
353+
K: FromReflect + GetTypeRegistration + Eq + Hash,
354+
V: FromReflect + GetTypeRegistration,
351355
{
352356
fn get_type_registration() -> TypeRegistration {
353357
let mut registration = TypeRegistration::of::<HashMap<K, V>>();
354358
registration.insert::<ReflectFromPtr>(FromType::<HashMap<K, V>>::from_type());
355359
registration
356360
}
361+
362+
fn register_type_dependencies(registry: &mut TypeRegistry) {
363+
registry.try_register::<K>();
364+
registry.try_register::<V>();
365+
}
357366
}
358367

359368
impl<K: FromReflect + Eq + Hash, V: FromReflect> FromReflect for HashMap<K, V> {
@@ -498,10 +507,14 @@ impl<T: Reflect, const N: usize> Typed for [T; N] {
498507
macro_rules! impl_array_get_type_registration {
499508
($($N:expr)+) => {
500509
$(
501-
impl<T: Reflect > GetTypeRegistration for [T; $N] {
510+
impl<T: Reflect + GetTypeRegistration> GetTypeRegistration for [T; $N] {
502511
fn get_type_registration() -> TypeRegistration {
503512
TypeRegistration::of::<[T; $N]>()
504513
}
514+
515+
fn register_type_dependencies(registry: &mut TypeRegistry) {
516+
registry.try_register::<T>();
517+
}
505518
}
506519
)+
507520
};
@@ -586,10 +599,14 @@ impl Reflect for Cow<'static, str> {
586599
}
587600
}
588601

589-
impl<T: FromReflect> GetTypeRegistration for Option<T> {
602+
impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for Option<T> {
590603
fn get_type_registration() -> TypeRegistration {
591604
TypeRegistration::of::<Option<T>>()
592605
}
606+
607+
fn register_type_dependencies(registry: &mut TypeRegistry) {
608+
registry.try_register::<T>();
609+
}
593610
}
594611

595612
impl<T: FromReflect> Enum for Option<T> {

crates/bevy_reflect/src/lib.rs

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ pub use erased_serde;
6262
pub mod __macro_exports {
6363
use crate::Uuid;
6464

65+
pub use crate::TypeRegistry;
66+
6567
/// Generates a new UUID from the given UUIDs `a` and `b`,
6668
/// where the bytes are generated by a bitwise `a ^ b.rotate_right(1)`.
6769
/// The generated UUID will be a `UUIDv4` (meaning that the bytes should be random, not e.g. derived from the system time).
@@ -99,6 +101,7 @@ mod tests {
99101
ser::{to_string_pretty, PrettyConfig},
100102
Deserializer,
101103
};
104+
use std::any::TypeId;
102105
use std::fmt::{Debug, Formatter};
103106

104107
use super::prelude::*;
@@ -436,6 +439,99 @@ mod tests {
436439
assert_eq!(new_foo, expected_new_foo);
437440
}
438441

442+
#[test]
443+
fn should_auto_register_fields() {
444+
#[derive(Reflect, FromReflect)]
445+
struct Foo {
446+
bar: Bar,
447+
}
448+
449+
#[derive(Reflect, FromReflect)]
450+
enum Bar {
451+
Variant(Baz),
452+
}
453+
454+
#[derive(Reflect, FromReflect)]
455+
struct Baz(usize);
456+
457+
// === Basic === //
458+
let mut registry = TypeRegistry::empty();
459+
registry.register::<Foo>();
460+
461+
assert!(
462+
registry.contains(TypeId::of::<Bar>()),
463+
"registry should contain auto-registered `Bar` from `Foo`"
464+
);
465+
466+
// === Option === //
467+
let mut registry = TypeRegistry::empty();
468+
registry.register::<Option<Foo>>();
469+
470+
assert!(
471+
registry.contains(TypeId::of::<Bar>()),
472+
"registry should contain auto-registered `Bar` from `Option<Foo>`"
473+
);
474+
475+
// === Tuple === //
476+
let mut registry = TypeRegistry::empty();
477+
registry.register::<(Foo, Foo)>();
478+
479+
assert!(
480+
registry.contains(TypeId::of::<Bar>()),
481+
"registry should contain auto-registered `Bar` from `(Foo, Foo)`"
482+
);
483+
484+
// === Array === //
485+
let mut registry = TypeRegistry::empty();
486+
registry.register::<[Foo; 3]>();
487+
488+
assert!(
489+
registry.contains(TypeId::of::<Bar>()),
490+
"registry should contain auto-registered `Bar` from `[Foo; 3]`"
491+
);
492+
493+
// === Vec === //
494+
let mut registry = TypeRegistry::empty();
495+
registry.register::<Vec<Foo>>();
496+
497+
assert!(
498+
registry.contains(TypeId::of::<Bar>()),
499+
"registry should contain auto-registered `Bar` from `Vec<Foo>`"
500+
);
501+
502+
// === HashMap === //
503+
let mut registry = TypeRegistry::empty();
504+
registry.register::<HashMap<i32, Foo>>();
505+
506+
assert!(
507+
registry.contains(TypeId::of::<Bar>()),
508+
"registry should contain auto-registered `Bar` from `HashMap<i32, Foo>`"
509+
);
510+
}
511+
512+
#[test]
513+
fn should_not_auto_register_existing_types() {
514+
#[derive(Reflect)]
515+
struct Foo {
516+
bar: Bar,
517+
}
518+
519+
#[derive(Reflect, Default)]
520+
struct Bar(usize);
521+
522+
let mut registry = TypeRegistry::empty();
523+
registry.register::<Bar>();
524+
registry.register_type_data::<Bar, ReflectDefault>();
525+
registry.register::<Foo>();
526+
527+
assert!(
528+
registry
529+
.get_type_data::<ReflectDefault>(TypeId::of::<Bar>())
530+
.is_some(),
531+
"registry should contain existing registration for `Bar`"
532+
);
533+
}
534+
439535
#[test]
440536
fn reflect_serialize() {
441537
#[derive(Reflect)]
@@ -628,7 +724,7 @@ mod tests {
628724

629725
// Struct (generic)
630726
#[derive(Reflect)]
631-
struct MyGenericStruct<T: Reflect> {
727+
struct MyGenericStruct<T: Reflect + GetTypeRegistration> {
632728
foo: T,
633729
bar: usize,
634730
}

crates/bevy_reflect/src/tuple.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::utility::NonGenericTypeInfoCell;
22
use crate::{
33
DynamicInfo, FromReflect, GetTypeRegistration, Reflect, ReflectMut, ReflectRef, TypeInfo,
4-
TypeRegistration, Typed, UnnamedField,
4+
TypeRegistration, TypeRegistry, Typed, UnnamedField,
55
};
66
use std::any::{Any, TypeId};
77
use std::fmt::{Debug, Formatter};
@@ -533,10 +533,14 @@ macro_rules! impl_reflect_tuple {
533533
}
534534
}
535535

536-
impl<$($name: Reflect + Typed),*> GetTypeRegistration for ($($name,)*) {
536+
impl<$($name: Reflect + Typed + GetTypeRegistration),*> GetTypeRegistration for ($($name,)*) {
537537
fn get_type_registration() -> TypeRegistration {
538538
TypeRegistration::of::<($($name,)*)>()
539539
}
540+
541+
fn register_type_dependencies(_registry: &mut TypeRegistry) {
542+
$(_registry.try_register::<$name>();)*
543+
}
540544
}
541545

542546
impl<$($name: FromReflect),*> FromReflect for ($($name,)*)

0 commit comments

Comments
 (0)