bevy/crates
Gino Valente 60773e6787
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
..
bevy_a11y Various accessibility API updates. (#9989) 2023-10-02 21:22:52 +00:00
bevy_animation refactor: Change Option<With<T>> query params to Has<T> (#9959) 2023-10-02 01:21:41 +00:00
bevy_app Prevent black frames during startup (#9826) 2023-10-18 23:24:19 +00:00
bevy_asset Add asset_processor feature and remove AssetMode::ProcessedDev (#10194) 2023-10-20 20:50:26 +00:00
bevy_audio More ergonomic spatial audio (#9800) 2023-10-09 19:43:56 +00:00
bevy_core Change visibility of bevy::core::update_frame_count to pub (#10111) 2023-10-16 13:43:02 +00:00
bevy_core_pipeline Bind group entries (#9694) 2023-10-21 15:39:22 +00:00
bevy_derive bevy_derive: Fix #[deref] breaking other attributes (#9551) 2023-08-28 17:36:18 +00:00
bevy_diagnostic Unify FixedTime and Time while fixing several problems (#8964) 2023-10-16 01:57:55 +00:00
bevy_dylib Bump Version after Release (#9106) 2023-07-10 21:19:27 +00:00
bevy_dynamic_plugin Bump Version after Release (#9106) 2023-07-10 21:19:27 +00:00
bevy_ecs ParamSets containing non-send parameters should also be non-send (#10211) 2023-10-21 18:07:52 +00:00
bevy_ecs_compile_fail_tests Updates for rust 1.73 (#10035) 2023-10-06 00:31:10 +00:00
bevy_encase_derive Bump Version after Release (#9106) 2023-07-10 21:19:27 +00:00
bevy_gilrs Unify FixedTime and Time while fixing several problems (#8964) 2023-10-16 01:57:55 +00:00
bevy_gizmos Bind group entries (#9694) 2023-10-21 15:39:22 +00:00
bevy_gltf Multiple Asset Sources (#9885) 2023-10-13 23:17:32 +00:00
bevy_hierarchy Fix some warnings shown in nightly (#10012) 2023-10-05 05:41:09 +00:00
bevy_input Change AxisSettings livezone default (#10090) 2023-10-12 17:58:32 +00:00
bevy_internal Add asset_processor feature and remove AssetMode::ProcessedDev (#10194) 2023-10-20 20:50:26 +00:00
bevy_log Update tracy-client requirement from 0.15 to 0.16 (#9436) 2023-08-15 07:45:21 +00:00
bevy_macro_utils Update toml_edit requirement from 0.19 to 0.20 (#10058) 2023-10-09 11:55:16 +00:00
bevy_macros_compile_fail_tests bevy_derive: Fix #[deref] breaking other attributes (#9551) 2023-08-28 17:36:18 +00:00
bevy_math Automatic batching/instancing of draw commands (#9685) 2023-09-21 22:12:34 +00:00
bevy_mikktspace add and fix shields in Readmes (#9993) 2023-10-15 00:52:31 +00:00
bevy_pbr Bind group entries (#9694) 2023-10-21 15:39:22 +00:00
bevy_ptr add and fix shields in Readmes (#9993) 2023-10-15 00:52:31 +00:00
bevy_reflect bevy_reflect: Fix ignored/skipped field order (#7575) 2023-10-22 12:43:31 +00:00
bevy_reflect_compile_fail_tests Improve TypeUuid's derive macro error messages (#9315) 2023-10-02 12:42:01 +00:00
bevy_render Add convenient methods for Image (#10221) 2023-10-22 01:45:29 +00:00
bevy_scene Correct Scene loader error description (#10161) 2023-10-17 17:58:35 +00:00
bevy_sprite Add convenient methods for Image (#10221) 2023-10-22 01:45:29 +00:00
bevy_tasks add and fix shields in Readmes (#9993) 2023-10-15 00:52:31 +00:00
bevy_text Fix text2d view-visibility (#10100) 2023-10-13 19:14:31 +00:00
bevy_time add on_real_time_timer run condition (#10179) 2023-10-20 12:58:37 +00:00
bevy_transform Add system parameter for computing up-to-date GlobalTransforms (#8603) 2023-10-18 20:07:51 +00:00
bevy_ui Tidy up UI node docs (#10189) 2023-10-21 17:38:15 +00:00
bevy_utils Bind group entries (#9694) 2023-10-21 15:39:22 +00:00
bevy_window Various accessibility API updates. (#9989) 2023-10-02 21:22:52 +00:00
bevy_winit Prevent black frames during startup (#9826) 2023-10-18 23:24:19 +00:00