Skip to content

Commit 55fd105

Browse files
Required components accept const values (#16720) (#18309)
# Objective Const values should be more ergonomic to insert, since this is too verbose ``` rust #[derive(Component)] #[require( LockedAxes(||LockedAxes::ROTATION_LOCKED), )] pub struct CharacterController; ``` instead, users can now abbreviate that nonsense like this ``` rust #[derive(Component)] #[require( LockedAxes = ROTATION_LOCKED), )] pub struct CharacterController; ``` it also works for enum labels. I chose to omit the type, since were trying to reduce typing here. The alternative would have been this: ```rust #[require( LockedAxes = LockedAxes::ROTATION_LOCKED), )] ``` This of course has its disadvantages, since the const has to be associated, but the old closure method is still possible, so I dont think its a problem. - Fixes #16720 ## Testing I added one new test in the docs, which also explain the new change. I also saw that the docs for the required components on line 165 was missing an assertion, so I added it back in --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
1 parent dac0b10 commit 55fd105

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

crates/bevy_ecs/macros/src/component.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,12 @@ impl Parse for Require {
611611
let func = content.parse::<Path>()?;
612612
Some(RequireFunc::Path(func))
613613
}
614+
} else if input.peek(Token![=]) {
615+
let _t: syn::Token![=] = input.parse()?;
616+
let label: Ident = input.parse()?;
617+
let tokens: TokenStream = quote::quote! (|| #path::#label).into();
618+
let func = syn::parse(tokens).unwrap();
619+
Some(RequireFunc::Closure(func))
614620
} else {
615621
None
616622
};

crates/bevy_ecs/src/component.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,43 @@ use thiserror::Error;
180180
/// }
181181
///
182182
/// # let mut world = World::default();
183+
/// // This will implicitly also insert C with the init_c() constructor
184+
/// let id = world.spawn(A).id();
185+
/// assert_eq!(&C(10), world.entity(id).get::<C>().unwrap());
186+
///
183187
/// // This will implicitly also insert C with the `|| C(20)` constructor closure
184188
/// let id = world.spawn(B).id();
185189
/// assert_eq!(&C(20), world.entity(id).get::<C>().unwrap());
186190
/// ```
187191
///
192+
/// For convenience sake, you can abbreviate enum labels or constant values, with the type inferred to match that of the component you are requiring:
193+
///
194+
/// ```
195+
/// # use bevy_ecs::prelude::*;
196+
/// #[derive(Component)]
197+
/// #[require(B = One, C = ONE)]
198+
/// struct A;
199+
///
200+
/// #[derive(Component, PartialEq, Eq, Debug)]
201+
/// enum B {
202+
/// Zero,
203+
/// One,
204+
/// Two
205+
/// }
206+
///
207+
/// #[derive(Component, PartialEq, Eq, Debug)]
208+
/// struct C(u8);
209+
///
210+
/// impl C {
211+
/// pub const ONE: Self = Self(1);
212+
/// }
213+
///
214+
/// # let mut world = World::default();
215+
/// let id = world.spawn(A).id();
216+
/// assert_eq!(&B::One, world.entity(id).get::<B>().unwrap());
217+
/// assert_eq!(&C(1), world.entity(id).get::<C>().unwrap());
218+
/// ````
219+
///
188220
/// Required components are _recursive_. This means, if a Required Component has required components,
189221
/// those components will _also_ be inserted if they are missing:
190222
///

0 commit comments

Comments
 (0)