From 55fd10502c330f50dcdff70e24bdd13f8f077afa Mon Sep 17 00:00:00 2001 From: Wuketuke <59253838+Wuketuke@users.noreply.github.com> Date: Fri, 21 Mar 2025 00:02:10 +0000 Subject: [PATCH] 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 --- crates/bevy_ecs/macros/src/component.rs | 6 +++++ crates/bevy_ecs/src/component.rs | 32 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index 464e4efabf..3639f0835a 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -611,6 +611,12 @@ impl Parse for Require { let func = content.parse::()?; Some(RequireFunc::Path(func)) } + } else if input.peek(Token![=]) { + let _t: syn::Token![=] = input.parse()?; + let label: Ident = input.parse()?; + let tokens: TokenStream = quote::quote! (|| #path::#label).into(); + let func = syn::parse(tokens).unwrap(); + Some(RequireFunc::Closure(func)) } else { None }; diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 9a2bdff16e..6077761bb3 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -180,11 +180,43 @@ use thiserror::Error; /// } /// /// # let mut world = World::default(); +/// // This will implicitly also insert C with the init_c() constructor +/// let id = world.spawn(A).id(); +/// assert_eq!(&C(10), world.entity(id).get::().unwrap()); +/// /// // This will implicitly also insert C with the `|| C(20)` constructor closure /// let id = world.spawn(B).id(); /// assert_eq!(&C(20), world.entity(id).get::().unwrap()); /// ``` /// +/// For convenience sake, you can abbreviate enum labels or constant values, with the type inferred to match that of the component you are requiring: +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// #[derive(Component)] +/// #[require(B = One, C = ONE)] +/// struct A; +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// enum B { +/// Zero, +/// One, +/// Two +/// } +/// +/// #[derive(Component, PartialEq, Eq, Debug)] +/// struct C(u8); +/// +/// impl C { +/// pub const ONE: Self = Self(1); +/// } +/// +/// # let mut world = World::default(); +/// let id = world.spawn(A).id(); +/// assert_eq!(&B::One, world.entity(id).get::().unwrap()); +/// assert_eq!(&C(1), world.entity(id).get::().unwrap()); +/// ```` +/// /// Required components are _recursive_. This means, if a Required Component has required components, /// those components will _also_ be inserted if they are missing: ///