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 32 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 @@ -130,6 +130,7 @@ default = [
"hdr",
"multi_threaded",
"png",
"reflect_auto_register",
"smaa_luts",
"sysinfo_plugin",
"tonemapping_luts",
Expand Down Expand Up @@ -454,6 +455,9 @@ track_change_detection = ["bevy_internal/track_change_detection"]
# Enable function reflection
reflect_functions = ["bevy_internal/reflect_functions"]

# 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 @@ -18,6 +18,11 @@ reflect_functions = [
"bevy_reflect/functions",
"bevy_ecs/reflect_functions",
]
reflect_auto_register = [
"bevy_reflect",
"bevy_reflect/auto_register",
"bevy_ecs/reflect_auto_register",
]

[dependencies]
# bevy
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,12 @@ impl Default for App {
let mut app = App::empty();
app.sub_apps.main.update_schedule = Some(Main.intern());

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

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

#[cfg(feature = "reflect_functions")]
app.init_resource::<AppFunctionRegistry>();

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 @@ -18,6 +18,7 @@ bevy_debug_stepping = []
serialize = ["dep:serde"]
track_change_detection = []
reflect_functions = ["bevy_reflect", "bevy_reflect/functions"]
reflect_auto_register = ["bevy_reflect", "bevy_reflect/auto_register"]
detailed_trace = []

[dependencies]
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 @@ -49,6 +49,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 @@ -250,6 +250,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 winit custom cursor support
custom_cursor = ["bevy_winit/custom_cursor"]
Expand Down
13 changes: 13 additions & 0 deletions crates/bevy_reflect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ debug_stack = []
documentation = ["bevy_reflect_derive/documentation"]
# Enables function reflection
functions = ["bevy_reflect_derive/functions"]
# Enables automatic reflect registration
auto_register = [
"bevy_reflect_derive/auto_register",
"dep:inventory",
"dep:wasm-init",
]
alloc = []

[dependencies]
Expand Down Expand Up @@ -53,6 +59,13 @@ smol_str = { version = "0.2.0", features = ["serde"], optional = true }
uuid = { version = "1.0", optional = true, features = ["v4", "serde"] }
wgpu-types = { version = "23", features = ["serde"], optional = true }

# deps for automatic type registration
[target.'cfg(not(target_family = "wasm"))'.dependencies]
inventory = { version = "0.3", optional = true }
[target.'cfg(target_family = "wasm")'.dependencies]
wasm-init = { version = "0.2", optional = true }


[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.15.0-dev" }
Expand Down
21 changes: 21 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 @@ -188,6 +189,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 @@ -242,6 +244,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 @@ -360,6 +364,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 @@ -543,6 +557,13 @@ impl ContainerAttributes {
self.no_field_bounds
}

/// Returns true if the `no_auto_register` attribute was found on this type.
// This is not feature-gated because derive macro shouldn't break if auto_register feature is disabled.
#[allow(dead_code)]
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
25 changes: 25 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,28 @@ pub fn common_partial_reflect_methods(
#debug_fn
}
}

#[cfg(feature = "auto_register")]
pub fn reflect_auto_registration(meta: &ReflectMeta) -> Option<proc_macro2::TokenStream> {
use quote::ToTokens;

if meta.attrs().no_auto_register() {
return None;
}

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

if !generics.into_token_stream().is_empty() {
return None;
};

Some(quote! {
#bevy_reflect_path::__macro_exports::auto_register::auto_register_function!{
#bevy_reflect_path::__macro_exports::auto_register::AutomaticReflectRegistrations::add(
<#type_path as #bevy_reflect_path::__macro_exports::auto_register::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
Loading