bevy/crates/bevy_reflect/derive/src/registration.rs

64 lines
2.5 KiB
Rust
Raw Normal View History

bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
//! Contains code related specifically to Bevy's type registration.
use crate::{
derive_data::ReflectMeta, serialization::SerializationDataDef,
where_clause_options::WhereClauseOptions,
};
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
use quote::quote;
bevy_reflect: Recursive registration (#5781) # Objective Resolves #4154 Currently, registration must all be done manually: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app .register_type::<Foo>() .register_type::<Bar>() .register_type::<Baz>() // .register_type::<usize>() <- This one is handled by Bevy, thankfully // ... } ``` This can grow really quickly and become very annoying to add, remove, and update as types change. It would be great if we could help reduce the number of types that a user must manually implement themselves. ## Solution As suggested in #4154, this PR adds automatic recursive registration. Essentially, when a type is registered, it may now also choose to register additional types along with it using the new `GetTypeRegistration::register_type_dependencies` trait method. The `Reflect` derive macro now automatically does this for all fields in structs, tuple structs, struct variants, and tuple variants. This is also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>`. This allows us to simplify the code above like: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app.register_type::<Foo>() // ... } ``` This automatic registration only occurs if the type has not yet been registered. If it has been registered, we simply skip it and move to the next one. This reduces the cost of registration and prevents overwriting customized registrations. ## Considerations While this does improve ergonomics on one front, it's important to look at some of the arguments against adopting a PR like this. #### Generic Bounds ~~Since we need to be able to register the fields individually, we need those fields to implement `GetTypeRegistration`. This forces users to then add this trait as a bound on their generic arguments. This annoyance could be relieved with something like #5772.~~ This is no longer a major issue as the `Reflect` derive now adds the `GetTypeRegistration` bound by default. This should technically be okay, since we already add the `Reflect` bound. However, this can also be considered a breaking change for manual implementations that left out a `GetTypeRegistration` impl ~~or for items that contain dynamic types (e.g. `DynamicStruct`) since those also do not implement `GetTypeRegistration`~~. #### Registration Assumptions By automatically registering fields, users might inadvertently be relying on certain types to be automatically registered. If `Foo` auto-registers `Bar`, but `Foo` is later removed from the code, then anywhere that previously used or relied on `Bar`'s registration would now fail. --- ## Changelog - Added recursive type registration to structs, tuple structs, struct variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>` - Added a new trait in the hidden `bevy_reflect::__macro_exports` module called `RegisterForReflection` - Added `GetTypeRegistration` impl for `bevy_render::render_asset::RenderAssetUsages` ## Migration Guide All types that derive `Reflect` will now automatically add `GetTypeRegistration` as a bound on all (unignored) fields. This means that all reflected fields will need to also implement `GetTypeRegistration`. If all fields **derive** `Reflect` or are implemented in `bevy_reflect`, this should not cause any issues. However, manual implementations of `Reflect` that excluded a `GetTypeRegistration` impl for their type will need to add one. ```rust #[derive(Reflect)] struct Foo<T: FromReflect> { data: MyCustomType<T> } // OLD impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */} // NEW impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */} impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */} ``` --------- Co-authored-by: James Liu <contact@jamessliu.com> Co-authored-by: radiish <cb.setho@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
use syn::Type;
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
/// Creates the `GetTypeRegistration` impl for the given type data.
bevy_reflect: Recursive registration (#5781) # Objective Resolves #4154 Currently, registration must all be done manually: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app .register_type::<Foo>() .register_type::<Bar>() .register_type::<Baz>() // .register_type::<usize>() <- This one is handled by Bevy, thankfully // ... } ``` This can grow really quickly and become very annoying to add, remove, and update as types change. It would be great if we could help reduce the number of types that a user must manually implement themselves. ## Solution As suggested in #4154, this PR adds automatic recursive registration. Essentially, when a type is registered, it may now also choose to register additional types along with it using the new `GetTypeRegistration::register_type_dependencies` trait method. The `Reflect` derive macro now automatically does this for all fields in structs, tuple structs, struct variants, and tuple variants. This is also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>`. This allows us to simplify the code above like: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app.register_type::<Foo>() // ... } ``` This automatic registration only occurs if the type has not yet been registered. If it has been registered, we simply skip it and move to the next one. This reduces the cost of registration and prevents overwriting customized registrations. ## Considerations While this does improve ergonomics on one front, it's important to look at some of the arguments against adopting a PR like this. #### Generic Bounds ~~Since we need to be able to register the fields individually, we need those fields to implement `GetTypeRegistration`. This forces users to then add this trait as a bound on their generic arguments. This annoyance could be relieved with something like #5772.~~ This is no longer a major issue as the `Reflect` derive now adds the `GetTypeRegistration` bound by default. This should technically be okay, since we already add the `Reflect` bound. However, this can also be considered a breaking change for manual implementations that left out a `GetTypeRegistration` impl ~~or for items that contain dynamic types (e.g. `DynamicStruct`) since those also do not implement `GetTypeRegistration`~~. #### Registration Assumptions By automatically registering fields, users might inadvertently be relying on certain types to be automatically registered. If `Foo` auto-registers `Bar`, but `Foo` is later removed from the code, then anywhere that previously used or relied on `Bar`'s registration would now fail. --- ## Changelog - Added recursive type registration to structs, tuple structs, struct variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>` - Added a new trait in the hidden `bevy_reflect::__macro_exports` module called `RegisterForReflection` - Added `GetTypeRegistration` impl for `bevy_render::render_asset::RenderAssetUsages` ## Migration Guide All types that derive `Reflect` will now automatically add `GetTypeRegistration` as a bound on all (unignored) fields. This means that all reflected fields will need to also implement `GetTypeRegistration`. If all fields **derive** `Reflect` or are implemented in `bevy_reflect`, this should not cause any issues. However, manual implementations of `Reflect` that excluded a `GetTypeRegistration` impl for their type will need to add one. ```rust #[derive(Reflect)] struct Foo<T: FromReflect> { data: MyCustomType<T> } // OLD impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */} // NEW impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */} impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */} ``` --------- Co-authored-by: James Liu <contact@jamessliu.com> Co-authored-by: radiish <cb.setho@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
pub(crate) fn impl_get_type_registration<'a>(
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
meta: &ReflectMeta,
Enable deriving Reflect on structs with generic types (#7364) # Objective I recently had an issue, where I have a struct: ``` struct Property { inner: T } ``` that I use as a wrapper for internal purposes. I don't want to update my struct definition to ``` struct Property<T: Reflect>{ inner: T } ``` because I still want to be able to build `Property<T>` for types `T` that are not `Reflect`. (and also because I don't want to update my whole code base with `<T: Reflect>` bounds) I still wanted to have reflection on it (for `bevy_inspector_egui`), but adding `derive(Reflect)` fails with the error: `T cannot be sent between threads safely. T needs to implement Sync.` I believe that `bevy_reflect` should adopt the model of other derives in the case of generics, which is to add the `Reflect` implementation only if the generics also implement `Reflect`. (That is the behaviour of other macros such as `derive(Clone)` or `derive(Debug)`. It's also the current behavior of `derive(FromReflect)`. Basically doing something like: ``` impl<T> Reflect for Foo<T> where T: Reflect ``` ## Solution - I updated the derive macros for `Structs` and `TupleStructs` to add extra `where` bounds. - Every type that is reflected will need a `T: Reflect` bound - Ignored types will need a `T: 'static + Send + Sync` bound. Here's the reason. For cases like this: ``` #[derive(Reflect)] struct Foo<T, U>{ a: T #[reflect(ignore)] b: U } ``` I had to add the bound `'static + Send + Sync` to ignored generics like `U`. The reason is that we want `Foo<T, U>` to be `Reflect: 'static + Send + Sync`, so `Foo<T, U>` must be able to implement those auto-traits. `Foo<T, U>` will only implement those auto-traits if every generic type implements them, including ignored types. This means that the previously compile-fail case now compiles: ``` #[derive(Reflect)] struct Foo<'a> { #[reflect(ignore)] value: &'a str, } ``` But `Foo<'a>` will only be useable in the cases where `'a: 'static` and panic if we don't have `'a: 'static`, which is what we want (nice bonus from this PR ;) ) --- ## Changelog > This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section. ### Added Possibility to add `derive(Reflect)` to structs and enums that contain generic types, like so: ``` #[derive(Reflect)] struct Foo<T>{ a: T } ``` Reflection will only be available if the generic type T also implements `Reflect`. (previously, this would just return a compiler error)
2023-01-28 00:12:06 +00:00
where_clause_options: &WhereClauseOptions,
bevy_reflect: Fix ignored/skipped field order (#7575) # Objective Fixes #5101 Alternative to #6511 ## Solution Corrected the behavior for ignored fields in `FromReflect`, which was previously using the incorrect field indexes. Similarly, fields marked with `#[reflect(skip_serializing)]` no longer break when using `FromReflect` after deserialization. This was done by modifying `SerializationData` to store a function pointer that can later be used to generate a default instance of the skipped field during deserialization. The function pointer points to a function generated by the derive macro using the behavior designated by `#[reflect(default)]` (or just `Default` if none provided). The entire output of the macro is now wrapped in an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) which keeps this behavior hygienic. #### Rationale The biggest downside to this approach is that it requires fields marked `#[reflect(skip_serializing)]` to provide the ability to create a default instance— either via a `Default` impl or by specifying a custom one. While this isn't great, I think it might be justified by the fact that we really need to create this value when using `FromReflect` on a deserialized object. And we need to do this _during_ deserialization because after that (at least for tuples and tuple structs) we lose information about which field is which: _"is the value at index 1 in this `DynamicTupleStruct` the actual value for index 1 or is it really the value for index 2 since index 1 is skippable...?"_ #### Alternatives An alternative would be to store `Option<Box<dyn Reflect>>` within `DynamicTuple` and `DynamicTupleStruct` instead of just `Box<dyn Reflect>`. This would allow us to insert "empty"/"missing" fields during deserialization, thus saving the positional information of the skipped fields. However, this may require changing the API of `Tuple` and `TupleStruct` such that they can account for their dynamic counterparts returning `None` for a skipped field. In practice this would probably mean exposing the `Option`-ness of the dynamics onto implementors via methods like `Tuple::drain` or `TupleStruct::field`. Personally, I think requiring `Default` would be better than muddying up the API to account for these special cases. But I'm open to trying out this other approach if the community feels that it's better. --- ## Changelog ### Public Changes #### Fixed - The behaviors of `#[reflect(ignore)]` and `#[reflect(skip_serializing)]` are no longer dependent on field order #### Changed - Fields marked with `#[reflect(skip_serializing)]` now need to either implement `Default` or specify a custom default function using `#[reflect(default = "path::to::some_func")]` - Deserializing a type with fields marked `#[reflect(skip_serializing)]` will now include that field initialized to its specified default value - `SerializationData::new` now takes the new `SkippedField` struct along with the skipped field index - Renamed `SerializationData::is_ignored_field` to `SerializationData::is_field_skipped` #### Added - Added `SkippedField` struct - Added methods `SerializationData::generate_default` and `SerializationData::iter_skipped` ### Internal Changes #### Changed - Replaced `members_to_serialization_denylist` and `BitSet<u32>` with `SerializationDataDef` - The `Reflect` derive is more hygienic as it now outputs within an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) - `StructField::index` has been split up into `StructField::declaration_index` and `StructField::reflection_index` #### Removed - Removed `bitset` dependency ## Migration Guide * Fields marked `#[reflect(skip_serializing)]` now must implement `Default` or specify a custom default function with `#[reflect(default = "path::to::some_func")]` ```rust #[derive(Reflect)] struct MyStruct { #[reflect(skip_serializing)] #[reflect(default = "get_foo_default")] foo: Foo, // <- `Foo` does not impl `Default` so requires a custom function #[reflect(skip_serializing)] bar: Bar, // <- `Bar` impls `Default` } #[derive(Reflect)] struct Foo(i32); #[derive(Reflect, Default)] struct Bar(i32); fn get_foo_default() -> Foo { Foo(123) } ``` * `SerializationData::new` has been changed to expect an iterator of `(usize, SkippedField)` rather than one of just `usize` ```rust // BEFORE SerializationData::new([0, 3].into_iter()); // AFTER SerializationData::new([ (0, SkippedField::new(field_0_default_fn)), (3, SkippedField::new(field_3_default_fn)), ].into_iter()); ``` * `Serialization::is_ignored_field` has been renamed to `Serialization::is_field_skipped` * Fields marked `#[reflect(skip_serializing)]` are now included in deserialization output. This may affect logic that expected those fields to be absent.
2023-10-22 12:43:31 +00:00
serialization_data: Option<&SerializationDataDef>,
bevy_reflect: Recursive registration (#5781) # Objective Resolves #4154 Currently, registration must all be done manually: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app .register_type::<Foo>() .register_type::<Bar>() .register_type::<Baz>() // .register_type::<usize>() <- This one is handled by Bevy, thankfully // ... } ``` This can grow really quickly and become very annoying to add, remove, and update as types change. It would be great if we could help reduce the number of types that a user must manually implement themselves. ## Solution As suggested in #4154, this PR adds automatic recursive registration. Essentially, when a type is registered, it may now also choose to register additional types along with it using the new `GetTypeRegistration::register_type_dependencies` trait method. The `Reflect` derive macro now automatically does this for all fields in structs, tuple structs, struct variants, and tuple variants. This is also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>`. This allows us to simplify the code above like: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app.register_type::<Foo>() // ... } ``` This automatic registration only occurs if the type has not yet been registered. If it has been registered, we simply skip it and move to the next one. This reduces the cost of registration and prevents overwriting customized registrations. ## Considerations While this does improve ergonomics on one front, it's important to look at some of the arguments against adopting a PR like this. #### Generic Bounds ~~Since we need to be able to register the fields individually, we need those fields to implement `GetTypeRegistration`. This forces users to then add this trait as a bound on their generic arguments. This annoyance could be relieved with something like #5772.~~ This is no longer a major issue as the `Reflect` derive now adds the `GetTypeRegistration` bound by default. This should technically be okay, since we already add the `Reflect` bound. However, this can also be considered a breaking change for manual implementations that left out a `GetTypeRegistration` impl ~~or for items that contain dynamic types (e.g. `DynamicStruct`) since those also do not implement `GetTypeRegistration`~~. #### Registration Assumptions By automatically registering fields, users might inadvertently be relying on certain types to be automatically registered. If `Foo` auto-registers `Bar`, but `Foo` is later removed from the code, then anywhere that previously used or relied on `Bar`'s registration would now fail. --- ## Changelog - Added recursive type registration to structs, tuple structs, struct variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>` - Added a new trait in the hidden `bevy_reflect::__macro_exports` module called `RegisterForReflection` - Added `GetTypeRegistration` impl for `bevy_render::render_asset::RenderAssetUsages` ## Migration Guide All types that derive `Reflect` will now automatically add `GetTypeRegistration` as a bound on all (unignored) fields. This means that all reflected fields will need to also implement `GetTypeRegistration`. If all fields **derive** `Reflect` or are implemented in `bevy_reflect`, this should not cause any issues. However, manual implementations of `Reflect` that excluded a `GetTypeRegistration` impl for their type will need to add one. ```rust #[derive(Reflect)] struct Foo<T: FromReflect> { data: MyCustomType<T> } // OLD impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */} // NEW impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */} impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */} ``` --------- Co-authored-by: James Liu <contact@jamessliu.com> Co-authored-by: radiish <cb.setho@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
type_dependencies: Option<impl Iterator<Item = &'a Type>>,
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
) -> proc_macro2::TokenStream {
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path();
bevy_reflect_derive: Clean up attribute logic (#11777) # Objective The code in `bevy_reflect_derive` could use some cleanup. ## Solution Took some of the changes in #11659 to create a dedicated PR for cleaning up the field and container attribute logic. #### Updated Naming I renamed `ReflectTraits` and `ReflectFieldAttr` to `ContainerAttributes` and `FieldAttributes`, respectively. I think these are clearer. #### Updated Parsing ##### Readability The parsing logic wasn't too bad before, but it was getting difficult to read. There was some duplicated logic between `Meta::List` and `Meta::Path` attributes. Additionally, all the logic was kept inside a large method. To simply things, I replaced the nested meta parsing with `ParseStream` parsing. In my opinion, this is easier to follow since it breaks up the large match statement into a small set of single-line if statements, where each if-block contains a single call to the appropriate attribute parsing method. ##### Flexibility On top of the added simplicity, this also makes our attribute parsing much more flexible. It allows us to more elegantly handle custom where clauses (i.e. `#[reflect(where T: Foo)]`) and it opens the door for more non-standard attribute syntax (e.g. #11659). ##### Errors This also allows us to automatically provide certain errors when parsing. For example, since we can use `stream.lookahead1()`, we get errors like the following for free: ``` error: expected one of: `ignore`, `skip_serializing`, `default` --> crates/bevy_reflect/src/lib.rs:1988:23 | 1988 | #[reflect(foo)] | ^^^ ``` --- ## Changelog > [!note] > All changes are internal to `bevy_reflect_derive` and should not affect the public API[^1]. - Renamed `ReflectTraits` to `ContainerAttributes` - Renamed `ReflectMeta::traits` to `ReflectMeta::attrs` - Renamed `ReflectFieldAttr` to `FieldAttributes` - Updated parsing logic for field/container attribute parsing - Now uses a `ParseStream` directly instead of nested meta parsing - General code cleanup of the field/container attribute modules for `bevy_reflect_derive` [^1]: Does not include errors, which may look slightly different. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-12 15:16:27 +00:00
let registration_data = meta.attrs().idents();
bevy_reflect: Recursive registration (#5781) # Objective Resolves #4154 Currently, registration must all be done manually: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app .register_type::<Foo>() .register_type::<Bar>() .register_type::<Baz>() // .register_type::<usize>() <- This one is handled by Bevy, thankfully // ... } ``` This can grow really quickly and become very annoying to add, remove, and update as types change. It would be great if we could help reduce the number of types that a user must manually implement themselves. ## Solution As suggested in #4154, this PR adds automatic recursive registration. Essentially, when a type is registered, it may now also choose to register additional types along with it using the new `GetTypeRegistration::register_type_dependencies` trait method. The `Reflect` derive macro now automatically does this for all fields in structs, tuple structs, struct variants, and tuple variants. This is also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>`. This allows us to simplify the code above like: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app.register_type::<Foo>() // ... } ``` This automatic registration only occurs if the type has not yet been registered. If it has been registered, we simply skip it and move to the next one. This reduces the cost of registration and prevents overwriting customized registrations. ## Considerations While this does improve ergonomics on one front, it's important to look at some of the arguments against adopting a PR like this. #### Generic Bounds ~~Since we need to be able to register the fields individually, we need those fields to implement `GetTypeRegistration`. This forces users to then add this trait as a bound on their generic arguments. This annoyance could be relieved with something like #5772.~~ This is no longer a major issue as the `Reflect` derive now adds the `GetTypeRegistration` bound by default. This should technically be okay, since we already add the `Reflect` bound. However, this can also be considered a breaking change for manual implementations that left out a `GetTypeRegistration` impl ~~or for items that contain dynamic types (e.g. `DynamicStruct`) since those also do not implement `GetTypeRegistration`~~. #### Registration Assumptions By automatically registering fields, users might inadvertently be relying on certain types to be automatically registered. If `Foo` auto-registers `Bar`, but `Foo` is later removed from the code, then anywhere that previously used or relied on `Bar`'s registration would now fail. --- ## Changelog - Added recursive type registration to structs, tuple structs, struct variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>` - Added a new trait in the hidden `bevy_reflect::__macro_exports` module called `RegisterForReflection` - Added `GetTypeRegistration` impl for `bevy_render::render_asset::RenderAssetUsages` ## Migration Guide All types that derive `Reflect` will now automatically add `GetTypeRegistration` as a bound on all (unignored) fields. This means that all reflected fields will need to also implement `GetTypeRegistration`. If all fields **derive** `Reflect` or are implemented in `bevy_reflect`, this should not cause any issues. However, manual implementations of `Reflect` that excluded a `GetTypeRegistration` impl for their type will need to add one. ```rust #[derive(Reflect)] struct Foo<T: FromReflect> { data: MyCustomType<T> } // OLD impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */} // NEW impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */} impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */} ``` --------- Co-authored-by: James Liu <contact@jamessliu.com> Co-authored-by: radiish <cb.setho@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
let type_deps_fn = type_dependencies.map(|deps| {
quote! {
#[inline(never)]
fn register_type_dependencies(registry: &mut #bevy_reflect_path::TypeRegistry) {
#(<#deps as #bevy_reflect_path::__macro_exports::RegisterForReflection>::__register(registry);)*
}
}
});
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
bevy_reflect: Type parameter bounds (#9046) # Objective Fixes #8965. #### Background For convenience and to ensure everything is setup properly, we automatically add certain bounds to the derived types. The current implementation does this by taking the types from all active fields and adding them to the where-clause of the generated impls. I believe this method was chosen because it won't add bounds to types that are otherwise ignored. ```rust #[derive(Reflect)] struct Foo<T, U: SomeTrait, V> { t: T, u: U::Assoc, #[reflect(ignore)] v: [V; 2] } // Generates something like: impl<T, U: SomeTrait, V> for Foo<T, U, V> where // Active: T: Reflect, U::Assoc: Reflect, // Ignored: [V; 2]: Send + Sync + Any { // ... } ``` The self-referential type fails because it ends up using _itself_ as a type bound due to being one of its own active fields. ```rust #[derive(Reflect)] struct Foo { foo: Vec<Foo> } // Foo where Vec<Foo>: Reflect -> Vec<T> where T: Reflect -> Foo where Vec<Foo>: Reflect -> ... ``` ## Solution We can't simply parse all field types for the name of our type. That would be both complex and prone to errors and false-positives. And even if it wasn't, what would we replace the bound with? Instead, I opted to go for a solution that only adds the bounds to what really needs it: the type parameters. While the bounds on concrete types make errors a bit cleaner, they aren't strictly necessary. This means we can change our generated where-clause to only add bounds to generic type parameters. Doing this, though, returns us back to the problem of over-bounding parameters that don't need to be bounded. To solve this, I added a new container attribute (based on [this](https://github.com/dtolnay/syn/issues/422#issuecomment-406882925) comment and @nicopap's [comment](https://github.com/bevyengine/bevy/pull/9046#issuecomment-1623593780)) that allows us to pass in a custom where clause to modify what bounds are added to these type parameters. This allows us to do stuff like: ```rust trait Trait { type Assoc; } // We don't need `T` to be reflectable since we only care about `T::Assoc`. #[derive(Reflect)] #[reflect(where T::Assoc: FromReflect)] struct Foo<T: Trait>(T::Assoc); #[derive(TypePath)] struct Bar; impl Trait for Bar { type Assoc = usize; } #[derive(Reflect)] struct Baz { a: Foo<Bar>, } ``` > **Note** > I also [tried](https://github.com/bevyengine/bevy/commit/dc139ea34c4737da3ea7ab7ea2e8701462693d02) allowing `#[reflect(ignore)]` to be used on the type parameters themselves, but that proved problematic since the derive macro does not consume the attribute. This is why I went with the container attribute approach. ### Alternatives One alternative could possibly be to just not add reflection bounds automatically (i.e. only add required bounds like `Send`, `Sync`, `Any`, and `TypePath`). The downside here is we add more friction to using reflection, which already comes with its own set of considerations. This is a potentially viable option, but we really need to consider whether or not the ergonomics hit is worth it. If we did decide to go the more manual route, we should at least consider something like #5772 to make it easier for users to add the right bounds (although, this could still become tricky with `FromReflect` also being automatically derived). ### Open Questions 1. Should we go with this approach or the manual alternative? 2. ~~Should we add a `skip_params` attribute to avoid the `T: 'static` trick?~~ ~~Decided to go with `custom_where()` as it's the simplest~~ Scratch that, went with a normal where clause 3. ~~`custom_where` bikeshedding?~~ No longer needed since we are using a normal where clause ### TODO - [x] Add compile-fail tests --- ## Changelog - Fixed issue preventing recursive types from deriving `Reflect` - Changed how where-clause bounds are generated by the `Reflect` derive macro - They are now only applied to the type parameters, not to all active fields - Added `#[reflect(where T: Trait, U::Assoc: Trait, ...)]` container attribute ## Migration Guide When deriving `Reflect`, generic type params that do not need the automatic reflection bounds (such as `Reflect`) applied to them will need to opt-out using a custom where clause like: `#[reflect(where T: Trait, U::Assoc: Trait, ...)]`. The attribute can define custom bounds only used by the reflection impls. To simply opt-out all the type params, we can pass in an empty where clause: `#[reflect(where)]`. ```rust // BEFORE: #[derive(Reflect)] struct Foo<T>(#[reflect(ignore)] T); // AFTER: #[derive(Reflect)] #[reflect(where)] struct Foo<T>(#[reflect(ignore)] T); ``` --------- Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2024-01-28 16:24:03 +00:00
let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056) # Objective **This implementation is based on https://github.com/bevyengine/rfcs/pull/59.** --- Resolves #4597 Full details and motivation can be found in the RFC, but here's a brief summary. `FromReflect` is a very powerful and important trait within the reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to be formed into Real ones (e.g., `Vec<i32>`, etc.). This mainly comes into play concerning deserialization, where the reflection deserializers both return a `Box<dyn Reflect>` that almost always contain one of these Dynamic representations of a Real type. To convert this to our Real type, we need to use `FromReflect`. It also sneaks up in other ways. For example, it's a required bound for `T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`. It's also required by all fields of an enum as it's used as part of the `Reflect::apply` implementation. So in other words, much like `GetTypeRegistration` and `Typed`, it is very much a core reflection trait. The problem is that it is not currently treated like a core trait and is not automatically derived alongside `Reflect`. This makes using it a bit cumbersome and easy to forget. ## Solution Automatically derive `FromReflect` when deriving `Reflect`. Users can then choose to opt-out if needed using the `#[reflect(from_reflect = false)]` attribute. ```rust #[derive(Reflect)] struct Foo; #[derive(Reflect)] #[reflect(from_reflect = false)] struct Bar; fn test<T: FromReflect>(value: T) {} test(Foo); // <-- OK test(Bar); // <-- Panic! Bar does not implement trait `FromReflect` ``` #### `ReflectFromReflect` This PR also automatically adds the `ReflectFromReflect` (introduced in #6245) registration to the derived `GetTypeRegistration` impl— if the type hasn't opted out of `FromReflect` of course. <details> <summary><h4>Improved Deserialization</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. And since we can do all the above, we might as well improve deserialization. We can now choose to deserialize into a Dynamic type or automatically convert it using `FromReflect` under the hood. `[Un]TypedReflectDeserializer::new` will now perform the conversion and return the `Box`'d Real type. `[Un]TypedReflectDeserializer::new_dynamic` will work like what we have now and simply return the `Box`'d Dynamic type. ```rust // Returns the Real type let reflect_deserializer = UntypedReflectDeserializer::new(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // Returns the Dynamic type let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` </details> --- ## Changelog * `FromReflect` is now automatically derived within the `Reflect` derive macro * This includes auto-registering `ReflectFromReflect` in the derived `GetTypeRegistration` impl * ~~Renamed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped** * ~~Changed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to automatically convert the deserialized output using `FromReflect`~~ **Descoped** ## Migration Guide * `FromReflect` is now automatically derived within the `Reflect` derive macro. Items with both derives will need to remove the `FromReflect` one. ```rust // OLD #[derive(Reflect, FromReflect)] struct Foo; // NEW #[derive(Reflect)] struct Foo; ``` If using a manual implementation of `FromReflect` and the `Reflect` derive, users will need to opt-out of the automatic implementation. ```rust // OLD #[derive(Reflect)] struct Foo; impl FromReflect for Foo {/* ... */} // NEW #[derive(Reflect)] #[reflect(from_reflect = false)] struct Foo; impl FromReflect for Foo {/* ... */} ``` <details> <summary><h4>Removed Migrations</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. * The reflect deserializers now perform a `FromReflect` conversion internally. The expected output of `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` is no longer a Dynamic (e.g., `DynamicList`), but its Real counterpart (e.g., `Vec<i32>`). ```rust let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; // OLD let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // NEW let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` Alternatively, if this behavior isn't desired, use the `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic` methods instead: ```rust // OLD let reflect_deserializer = UntypedReflectDeserializer::new(&registry); // NEW let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); ``` </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
let from_reflect_data = if meta.from_reflect().should_auto_derive() {
Some(quote! {
bevy_reflect: Fix ignored/skipped field order (#7575) # Objective Fixes #5101 Alternative to #6511 ## Solution Corrected the behavior for ignored fields in `FromReflect`, which was previously using the incorrect field indexes. Similarly, fields marked with `#[reflect(skip_serializing)]` no longer break when using `FromReflect` after deserialization. This was done by modifying `SerializationData` to store a function pointer that can later be used to generate a default instance of the skipped field during deserialization. The function pointer points to a function generated by the derive macro using the behavior designated by `#[reflect(default)]` (or just `Default` if none provided). The entire output of the macro is now wrapped in an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) which keeps this behavior hygienic. #### Rationale The biggest downside to this approach is that it requires fields marked `#[reflect(skip_serializing)]` to provide the ability to create a default instance— either via a `Default` impl or by specifying a custom one. While this isn't great, I think it might be justified by the fact that we really need to create this value when using `FromReflect` on a deserialized object. And we need to do this _during_ deserialization because after that (at least for tuples and tuple structs) we lose information about which field is which: _"is the value at index 1 in this `DynamicTupleStruct` the actual value for index 1 or is it really the value for index 2 since index 1 is skippable...?"_ #### Alternatives An alternative would be to store `Option<Box<dyn Reflect>>` within `DynamicTuple` and `DynamicTupleStruct` instead of just `Box<dyn Reflect>`. This would allow us to insert "empty"/"missing" fields during deserialization, thus saving the positional information of the skipped fields. However, this may require changing the API of `Tuple` and `TupleStruct` such that they can account for their dynamic counterparts returning `None` for a skipped field. In practice this would probably mean exposing the `Option`-ness of the dynamics onto implementors via methods like `Tuple::drain` or `TupleStruct::field`. Personally, I think requiring `Default` would be better than muddying up the API to account for these special cases. But I'm open to trying out this other approach if the community feels that it's better. --- ## Changelog ### Public Changes #### Fixed - The behaviors of `#[reflect(ignore)]` and `#[reflect(skip_serializing)]` are no longer dependent on field order #### Changed - Fields marked with `#[reflect(skip_serializing)]` now need to either implement `Default` or specify a custom default function using `#[reflect(default = "path::to::some_func")]` - Deserializing a type with fields marked `#[reflect(skip_serializing)]` will now include that field initialized to its specified default value - `SerializationData::new` now takes the new `SkippedField` struct along with the skipped field index - Renamed `SerializationData::is_ignored_field` to `SerializationData::is_field_skipped` #### Added - Added `SkippedField` struct - Added methods `SerializationData::generate_default` and `SerializationData::iter_skipped` ### Internal Changes #### Changed - Replaced `members_to_serialization_denylist` and `BitSet<u32>` with `SerializationDataDef` - The `Reflect` derive is more hygienic as it now outputs within an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) - `StructField::index` has been split up into `StructField::declaration_index` and `StructField::reflection_index` #### Removed - Removed `bitset` dependency ## Migration Guide * Fields marked `#[reflect(skip_serializing)]` now must implement `Default` or specify a custom default function with `#[reflect(default = "path::to::some_func")]` ```rust #[derive(Reflect)] struct MyStruct { #[reflect(skip_serializing)] #[reflect(default = "get_foo_default")] foo: Foo, // <- `Foo` does not impl `Default` so requires a custom function #[reflect(skip_serializing)] bar: Bar, // <- `Bar` impls `Default` } #[derive(Reflect)] struct Foo(i32); #[derive(Reflect, Default)] struct Bar(i32); fn get_foo_default() -> Foo { Foo(123) } ``` * `SerializationData::new` has been changed to expect an iterator of `(usize, SkippedField)` rather than one of just `usize` ```rust // BEFORE SerializationData::new([0, 3].into_iter()); // AFTER SerializationData::new([ (0, SkippedField::new(field_0_default_fn)), (3, SkippedField::new(field_3_default_fn)), ].into_iter()); ``` * `Serialization::is_ignored_field` has been renamed to `Serialization::is_field_skipped` * Fields marked `#[reflect(skip_serializing)]` are now included in deserialization output. This may affect logic that expected those fields to be absent.
2023-10-22 12:43:31 +00:00
registration.insert::<#bevy_reflect_path::ReflectFromReflect>(#bevy_reflect_path::FromType::<Self>::from_type());
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056) # Objective **This implementation is based on https://github.com/bevyengine/rfcs/pull/59.** --- Resolves #4597 Full details and motivation can be found in the RFC, but here's a brief summary. `FromReflect` is a very powerful and important trait within the reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to be formed into Real ones (e.g., `Vec<i32>`, etc.). This mainly comes into play concerning deserialization, where the reflection deserializers both return a `Box<dyn Reflect>` that almost always contain one of these Dynamic representations of a Real type. To convert this to our Real type, we need to use `FromReflect`. It also sneaks up in other ways. For example, it's a required bound for `T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`. It's also required by all fields of an enum as it's used as part of the `Reflect::apply` implementation. So in other words, much like `GetTypeRegistration` and `Typed`, it is very much a core reflection trait. The problem is that it is not currently treated like a core trait and is not automatically derived alongside `Reflect`. This makes using it a bit cumbersome and easy to forget. ## Solution Automatically derive `FromReflect` when deriving `Reflect`. Users can then choose to opt-out if needed using the `#[reflect(from_reflect = false)]` attribute. ```rust #[derive(Reflect)] struct Foo; #[derive(Reflect)] #[reflect(from_reflect = false)] struct Bar; fn test<T: FromReflect>(value: T) {} test(Foo); // <-- OK test(Bar); // <-- Panic! Bar does not implement trait `FromReflect` ``` #### `ReflectFromReflect` This PR also automatically adds the `ReflectFromReflect` (introduced in #6245) registration to the derived `GetTypeRegistration` impl— if the type hasn't opted out of `FromReflect` of course. <details> <summary><h4>Improved Deserialization</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. And since we can do all the above, we might as well improve deserialization. We can now choose to deserialize into a Dynamic type or automatically convert it using `FromReflect` under the hood. `[Un]TypedReflectDeserializer::new` will now perform the conversion and return the `Box`'d Real type. `[Un]TypedReflectDeserializer::new_dynamic` will work like what we have now and simply return the `Box`'d Dynamic type. ```rust // Returns the Real type let reflect_deserializer = UntypedReflectDeserializer::new(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // Returns the Dynamic type let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` </details> --- ## Changelog * `FromReflect` is now automatically derived within the `Reflect` derive macro * This includes auto-registering `ReflectFromReflect` in the derived `GetTypeRegistration` impl * ~~Renamed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped** * ~~Changed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to automatically convert the deserialized output using `FromReflect`~~ **Descoped** ## Migration Guide * `FromReflect` is now automatically derived within the `Reflect` derive macro. Items with both derives will need to remove the `FromReflect` one. ```rust // OLD #[derive(Reflect, FromReflect)] struct Foo; // NEW #[derive(Reflect)] struct Foo; ``` If using a manual implementation of `FromReflect` and the `Reflect` derive, users will need to opt-out of the automatic implementation. ```rust // OLD #[derive(Reflect)] struct Foo; impl FromReflect for Foo {/* ... */} // NEW #[derive(Reflect)] #[reflect(from_reflect = false)] struct Foo; impl FromReflect for Foo {/* ... */} ``` <details> <summary><h4>Removed Migrations</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. * The reflect deserializers now perform a `FromReflect` conversion internally. The expected output of `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` is no longer a Dynamic (e.g., `DynamicList`), but its Real counterpart (e.g., `Vec<i32>`). ```rust let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; // OLD let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // NEW let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` Alternatively, if this behavior isn't desired, use the `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic` methods instead: ```rust // OLD let reflect_deserializer = UntypedReflectDeserializer::new(&registry); // NEW let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); ``` </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
})
} else {
None
};
bevy_reflect: Fix ignored/skipped field order (#7575) # Objective Fixes #5101 Alternative to #6511 ## Solution Corrected the behavior for ignored fields in `FromReflect`, which was previously using the incorrect field indexes. Similarly, fields marked with `#[reflect(skip_serializing)]` no longer break when using `FromReflect` after deserialization. This was done by modifying `SerializationData` to store a function pointer that can later be used to generate a default instance of the skipped field during deserialization. The function pointer points to a function generated by the derive macro using the behavior designated by `#[reflect(default)]` (or just `Default` if none provided). The entire output of the macro is now wrapped in an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) which keeps this behavior hygienic. #### Rationale The biggest downside to this approach is that it requires fields marked `#[reflect(skip_serializing)]` to provide the ability to create a default instance— either via a `Default` impl or by specifying a custom one. While this isn't great, I think it might be justified by the fact that we really need to create this value when using `FromReflect` on a deserialized object. And we need to do this _during_ deserialization because after that (at least for tuples and tuple structs) we lose information about which field is which: _"is the value at index 1 in this `DynamicTupleStruct` the actual value for index 1 or is it really the value for index 2 since index 1 is skippable...?"_ #### Alternatives An alternative would be to store `Option<Box<dyn Reflect>>` within `DynamicTuple` and `DynamicTupleStruct` instead of just `Box<dyn Reflect>`. This would allow us to insert "empty"/"missing" fields during deserialization, thus saving the positional information of the skipped fields. However, this may require changing the API of `Tuple` and `TupleStruct` such that they can account for their dynamic counterparts returning `None` for a skipped field. In practice this would probably mean exposing the `Option`-ness of the dynamics onto implementors via methods like `Tuple::drain` or `TupleStruct::field`. Personally, I think requiring `Default` would be better than muddying up the API to account for these special cases. But I'm open to trying out this other approach if the community feels that it's better. --- ## Changelog ### Public Changes #### Fixed - The behaviors of `#[reflect(ignore)]` and `#[reflect(skip_serializing)]` are no longer dependent on field order #### Changed - Fields marked with `#[reflect(skip_serializing)]` now need to either implement `Default` or specify a custom default function using `#[reflect(default = "path::to::some_func")]` - Deserializing a type with fields marked `#[reflect(skip_serializing)]` will now include that field initialized to its specified default value - `SerializationData::new` now takes the new `SkippedField` struct along with the skipped field index - Renamed `SerializationData::is_ignored_field` to `SerializationData::is_field_skipped` #### Added - Added `SkippedField` struct - Added methods `SerializationData::generate_default` and `SerializationData::iter_skipped` ### Internal Changes #### Changed - Replaced `members_to_serialization_denylist` and `BitSet<u32>` with `SerializationDataDef` - The `Reflect` derive is more hygienic as it now outputs within an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) - `StructField::index` has been split up into `StructField::declaration_index` and `StructField::reflection_index` #### Removed - Removed `bitset` dependency ## Migration Guide * Fields marked `#[reflect(skip_serializing)]` now must implement `Default` or specify a custom default function with `#[reflect(default = "path::to::some_func")]` ```rust #[derive(Reflect)] struct MyStruct { #[reflect(skip_serializing)] #[reflect(default = "get_foo_default")] foo: Foo, // <- `Foo` does not impl `Default` so requires a custom function #[reflect(skip_serializing)] bar: Bar, // <- `Bar` impls `Default` } #[derive(Reflect)] struct Foo(i32); #[derive(Reflect, Default)] struct Bar(i32); fn get_foo_default() -> Foo { Foo(123) } ``` * `SerializationData::new` has been changed to expect an iterator of `(usize, SkippedField)` rather than one of just `usize` ```rust // BEFORE SerializationData::new([0, 3].into_iter()); // AFTER SerializationData::new([ (0, SkippedField::new(field_0_default_fn)), (3, SkippedField::new(field_3_default_fn)), ].into_iter()); ``` * `Serialization::is_ignored_field` has been renamed to `Serialization::is_field_skipped` * Fields marked `#[reflect(skip_serializing)]` are now included in deserialization output. This may affect logic that expected those fields to be absent.
2023-10-22 12:43:31 +00:00
let serialization_data = serialization_data.map(|data| {
let serialization_data = data.as_serialization_data(bevy_reflect_path);
quote! {
bevy_reflect: Fix ignored/skipped field order (#7575) # Objective Fixes #5101 Alternative to #6511 ## Solution Corrected the behavior for ignored fields in `FromReflect`, which was previously using the incorrect field indexes. Similarly, fields marked with `#[reflect(skip_serializing)]` no longer break when using `FromReflect` after deserialization. This was done by modifying `SerializationData` to store a function pointer that can later be used to generate a default instance of the skipped field during deserialization. The function pointer points to a function generated by the derive macro using the behavior designated by `#[reflect(default)]` (or just `Default` if none provided). The entire output of the macro is now wrapped in an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) which keeps this behavior hygienic. #### Rationale The biggest downside to this approach is that it requires fields marked `#[reflect(skip_serializing)]` to provide the ability to create a default instance— either via a `Default` impl or by specifying a custom one. While this isn't great, I think it might be justified by the fact that we really need to create this value when using `FromReflect` on a deserialized object. And we need to do this _during_ deserialization because after that (at least for tuples and tuple structs) we lose information about which field is which: _"is the value at index 1 in this `DynamicTupleStruct` the actual value for index 1 or is it really the value for index 2 since index 1 is skippable...?"_ #### Alternatives An alternative would be to store `Option<Box<dyn Reflect>>` within `DynamicTuple` and `DynamicTupleStruct` instead of just `Box<dyn Reflect>`. This would allow us to insert "empty"/"missing" fields during deserialization, thus saving the positional information of the skipped fields. However, this may require changing the API of `Tuple` and `TupleStruct` such that they can account for their dynamic counterparts returning `None` for a skipped field. In practice this would probably mean exposing the `Option`-ness of the dynamics onto implementors via methods like `Tuple::drain` or `TupleStruct::field`. Personally, I think requiring `Default` would be better than muddying up the API to account for these special cases. But I'm open to trying out this other approach if the community feels that it's better. --- ## Changelog ### Public Changes #### Fixed - The behaviors of `#[reflect(ignore)]` and `#[reflect(skip_serializing)]` are no longer dependent on field order #### Changed - Fields marked with `#[reflect(skip_serializing)]` now need to either implement `Default` or specify a custom default function using `#[reflect(default = "path::to::some_func")]` - Deserializing a type with fields marked `#[reflect(skip_serializing)]` will now include that field initialized to its specified default value - `SerializationData::new` now takes the new `SkippedField` struct along with the skipped field index - Renamed `SerializationData::is_ignored_field` to `SerializationData::is_field_skipped` #### Added - Added `SkippedField` struct - Added methods `SerializationData::generate_default` and `SerializationData::iter_skipped` ### Internal Changes #### Changed - Replaced `members_to_serialization_denylist` and `BitSet<u32>` with `SerializationDataDef` - The `Reflect` derive is more hygienic as it now outputs within an [unnamed constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant) - `StructField::index` has been split up into `StructField::declaration_index` and `StructField::reflection_index` #### Removed - Removed `bitset` dependency ## Migration Guide * Fields marked `#[reflect(skip_serializing)]` now must implement `Default` or specify a custom default function with `#[reflect(default = "path::to::some_func")]` ```rust #[derive(Reflect)] struct MyStruct { #[reflect(skip_serializing)] #[reflect(default = "get_foo_default")] foo: Foo, // <- `Foo` does not impl `Default` so requires a custom function #[reflect(skip_serializing)] bar: Bar, // <- `Bar` impls `Default` } #[derive(Reflect)] struct Foo(i32); #[derive(Reflect, Default)] struct Bar(i32); fn get_foo_default() -> Foo { Foo(123) } ``` * `SerializationData::new` has been changed to expect an iterator of `(usize, SkippedField)` rather than one of just `usize` ```rust // BEFORE SerializationData::new([0, 3].into_iter()); // AFTER SerializationData::new([ (0, SkippedField::new(field_0_default_fn)), (3, SkippedField::new(field_3_default_fn)), ].into_iter()); ``` * `Serialization::is_ignored_field` has been renamed to `Serialization::is_field_skipped` * Fields marked `#[reflect(skip_serializing)]` are now included in deserialization output. This may affect logic that expected those fields to be absent.
2023-10-22 12:43:31 +00:00
registration.insert::<#bevy_reflect_path::serde::SerializationData>(#serialization_data);
}
});
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
quote! {
#[allow(unused_mut)]
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_path #ty_generics #where_reflect_clause {
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
fn get_type_registration() -> #bevy_reflect_path::TypeRegistration {
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
let mut registration = #bevy_reflect_path::TypeRegistration::of::<Self>();
registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<Self>::from_type());
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056) # Objective **This implementation is based on https://github.com/bevyengine/rfcs/pull/59.** --- Resolves #4597 Full details and motivation can be found in the RFC, but here's a brief summary. `FromReflect` is a very powerful and important trait within the reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to be formed into Real ones (e.g., `Vec<i32>`, etc.). This mainly comes into play concerning deserialization, where the reflection deserializers both return a `Box<dyn Reflect>` that almost always contain one of these Dynamic representations of a Real type. To convert this to our Real type, we need to use `FromReflect`. It also sneaks up in other ways. For example, it's a required bound for `T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`. It's also required by all fields of an enum as it's used as part of the `Reflect::apply` implementation. So in other words, much like `GetTypeRegistration` and `Typed`, it is very much a core reflection trait. The problem is that it is not currently treated like a core trait and is not automatically derived alongside `Reflect`. This makes using it a bit cumbersome and easy to forget. ## Solution Automatically derive `FromReflect` when deriving `Reflect`. Users can then choose to opt-out if needed using the `#[reflect(from_reflect = false)]` attribute. ```rust #[derive(Reflect)] struct Foo; #[derive(Reflect)] #[reflect(from_reflect = false)] struct Bar; fn test<T: FromReflect>(value: T) {} test(Foo); // <-- OK test(Bar); // <-- Panic! Bar does not implement trait `FromReflect` ``` #### `ReflectFromReflect` This PR also automatically adds the `ReflectFromReflect` (introduced in #6245) registration to the derived `GetTypeRegistration` impl— if the type hasn't opted out of `FromReflect` of course. <details> <summary><h4>Improved Deserialization</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. And since we can do all the above, we might as well improve deserialization. We can now choose to deserialize into a Dynamic type or automatically convert it using `FromReflect` under the hood. `[Un]TypedReflectDeserializer::new` will now perform the conversion and return the `Box`'d Real type. `[Un]TypedReflectDeserializer::new_dynamic` will work like what we have now and simply return the `Box`'d Dynamic type. ```rust // Returns the Real type let reflect_deserializer = UntypedReflectDeserializer::new(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // Returns the Dynamic type let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` </details> --- ## Changelog * `FromReflect` is now automatically derived within the `Reflect` derive macro * This includes auto-registering `ReflectFromReflect` in the derived `GetTypeRegistration` impl * ~~Renamed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped** * ~~Changed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to automatically convert the deserialized output using `FromReflect`~~ **Descoped** ## Migration Guide * `FromReflect` is now automatically derived within the `Reflect` derive macro. Items with both derives will need to remove the `FromReflect` one. ```rust // OLD #[derive(Reflect, FromReflect)] struct Foo; // NEW #[derive(Reflect)] struct Foo; ``` If using a manual implementation of `FromReflect` and the `Reflect` derive, users will need to opt-out of the automatic implementation. ```rust // OLD #[derive(Reflect)] struct Foo; impl FromReflect for Foo {/* ... */} // NEW #[derive(Reflect)] #[reflect(from_reflect = false)] struct Foo; impl FromReflect for Foo {/* ... */} ``` <details> <summary><h4>Removed Migrations</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. * The reflect deserializers now perform a `FromReflect` conversion internally. The expected output of `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` is no longer a Dynamic (e.g., `DynamicList`), but its Real counterpart (e.g., `Vec<i32>`). ```rust let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; // OLD let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // NEW let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` Alternatively, if this behavior isn't desired, use the `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic` methods instead: ```rust // OLD let reflect_deserializer = UntypedReflectDeserializer::new(&registry); // NEW let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); ``` </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
#from_reflect_data
#serialization_data
reflect: stable type path v2 (#7184) # Objective - Introduce a stable alternative to [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html). - Rewrite of #5805 with heavy inspiration in design. - On the path to #5830. - Part of solving #3327. ## Solution - Add a `TypePath` trait for static stable type path/name information. - Add a `TypePath` derive macro. - Add a `impl_type_path` macro for implementing internal and foreign types in `bevy_reflect`. --- ## Changelog - Added `TypePath` trait. - Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`. - Added a `TypePath` derive macro. - Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on internal and foreign types in `bevy_reflect`. - Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to `(Non)GenericTypedCell<T>` which allows us to be generic over both `TypeInfo` and `TypePath`. - `TypePath` is now a supertrait of `Asset`, `Material` and `Material2d`. - `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be specified. - `impl_reflect_value` needs to either specify path starting with a double colon (`::core::option::Option`) or an `in my_crate::foo` declaration. - Added `bevy_reflect_derive::ReflectTypePath`. - Most uses of `Ident` in `bevy_reflect_derive` changed to use `ReflectTypePath`. ## Migration Guide - Implementors of `Asset`, `Material` and `Material2d` now also need to derive `TypePath`. - Manual implementors of `Reflect` will need to implement the new `get_type_path` method. ## Open Questions - [x] ~This PR currently does not migrate any usages of `std::any::type_name` to use `bevy_reflect::TypePath` to ease the review process. Should it?~ Migration will be left to a follow-up PR. - [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to satisfy new bounds, mostly when deriving `TypeUuid`. Should we make `TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in favour of `TypePath`?](https://github.com/bevyengine/bevy/pull/5805/files/2afbd855327c4b68e0a6b6f03118f289988441a4#r961067892)
2023-06-05 20:31:20 +00:00
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<Self>::from_type());)*
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
registration
}
bevy_reflect: Recursive registration (#5781) # Objective Resolves #4154 Currently, registration must all be done manually: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app .register_type::<Foo>() .register_type::<Bar>() .register_type::<Baz>() // .register_type::<usize>() <- This one is handled by Bevy, thankfully // ... } ``` This can grow really quickly and become very annoying to add, remove, and update as types change. It would be great if we could help reduce the number of types that a user must manually implement themselves. ## Solution As suggested in #4154, this PR adds automatic recursive registration. Essentially, when a type is registered, it may now also choose to register additional types along with it using the new `GetTypeRegistration::register_type_dependencies` trait method. The `Reflect` derive macro now automatically does this for all fields in structs, tuple structs, struct variants, and tuple variants. This is also done for tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>`. This allows us to simplify the code above like: ```rust #[derive(Reflect)] struct Foo(Bar); #[derive(Reflect)] struct Bar(Baz); #[derive(Reflect)] struct Baz(usize); fn main() { // ... app.register_type::<Foo>() // ... } ``` This automatic registration only occurs if the type has not yet been registered. If it has been registered, we simply skip it and move to the next one. This reduces the cost of registration and prevents overwriting customized registrations. ## Considerations While this does improve ergonomics on one front, it's important to look at some of the arguments against adopting a PR like this. #### Generic Bounds ~~Since we need to be able to register the fields individually, we need those fields to implement `GetTypeRegistration`. This forces users to then add this trait as a bound on their generic arguments. This annoyance could be relieved with something like #5772.~~ This is no longer a major issue as the `Reflect` derive now adds the `GetTypeRegistration` bound by default. This should technically be okay, since we already add the `Reflect` bound. However, this can also be considered a breaking change for manual implementations that left out a `GetTypeRegistration` impl ~~or for items that contain dynamic types (e.g. `DynamicStruct`) since those also do not implement `GetTypeRegistration`~~. #### Registration Assumptions By automatically registering fields, users might inadvertently be relying on certain types to be automatically registered. If `Foo` auto-registers `Bar`, but `Foo` is later removed from the code, then anywhere that previously used or relied on `Bar`'s registration would now fail. --- ## Changelog - Added recursive type registration to structs, tuple structs, struct variants, tuple variants, tuples, arrays, `Vec<T>`, `HashMap<K, V>`, and `Option<T>` - Added a new trait in the hidden `bevy_reflect::__macro_exports` module called `RegisterForReflection` - Added `GetTypeRegistration` impl for `bevy_render::render_asset::RenderAssetUsages` ## Migration Guide All types that derive `Reflect` will now automatically add `GetTypeRegistration` as a bound on all (unignored) fields. This means that all reflected fields will need to also implement `GetTypeRegistration`. If all fields **derive** `Reflect` or are implemented in `bevy_reflect`, this should not cause any issues. However, manual implementations of `Reflect` that excluded a `GetTypeRegistration` impl for their type will need to add one. ```rust #[derive(Reflect)] struct Foo<T: FromReflect> { data: MyCustomType<T> } // OLD impl<T: FromReflect> Reflect for MyCustomType<T> {/* ... */} // NEW impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {/* ... */} impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {/* ... */} ``` --------- Co-authored-by: James Liu <contact@jamessliu.com> Co-authored-by: radiish <cb.setho@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-03-04 19:04:10 +00:00
#type_deps_fn
bevy_reflect_derive: Tidying up the code (#4712) # Objective The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work. ## Solution Split `bevy_reflect_derive` into many more submodules. The submodules include: * `container_attributes` - Code relating to container attributes * `derive_data` - Code relating to reflection-based derive metadata * `field_attributes` - Code relating to field attributes * `impls` - Code containing actual reflection implementations * `reflect_value` - Code relating to reflection-based value metadata * `registration` - Code relating to type registration * `utility` - General-purpose utility functions This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines). By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions. ### Metadata Structs This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs. Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute). We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one. ### Out of Scope _Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR. ## 🔍 Focus Points (for reviewers) I know it's a lot to sift through, so here is a list of **key points for reviewers**: - The following files contain code that was mostly just relocated: - `reflect_value.rs` - `registration.rs` - `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments - Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication. - `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention. - Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus. - There was no change to the `lib.rs` exports so the end-user API should be the same. ## Prior Work This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year! --- ## Changelog * **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules * **[INTERNAL]** Add `ReflectFieldAttr` * **[INTERNAL]** Add `ReflectDeriveData` * Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`) Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
}
}
}