[Merged by Bors] - Add attribute to ignore fields of derived labels#5366
[Merged by Bors] - Add attribute to ignore fields of derived labels#5366joseph-gio wants to merge 7 commits intobevyengine:mainfrom
Conversation
| #[derive(SystemLabel)] | ||
| pub enum GenericLabel<T> { | ||
| One, | ||
| #[system_label(ignore_fields)] |
There was a problem hiding this comment.
| #[system_label(ignore_fields)] | |
| #[system_label(ignore)] |
Bikeshedding: I think this is marginally clearer, less verbose and more idiomatic.
There was a problem hiding this comment.
To me, that implies that we're ignoring the entire variant, but we're only ignoring the fields.
There was a problem hiding this comment.
Oh I see 🤔 Yeah I think you're right, but we should make sure to make this clear in the docs.
Weird to think that you could set your enum label to the phantomdata variant...
alice-i-cecile
left a comment
There was a problem hiding this comment.
Some nits, but I'm on board with this solution and the underlying code implementation looks correct.
|
Adding to the 0.8 milestone; I think it's important that we have a migration path here. |
|
@IceSentry this plus #4957 will have to be added to the migration guide. |
|
|
||
| fn main() { | ||
| // Unit labels are always equal. | ||
| assert_eq!(UnitLabel.as_label(), UnitLabel.as_label()); |
There was a problem hiding this comment.
These tests are critical, but won't be run in CI. I actually think that these should be moved to doc tests on SystemLabel.
There was a problem hiding this comment.
I agree, but we can't actually add doctests to label types until #5367
Co-authored-by: François <mockersf@gmail.com>
779b608 to
dc56e1d
Compare
cart
left a comment
There was a problem hiding this comment.
All of this additional complexity around ensuring labels don't have values makes me want to revisit #4957. All of this weirdness could be avoided if we just let labels have normal values, be normal structs, and use the derived Hash/PartialEq impls. I think that would be easier to document / understand for users.
Likewise, the benchmarks used to justify #4957 don't account for enums / longer names in the comparison, which I suspect might paint that impl in a worse light. Given the runtime cost scales with the struct name length, we should be benching real world names / enum lengths like VisibilitySystems::UpdateOrthographicFrusta, not the unit struct DummyLabel. And ideally we benchmark more complicated schedules with multiple labels. I'm a bit wary of things being optimized out when code only contains instance of a thing (ex: hashes, comparisons, collections, etc).
Too late to rethink for 0.8 (and i think we should merge this to make migrations smoother), but I think the @bevyengine/ecs-team should give this one last pass for 0.9 to do a final weighing of the pros and cons.
I'm not fully convinced one way or the other (and i do really like the elimination of boxing + removing the need for some trait impls in the api), but this doesn't feel clear cut to me yet.
|
bors r+ |
# Objective Fixes #5362 ## Solution Add the attribute `#[label(ignore_fields)]` for `*Label` types. ```rust #[derive(SystemLabel)] pub enum MyLabel { One, // Previously this was not allowed since labels cannot contain data. #[system_label(ignore_fields)] Two(PhantomData<usize>), } ``` ## Notes This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example: ```rust #[derive(SystemLabel, PartialEq, Eq)] #[system_label(ignore_fields)] pub struct Foo(usize); ``` If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a `Foo`, the derive will incorrectly compare the inner fields. I see a few solutions 1. Do nothing. This is technically intended behavior, but I think we should do our best to prevent footguns. 2. Generate impls of `PartialEq` and `Eq` along with the `#[derive(Label)]` macros. This is a breaking change as it requires all users to remove these derives from their types. 3. Only allow `PhantomData` to be used with `ignore_fields` -- seems needlessly prescriptive. --- ## Changelog * Added the `ignore_fields` attribute to the derive macros for `*Label` types. * Added an example showing off different forms of the derive macro. <!-- ## Migration Guide > This section is optional. If there are no breaking changes, you can delete this section. - If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes - Simply adding new functionality is not a breaking change. - Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change. -->
|
Pull request successfully merged into main. Build succeeded: |
Note that on this branch I've optimized comparisons by storing a "key" (u64) along with the |
|
Ooh that would definitely close the gap / increase my comfort. I think thats worth pursuing. |
|
I agree; I like the new PR quite a bit and it alleviates some of my worries. And, obviously, I think that #4341 is a good idea (especially with the autolabelling). |
# Objective I noticed while working on #5366 that the documentation for label types wasn't working correctly. Having experimented with this for a few weeks, I believe that generating docs in macros is more effort than it's worth. ## Solution Add more boilerplate, copy-paste and edit the docs across types. This also lets us add custom doctests for specific types. Also, we don't need `concat_idents` as a dependency anymore.
# Objective Fixes bevyengine#5362 ## Solution Add the attribute `#[label(ignore_fields)]` for `*Label` types. ```rust #[derive(SystemLabel)] pub enum MyLabel { One, // Previously this was not allowed since labels cannot contain data. #[system_label(ignore_fields)] Two(PhantomData<usize>), } ``` ## Notes This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example: ```rust #[derive(SystemLabel, PartialEq, Eq)] #[system_label(ignore_fields)] pub struct Foo(usize); ``` If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a `Foo`, the derive will incorrectly compare the inner fields. I see a few solutions 1. Do nothing. This is technically intended behavior, but I think we should do our best to prevent footguns. 2. Generate impls of `PartialEq` and `Eq` along with the `#[derive(Label)]` macros. This is a breaking change as it requires all users to remove these derives from their types. 3. Only allow `PhantomData` to be used with `ignore_fields` -- seems needlessly prescriptive. --- ## Changelog * Added the `ignore_fields` attribute to the derive macros for `*Label` types. * Added an example showing off different forms of the derive macro. <!-- ## Migration Guide > This section is optional. If there are no breaking changes, you can delete this section. - If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes - Simply adding new functionality is not a breaking change. - Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change. -->
# Objective I noticed while working on bevyengine#5366 that the documentation for label types wasn't working correctly. Having experimented with this for a few weeks, I believe that generating docs in macros is more effort than it's worth. ## Solution Add more boilerplate, copy-paste and edit the docs across types. This also lets us add custom doctests for specific types. Also, we don't need `concat_idents` as a dependency anymore.
# Objective Fixes bevyengine#5362 ## Solution Add the attribute `#[label(ignore_fields)]` for `*Label` types. ```rust #[derive(SystemLabel)] pub enum MyLabel { One, // Previously this was not allowed since labels cannot contain data. #[system_label(ignore_fields)] Two(PhantomData<usize>), } ``` ## Notes This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example: ```rust #[derive(SystemLabel, PartialEq, Eq)] #[system_label(ignore_fields)] pub struct Foo(usize); ``` If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a `Foo`, the derive will incorrectly compare the inner fields. I see a few solutions 1. Do nothing. This is technically intended behavior, but I think we should do our best to prevent footguns. 2. Generate impls of `PartialEq` and `Eq` along with the `#[derive(Label)]` macros. This is a breaking change as it requires all users to remove these derives from their types. 3. Only allow `PhantomData` to be used with `ignore_fields` -- seems needlessly prescriptive. --- ## Changelog * Added the `ignore_fields` attribute to the derive macros for `*Label` types. * Added an example showing off different forms of the derive macro. <!-- ## Migration Guide > This section is optional. If there are no breaking changes, you can delete this section. - If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes - Simply adding new functionality is not a breaking change. - Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change. -->
# Objective I noticed while working on bevyengine#5366 that the documentation for label types wasn't working correctly. Having experimented with this for a few weeks, I believe that generating docs in macros is more effort than it's worth. ## Solution Add more boilerplate, copy-paste and edit the docs across types. This also lets us add custom doctests for specific types. Also, we don't need `concat_idents` as a dependency anymore.
# Objective Fixes bevyengine#5362 ## Solution Add the attribute `#[label(ignore_fields)]` for `*Label` types. ```rust #[derive(SystemLabel)] pub enum MyLabel { One, // Previously this was not allowed since labels cannot contain data. #[system_label(ignore_fields)] Two(PhantomData<usize>), } ``` ## Notes This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example: ```rust #[derive(SystemLabel, PartialEq, Eq)] #[system_label(ignore_fields)] pub struct Foo(usize); ``` If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a `Foo`, the derive will incorrectly compare the inner fields. I see a few solutions 1. Do nothing. This is technically intended behavior, but I think we should do our best to prevent footguns. 2. Generate impls of `PartialEq` and `Eq` along with the `#[derive(Label)]` macros. This is a breaking change as it requires all users to remove these derives from their types. 3. Only allow `PhantomData` to be used with `ignore_fields` -- seems needlessly prescriptive. --- ## Changelog * Added the `ignore_fields` attribute to the derive macros for `*Label` types. * Added an example showing off different forms of the derive macro. <!-- ## Migration Guide > This section is optional. If there are no breaking changes, you can delete this section. - If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes - Simply adding new functionality is not a breaking change. - Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change. -->
# Objective I noticed while working on bevyengine#5366 that the documentation for label types wasn't working correctly. Having experimented with this for a few weeks, I believe that generating docs in macros is more effort than it's worth. ## Solution Add more boilerplate, copy-paste and edit the docs across types. This also lets us add custom doctests for specific types. Also, we don't need `concat_idents` as a dependency anymore.
Objective
Fixes #5362
Solution
Add the attribute
#[label(ignore_fields)]for*Labeltypes.Notes
This label makes it possible for equality to behave differently depending on whether or not you are treating the type as a label. For example:
If you compare it as a label, it will ignore the wrapped fields as the user requested. But if you compare it as a
Foo, the derive will incorrectly compare the inner fields. I see a few solutionsPartialEqandEqalong with the#[derive(Label)]macros. This is a breaking change as it requires all users to remove these derives from their types.PhantomDatato be used withignore_fields-- seems needlessly prescriptive.Changelog
ignore_fieldsattribute to the derive macros for*Labeltypes.