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

bevy_reflect: Recursive registration #5781

Merged
merged 17 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
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
30 changes: 25 additions & 5 deletions crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,12 @@ impl<'a> ReflectMeta<'a> {
&self,
where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream {
crate::registration::impl_get_type_registration(self, where_clause_options, None)
crate::registration::impl_get_type_registration(
self,
where_clause_options,
None,
Option::<std::iter::Empty<&Type>>::None,
)
}

/// The collection of docstrings for this type, if any.
Expand Down Expand Up @@ -502,6 +507,7 @@ impl<'a> ReflectStruct<'a> {
self.meta(),
where_clause_options,
self.serialization_data(),
Some(self.active_types().iter()),
)
}

Expand All @@ -512,22 +518,21 @@ impl<'a> ReflectStruct<'a> {
.collect()
}

/// Get an iterator of fields which are exposed to the reflection API
/// Get an iterator of fields which are exposed to the reflection API.
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
self.fields
self.fields()
.iter()
.filter(|field| field.attrs.ignore.is_active())
}

/// Get an iterator of fields which are ignored by the reflection API
pub fn ignored_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
self.fields
self.fields()
.iter()
.filter(|field| field.attrs.ignore.is_ignored())
}

/// The complete set of fields in this struct.
#[allow(dead_code)]
pub fn fields(&self) -> &[StructField<'a>] {
&self.fields
}
Expand Down Expand Up @@ -573,6 +578,21 @@ impl<'a> ReflectEnum<'a> {
pub fn where_clause_options(&self) -> WhereClauseOptions {
WhereClauseOptions::new_with_fields(self.meta(), self.active_types().into_boxed_slice())
}

/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
///
/// Returns a specific implementation for enums and this method should be preferred over the generic [`get_type_registration`](crate::ReflectMeta) method
pub fn get_type_registration(
&self,
where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream {
crate::registration::impl_get_type_registration(
self.meta(),
where_clause_options,
None,
Some(self.active_fields().map(|field| &field.data.ty)),
)
}
}

impl<'a> EnumVariant<'a> {
Expand Down
4 changes: 1 addition & 3 deletions crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream

let type_path_impl = impl_type_path(reflect_enum.meta());

let get_type_registration_impl = reflect_enum
.meta()
.get_type_registration(&where_clause_options);
let get_type_registration_impl = reflect_enum.get_type_registration(&where_clause_options);

let (impl_generics, ty_generics, where_clause) =
reflect_enum.meta().type_path().generics().split_for_impl();
Expand Down
15 changes: 14 additions & 1 deletion crates/bevy_reflect/bevy_reflect_derive/src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,28 @@ use crate::derive_data::ReflectMeta;
use crate::serialization::SerializationDataDef;
use crate::utility::WhereClauseOptions;
use quote::quote;
use syn::Type;

/// Creates the `GetTypeRegistration` impl for the given type data.
#[allow(clippy::too_many_arguments)]
pub(crate) fn impl_get_type_registration(
pub(crate) fn impl_get_type_registration<'a>(
meta: &ReflectMeta,
where_clause_options: &WhereClauseOptions,
serialization_data: Option<&SerializationDataDef>,
type_dependencies: Option<impl Iterator<Item = &'a Type>>,
) -> proc_macro2::TokenStream {
let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path();
let registration_data = meta.attrs().idents();

let type_deps_fn = type_dependencies.map(|deps| {
quote! {
fn register_type_dependencies(registry: &mut #bevy_reflect_path::TypeRegistry) {
#(<#deps as #bevy_reflect_path::__macro_exports::RegisterForReflection>::__register(registry);)*
}
}
});

let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);

Expand Down Expand Up @@ -44,6 +55,8 @@ pub(crate) fn impl_get_type_registration(
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<Self>::from_type());)*
registration
}

#type_deps_fn
}
}
}
14 changes: 9 additions & 5 deletions crates/bevy_reflect/bevy_reflect_derive/src/utility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,15 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {

// `TypePath` is always required for active fields since they are used to
// construct `NamedField` and `UnnamedField` instances for the `Typed` impl.
Some(
self.active_fields
.iter()
.map(move |ty| quote!(#ty : #reflect_bound + #bevy_reflect_path::TypePath)),
)
// Likewise, `GetTypeRegistration` is always required for active fields since
// they are used to register the type's dependencies.
Some(self.active_fields.iter().map(move |ty| {
quote!(
#ty : #reflect_bound
+ #bevy_reflect_path::TypePath
+ #bevy_reflect_path::__macro_exports::RegisterForReflection
)
}))
}
}

Expand Down
Loading