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

Reflect auto registration #15030

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4b48e23
minimal example auto registration for reflect types
eugineerd Sep 2, 2024
89c52dd
implement auto registration for the rest of supported `#[derive(Refle…
eugineerd Sep 3, 2024
f3614b8
add `no_auto_register` reflect attribute to allow opting out of autom…
eugineerd Sep 3, 2024
7367345
added `reflect_auto_register` feature to allow enabling/disabling aut…
eugineerd Sep 3, 2024
16ee7cf
reduce wasm overhead
eugineerd Sep 4, 2024
35f0591
run `cargo run -p build-templated-pages -- update features`
eugineerd Sep 4, 2024
119a598
fix not registering `TypeData`
eugineerd Sep 4, 2024
53696f7
add doc test and remove feature-gating
eugineerd Sep 5, 2024
7d761e1
remove `dbg!`
eugineerd Sep 5, 2024
d8eb597
update examples for automatic reflect type registration
eugineerd Sep 5, 2024
1da577a
fix typo
eugineerd Sep 5, 2024
4485798
remove outdated comment from reflect Cargo.toml
eugineerd Sep 5, 2024
ef6bb2d
remove needless borrow
eugineerd Sep 5, 2024
5fa1572
fix from check-doc
eugineerd Sep 5, 2024
d2d3290
move calling automatic type registration to `AppTypeRegistry`.
eugineerd Sep 5, 2024
878e8d3
more clippy fixes
eugineerd Sep 5, 2024
b518d5e
Move automatic types registration to app creation
eugineerd Sep 5, 2024
edf5f87
revert changes to examples that use `TypeRegistry`
eugineerd Sep 6, 2024
e9f67f0
hide automatic reflect registration in `__macro_exports`
eugineerd Sep 6, 2024
301b60a
add note about `no_auto_register` to `Reflect` derive doc
eugineerd Sep 6, 2024
6ad0a23
made `inventory` and `wasm-init` platform specific deps
eugineerd Sep 7, 2024
1279d62
tried to abstract platform-dependent code away
eugineerd Sep 7, 2024
74337f7
update `bevy_reflect`'s module-level doc's "Manual Registration" section
eugineerd Sep 7, 2024
7723de5
Merge remote-tracking branch 'upstream/main' into reflect-auto-regist…
eugineerd Oct 2, 2024
b18b645
Merge remote-tracking branch 'upstream/main' into reflect-auto-regist…
eugineerd Oct 20, 2024
257af97
Merge branch 'main' into reflect-auto-registration
eugineerd Dec 1, 2024
943dde9
added test for ignored auto reflect registration
eugineerd Dec 1, 2024
36f49f0
clippy
eugineerd Dec 1, 2024
e50610b
apply suggested doc fix
eugineerd Dec 1, 2024
b0f2438
implement reflect auto register for opaque types
eugineerd Dec 1, 2024
2ae4bb9
add test for auto reflect registration on all supported types
eugineerd Dec 1, 2024
7c7bd79
put automatic type registration behind feature gate
eugineerd Dec 1, 2024
03ce543
add reason to `no_auto_register` allow
eugineerd Dec 1, 2024
67f4d02
use `impl_is_generic` instead of converting to token stream.
eugineerd Dec 1, 2024
1548654
Merge remote-tracking branch 'upstream/main' into reflect-auto-regist…
eugineerd Dec 8, 2024
69bbc17
fix missing `[package]` in `bevy_reflect/Cargo.toml` (How did that ev…
eugineerd Dec 8, 2024
e82d33c
Merge branch 'main' into reflect-auto-registration
eugineerd Jan 4, 2025
58b847c
add `no_std` support on wasm
eugineerd Jan 4, 2025
95593d1
feature-gate `no_auto_register` attribute getter
eugineerd Jan 5, 2025
e18aaef
Merge branch 'main' of https://github.com/bevyengine/bevy into reflec…
eugineerd Jan 20, 2025
42db5e0
Merge branch 'main' of https://github.com/bevyengine/bevy into reflec…
eugineerd Feb 21, 2025
1bb9ee8
remove `wasm-init` and just use `inventory` instead
eugineerd Feb 21, 2025
c6be4fa
Merge branch 'main' of https://github.com/bevyengine/bevy into reflec…
eugineerd Feb 25, 2025
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
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ default = [
"hdr",
"multi_threaded",
"png",
"reflect_auto_register",
"smaa_luts",
"sysinfo_plugin",
"tonemapping_luts",
Expand Down Expand Up @@ -478,6 +479,9 @@ reflect_functions = ["bevy_internal/reflect_functions"]
# Enable documentation reflection
reflect_documentation = ["bevy_internal/reflect_documentation"]

# Enable automatic reflect registration
reflect_auto_register = ["bevy_internal/reflect_auto_register"]

# Enable winit custom cursor support
custom_cursor = ["bevy_internal/custom_cursor"]

Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ reflect_functions = [
"bevy_reflect/functions",
"bevy_ecs/reflect_functions",
]
reflect_auto_register = [
"bevy_reflect",
"bevy_reflect/auto_register",
"bevy_ecs/reflect_auto_register",
]

## Adds support for running async background tasks
bevy_tasks = ["dep:bevy_tasks"]
Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ impl Default for App {

#[cfg(feature = "bevy_reflect")]
{
#[cfg(not(feature = "reflect_auto_register"))]
app.init_resource::<AppTypeRegistry>();

#[cfg(feature = "reflect_auto_register")]
app.insert_resource(AppTypeRegistry::new_with_derived_types());

app.register_type::<Name>();
app.register_type::<ChildOf>();
app.register_type::<Children>();
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ bevy_reflect = ["dep:bevy_reflect"]

## Extends reflection support to functions.
reflect_functions = ["bevy_reflect", "bevy_reflect/functions"]
reflect_auto_register = ["bevy_reflect", "bevy_reflect/auto_register"]

## Use the configurable global error handler as the default error handler
configurable_error_handler = []
Expand Down
12 changes: 12 additions & 0 deletions crates/bevy_ecs/src/reflect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ impl DerefMut for AppTypeRegistry {
}
}

impl AppTypeRegistry {
/// Creates [`AppTypeRegistry`] and automatically registers all types deriving [`Reflect`].
///
/// See [`TypeRegistry::register_derived_types`] for more details.
#[cfg(feature = "reflect_auto_register")]
pub fn new_with_derived_types() -> Self {
let app_registry = AppTypeRegistry::default();
app_registry.write().register_derived_types();
app_registry
}
}

/// A [`Resource`] storing [`FunctionRegistry`] for
/// function registrations relevant to a whole app.
///
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ reflect_functions = [
"bevy_app/reflect_functions",
"bevy_ecs/reflect_functions",
]
# Enable automatic reflect registration
reflect_auto_register = [
"bevy_reflect/auto_register",
"bevy_app/reflect_auto_register",
"bevy_ecs/reflect_auto_register",
]

# Enable documentation reflection
reflect_documentation = ["bevy_reflect/documentation"]
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_reflect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ critical-section = [
"bevy_platform_support/critical-section",
"bevy_utils/critical-section",
]
# Enables automatic reflect registration
auto_register = ["bevy_reflect_derive/auto_register", "dep:inventory"]

[dependencies]
# bevy
Expand Down Expand Up @@ -111,9 +113,13 @@ uuid = { version = "1.13.1", default-features = false, optional = true, features
variadics_please = "1.1"
wgpu-types = { version = "24", features = ["serde"], optional = true }

# deps for automatic type registration
inventory = { version = "0.3", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
uuid = { version = "1.13.1", default-features = false, features = ["js"] }


[dev-dependencies]
ron = "0.8.0"
rmp-serde = "1.1"
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_reflect/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ default = []
documentation = []
# Enables macro logic related to function reflection
functions = []
# Enables automatic reflect registration
auto_register = []

[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.16.0-dev" }
Expand Down
20 changes: 20 additions & 0 deletions crates/bevy_reflect/derive/src/container_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod kw {
syn::custom_keyword!(PartialEq);
syn::custom_keyword!(Hash);
syn::custom_keyword!(no_field_bounds);
syn::custom_keyword!(no_auto_register);
syn::custom_keyword!(opaque);
}

Expand Down Expand Up @@ -182,6 +183,7 @@ pub(crate) struct ContainerAttributes {
type_path_attrs: TypePathAttrs,
custom_where: Option<WhereClause>,
no_field_bounds: bool,
no_auto_register: bool,
custom_attributes: CustomAttributes,
is_opaque: bool,
idents: Vec<Ident>,
Expand Down Expand Up @@ -236,6 +238,8 @@ impl ContainerAttributes {
self.parse_opaque(input)
} else if lookahead.peek(kw::no_field_bounds) {
self.parse_no_field_bounds(input)
} else if lookahead.peek(kw::no_auto_register) {
self.parse_no_auto_register(input)
} else if lookahead.peek(kw::Debug) {
self.parse_debug(input)
} else if lookahead.peek(kw::PartialEq) {
Expand Down Expand Up @@ -354,6 +358,16 @@ impl ContainerAttributes {
Ok(())
}

/// Parse `no_auto_register` attribute.
///
/// Examples:
/// - `#[reflect(no_auto_register)]`
fn parse_no_auto_register(&mut self, input: ParseStream) -> syn::Result<()> {
input.parse::<kw::no_auto_register>()?;
self.no_auto_register = true;
Ok(())
}

/// Parse `where` attribute.
///
/// Examples:
Expand Down Expand Up @@ -537,6 +551,12 @@ impl ContainerAttributes {
self.no_field_bounds
}

/// Returns true if the `no_auto_register` attribute was found on this type.
#[cfg(feature = "auto_register")]
pub fn no_auto_register(&self) -> bool {
self.no_auto_register
}

/// Returns true if the `opaque` attribute was found on this type.
pub fn is_opaque(&self) -> bool {
self.is_opaque
Expand Down
22 changes: 22 additions & 0 deletions crates/bevy_reflect/derive/src/impls/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,25 @@ pub fn common_partial_reflect_methods(
#debug_fn
}
}

#[cfg(feature = "auto_register")]
pub fn reflect_auto_registration(meta: &ReflectMeta) -> Option<proc_macro2::TokenStream> {
if meta.attrs().no_auto_register() {
return None;
}

let bevy_reflect_path = meta.bevy_reflect_path();
let type_path = meta.type_path();

if type_path.impl_is_generic() {
return None;
};

Some(quote! {
#bevy_reflect_path::__macro_exports::auto_register::inventory::submit!{
#bevy_reflect_path::__macro_exports::auto_register::AutomaticReflectRegistrations(
<#type_path as #bevy_reflect_path::__macro_exports::RegisterForReflection>::__register
)
}
})
}
7 changes: 7 additions & 0 deletions crates/bevy_reflect/derive/src/impls/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
let (impl_generics, ty_generics, where_clause) =
reflect_enum.meta().type_path().generics().split_for_impl();

#[cfg(not(feature = "auto_register"))]
let auto_register = None::<proc_macro2::TokenStream>;
#[cfg(feature = "auto_register")]
let auto_register = crate::impls::reflect_auto_registration(reflect_enum.meta());

let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);

quote! {
Expand All @@ -95,6 +100,8 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream

#function_impls

#auto_register

impl #impl_generics #bevy_reflect_path::Enum for #enum_path #ty_generics #where_reflect_clause {
fn field(&self, #ref_name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match #match_this {
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_reflect/derive/src/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ mod tuple_structs;
mod typed;

pub(crate) use assertions::impl_assertions;
#[cfg(feature = "auto_register")]
pub(crate) use common::reflect_auto_registration;
pub(crate) use common::{common_partial_reflect_methods, impl_full_reflect};
pub(crate) use enums::impl_enum;
#[cfg(feature = "functions")]
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_reflect/derive/src/impls/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ pub(crate) fn impl_opaque(meta: &ReflectMeta) -> proc_macro2::TokenStream {
#[cfg(feature = "functions")]
let function_impls = crate::impls::impl_function_traits(meta, &where_clause_options);

#[cfg(not(feature = "auto_register"))]
let auto_register = None::<proc_macro2::TokenStream>;
#[cfg(feature = "auto_register")]
let auto_register = crate::impls::reflect_auto_registration(meta);

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);
let get_type_registration_impl = meta.get_type_registration(&where_clause_options);
Expand All @@ -70,6 +75,8 @@ pub(crate) fn impl_opaque(meta: &ReflectMeta) -> proc_macro2::TokenStream {

#function_impls

#auto_register

impl #impl_generics #bevy_reflect_path::PartialReflect for #type_path #ty_generics #where_reflect_clause {
#[inline]
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_reflect/derive/src/impls/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
.generics()
.split_for_impl();

#[cfg(not(feature = "auto_register"))]
let auto_register = None::<proc_macro2::TokenStream>;
#[cfg(feature = "auto_register")]
let auto_register = crate::impls::reflect_auto_registration(reflect_struct.meta());

let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);

quote! {
Expand All @@ -75,6 +80,8 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS

#function_impls

#auto_register

impl #impl_generics #bevy_reflect_path::Struct for #struct_path #ty_generics #where_reflect_clause {
fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match name {
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_reflect/derive/src/impls/tuple_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
.generics()
.split_for_impl();

#[cfg(not(feature = "auto_register"))]
let auto_register = None::<proc_macro2::TokenStream>;
#[cfg(feature = "auto_register")]
let auto_register = crate::impls::reflect_auto_registration(reflect_struct.meta());

let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);

quote! {
Expand All @@ -63,6 +68,8 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::

#function_impls

#auto_register

impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_path #ty_generics #where_reflect_clause {
fn field(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match index {
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_reflect/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@ fn match_reflect_impls(ast: DeriveInput, source: ReflectImplSource) -> TokenStre
/// #[reflect(@Required, @EditorTooltip::new("An ID is required!"))]
/// struct Id(u8);
/// ```
/// ## `#[reflect(no_auto_register)]`
///
/// This attribute will opt-out of the automatic reflect type registration.
///
/// All non-generic types annotated with `#[derive(Reflect)]` are usually automatically registered on app startup.
/// If this behavior is not desired, this attribute may be used to disable it for the annotated type.
///
/// # Field Attributes
///
Expand Down
Loading