 44e9cd4bfc
			
		
	
	
		44e9cd4bfc
		
	
	
	
	
		
			
			# 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. -->
		
			
				
	
	
		
			63 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			63 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use std::marker::PhantomData;
 | |
| 
 | |
| use bevy_ecs::prelude::*;
 | |
| 
 | |
| fn main() {
 | |
|     // Unit labels are always equal.
 | |
|     assert_eq!(UnitLabel.as_label(), UnitLabel.as_label());
 | |
| 
 | |
|     // Enum labels depend on the variant.
 | |
|     assert_eq!(EnumLabel::One.as_label(), EnumLabel::One.as_label());
 | |
|     assert_ne!(EnumLabel::One.as_label(), EnumLabel::Two.as_label());
 | |
| 
 | |
|     // Labels annotated with `ignore_fields` ignore their fields.
 | |
|     assert_eq!(WeirdLabel(1).as_label(), WeirdLabel(2).as_label());
 | |
| 
 | |
|     // Labels don't depend only on the variant name but on the full type
 | |
|     assert_ne!(
 | |
|         GenericLabel::<f64>::One.as_label(),
 | |
|         GenericLabel::<char>::One.as_label(),
 | |
|     );
 | |
| }
 | |
| 
 | |
| #[derive(SystemLabel)]
 | |
| pub struct UnitLabel;
 | |
| 
 | |
| #[derive(SystemLabel)]
 | |
| pub enum EnumLabel {
 | |
|     One,
 | |
|     Two,
 | |
| }
 | |
| 
 | |
| #[derive(SystemLabel)]
 | |
| #[system_label(ignore_fields)]
 | |
| pub struct WeirdLabel(i32);
 | |
| 
 | |
| #[derive(SystemLabel)]
 | |
| pub enum GenericLabel<T> {
 | |
|     One,
 | |
|     #[system_label(ignore_fields)]
 | |
|     Two(PhantomData<T>),
 | |
| }
 | |
| 
 | |
| // FIXME: this should be a compile_fail test
 | |
| /*#[derive(SystemLabel)]
 | |
| pub union Foo {
 | |
|     x: i32,
 | |
| }*/
 | |
| 
 | |
| // FIXME: this should be a compile_fail test
 | |
| /*#[derive(SystemLabel)]
 | |
| #[system_label(ignore_fields)]
 | |
| pub enum BadLabel {
 | |
|     One,
 | |
|     Two,
 | |
| }*/
 | |
| 
 | |
| // FIXME: this should be a compile_fail test
 | |
| /*#[derive(SystemLabel)]
 | |
| pub struct BadLabel2 {
 | |
|     #[system_label(ignore_fields)]
 | |
|     x: (),
 | |
| }*/
 |