Replace impl_param_set
proc macro with a macro_rules
macro (#16847)
# Objective Simplify the code by using `macro_rules` instead of a proc macro where possible. ## Solution Replace `impl_param_set` proc macro with a `macro_rules` macro.
This commit is contained in:
parent
b9123e74b6
commit
3ef99cf82c
@ -30,7 +30,7 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
|
|||||||
# other
|
# other
|
||||||
downcast-rs = "1.2.0"
|
downcast-rs = "1.2.0"
|
||||||
thiserror = { version = "2", default-features = false }
|
thiserror = { version = "2", default-features = false }
|
||||||
variadics_please = "1.0"
|
variadics_please = "1.1"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
ctrlc = "3.4.4"
|
ctrlc = "3.4.4"
|
||||||
|
@ -119,7 +119,7 @@ nonmax = { version = "0.5", default-features = false }
|
|||||||
arrayvec = { version = "0.7.4", default-features = false, optional = true }
|
arrayvec = { version = "0.7.4", default-features = false, optional = true }
|
||||||
smallvec = { version = "1", features = ["union"] }
|
smallvec = { version = "1", features = ["union"] }
|
||||||
indexmap = { version = "2.5.0", default-features = false }
|
indexmap = { version = "2.5.0", default-features = false }
|
||||||
variadics_please = { version = "1.0", default-features = false }
|
variadics_please = { version = "1.1", default-features = false }
|
||||||
critical-section = { version = "1.2.0", optional = true }
|
critical-section = { version = "1.2.0", optional = true }
|
||||||
portable-atomic = { version = "1", default-features = false, features = [
|
portable-atomic = { version = "1", default-features = false, features = [
|
||||||
"fallback",
|
"fallback",
|
||||||
|
@ -12,12 +12,11 @@ mod world_query;
|
|||||||
use crate::{query_data::derive_query_data_impl, query_filter::derive_query_filter_impl};
|
use crate::{query_data::derive_query_data_impl, query_filter::derive_query_filter_impl};
|
||||||
use bevy_macro_utils::{derive_label, ensure_no_collision, get_struct_fields, BevyManifest};
|
use bevy_macro_utils::{derive_label, ensure_no_collision, get_struct_fields, BevyManifest};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma,
|
parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma,
|
||||||
ConstParam, DeriveInput, GenericParam, Ident, Index, TypeParam,
|
ConstParam, DeriveInput, GenericParam, Index, TypeParam,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BundleFieldKind {
|
enum BundleFieldKind {
|
||||||
@ -284,136 +283,6 @@ pub fn derive_visit_entities(input: TokenStream) -> TokenStream {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec<Ident> {
|
|
||||||
(0..count)
|
|
||||||
.map(|i| Ident::new(&fmt_string(i), Span::call_site()))
|
|
||||||
.collect::<Vec<Ident>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn impl_param_set(_input: TokenStream) -> TokenStream {
|
|
||||||
let mut tokens = TokenStream::new();
|
|
||||||
let max_params = 8;
|
|
||||||
let params = get_idents(|i| format!("P{i}"), max_params);
|
|
||||||
let metas = get_idents(|i| format!("m{i}"), max_params);
|
|
||||||
let mut param_fn_muts = Vec::new();
|
|
||||||
for (i, param) in params.iter().enumerate() {
|
|
||||||
let fn_name = Ident::new(&format!("p{i}"), Span::call_site());
|
|
||||||
let index = Index::from(i);
|
|
||||||
let ordinal = match i {
|
|
||||||
1 => "1st".to_owned(),
|
|
||||||
2 => "2nd".to_owned(),
|
|
||||||
3 => "3rd".to_owned(),
|
|
||||||
x => format!("{x}th"),
|
|
||||||
};
|
|
||||||
let comment =
|
|
||||||
format!("Gets exclusive access to the {ordinal} parameter in this [`ParamSet`].");
|
|
||||||
param_fn_muts.push(quote! {
|
|
||||||
#[doc = #comment]
|
|
||||||
/// No other parameters may be accessed while this one is active.
|
|
||||||
pub fn #fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, #param> {
|
|
||||||
// SAFETY: systems run without conflicts with other systems.
|
|
||||||
// Conflicting params in ParamSet are not accessible at the same time
|
|
||||||
// ParamSets are guaranteed to not conflict with other SystemParams
|
|
||||||
unsafe {
|
|
||||||
#param::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for param_count in 1..=max_params {
|
|
||||||
let param = ¶ms[0..param_count];
|
|
||||||
let meta = &metas[0..param_count];
|
|
||||||
let param_fn_mut = ¶m_fn_muts[0..param_count];
|
|
||||||
tokens.extend(TokenStream::from(quote! {
|
|
||||||
// SAFETY: All parameters are constrained to ReadOnlySystemParam, so World is only read
|
|
||||||
unsafe impl<'w, 's, #(#param,)*> ReadOnlySystemParam for ParamSet<'w, 's, (#(#param,)*)>
|
|
||||||
where #(#param: ReadOnlySystemParam,)*
|
|
||||||
{ }
|
|
||||||
|
|
||||||
// SAFETY: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts
|
|
||||||
// with any prior access, a panic will occur.
|
|
||||||
unsafe impl<'_w, '_s, #(#param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, (#(#param,)*)>
|
|
||||||
{
|
|
||||||
type State = (#(#param::State,)*);
|
|
||||||
type Item<'w, 's> = ParamSet<'w, 's, (#(#param,)*)>;
|
|
||||||
|
|
||||||
// Note: We allow non snake case so the compiler don't complain about the creation of non_snake_case variables
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
|
|
||||||
#(
|
|
||||||
// Pretend to add each param to the system alone, see if it conflicts
|
|
||||||
let mut #meta = system_meta.clone();
|
|
||||||
#meta.component_access_set.clear();
|
|
||||||
#meta.archetype_component_access.clear();
|
|
||||||
#param::init_state(world, &mut #meta);
|
|
||||||
// The variable is being defined with non_snake_case here
|
|
||||||
let #param = #param::init_state(world, &mut system_meta.clone());
|
|
||||||
)*
|
|
||||||
// Make the ParamSet non-send if any of its parameters are non-send.
|
|
||||||
if false #(|| !#meta.is_send())* {
|
|
||||||
system_meta.set_non_send();
|
|
||||||
}
|
|
||||||
#(
|
|
||||||
system_meta
|
|
||||||
.component_access_set
|
|
||||||
.extend(#meta.component_access_set);
|
|
||||||
system_meta
|
|
||||||
.archetype_component_access
|
|
||||||
.extend(&#meta.archetype_component_access);
|
|
||||||
)*
|
|
||||||
(#(#param,)*)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn new_archetype(state: &mut Self::State, archetype: &Archetype, system_meta: &mut SystemMeta) {
|
|
||||||
// SAFETY: The caller ensures that `archetype` is from the World the state was initialized from in `init_state`.
|
|
||||||
unsafe { <(#(#param,)*) as SystemParam>::new_archetype(state, archetype, system_meta); }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
|
|
||||||
<(#(#param,)*) as SystemParam>::apply(state, system_meta, world);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
|
|
||||||
<(#(#param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn validate_param<'w, 's>(
|
|
||||||
state: &'s Self::State,
|
|
||||||
system_meta: &SystemMeta,
|
|
||||||
world: UnsafeWorldCell<'w>,
|
|
||||||
) -> bool {
|
|
||||||
<(#(#param,)*) as SystemParam>::validate_param(state, system_meta, world)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn get_param<'w, 's>(
|
|
||||||
state: &'s mut Self::State,
|
|
||||||
system_meta: &SystemMeta,
|
|
||||||
world: UnsafeWorldCell<'w>,
|
|
||||||
change_tick: Tick,
|
|
||||||
) -> Self::Item<'w, 's> {
|
|
||||||
ParamSet {
|
|
||||||
param_states: state,
|
|
||||||
system_meta: system_meta.clone(),
|
|
||||||
world,
|
|
||||||
change_tick,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)>
|
|
||||||
{
|
|
||||||
#(#param_fn_mut)*
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implement `SystemParam` to use a struct as a parameter in a system
|
/// Implement `SystemParam` to use a struct as a parameter in a system
|
||||||
#[proc_macro_derive(SystemParam, attributes(system_param))]
|
#[proc_macro_derive(SystemParam, attributes(system_param))]
|
||||||
pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
||||||
|
@ -17,7 +17,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
|
use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
|
||||||
use bevy_ecs_macros::impl_param_set;
|
|
||||||
pub use bevy_ecs_macros::{Resource, SystemParam};
|
pub use bevy_ecs_macros::{Resource, SystemParam};
|
||||||
use bevy_ptr::UnsafeCellDeref;
|
use bevy_ptr::UnsafeCellDeref;
|
||||||
use bevy_utils::synccell::SyncCell;
|
use bevy_utils::synccell::SyncCell;
|
||||||
@ -32,7 +31,7 @@ use core::{
|
|||||||
use disqualified::ShortName;
|
use disqualified::ShortName;
|
||||||
|
|
||||||
use super::Populated;
|
use super::Populated;
|
||||||
use variadics_please::all_tuples;
|
use variadics_please::{all_tuples, all_tuples_enumerated};
|
||||||
|
|
||||||
/// A parameter that can be used in a [`System`](super::System).
|
/// A parameter that can be used in a [`System`](super::System).
|
||||||
///
|
///
|
||||||
@ -674,7 +673,106 @@ pub struct ParamSet<'w, 's, T: SystemParam> {
|
|||||||
change_tick: Tick,
|
change_tick: Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_param_set!();
|
macro_rules! impl_param_set {
|
||||||
|
($(($index: tt, $param: ident, $system_meta: ident, $fn_name: ident)),*) => {
|
||||||
|
// SAFETY: All parameters are constrained to ReadOnlySystemParam, so World is only read
|
||||||
|
unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)>
|
||||||
|
where $($param: ReadOnlySystemParam,)*
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// SAFETY: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts
|
||||||
|
// with any prior access, a panic will occur.
|
||||||
|
unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)>
|
||||||
|
{
|
||||||
|
type State = ($($param::State,)*);
|
||||||
|
type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>;
|
||||||
|
|
||||||
|
// Note: We allow non snake case so the compiler don't complain about the creation of non_snake_case variables
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
|
||||||
|
$(
|
||||||
|
// Pretend to add each param to the system alone, see if it conflicts
|
||||||
|
let mut $system_meta = system_meta.clone();
|
||||||
|
$system_meta.component_access_set.clear();
|
||||||
|
$system_meta.archetype_component_access.clear();
|
||||||
|
$param::init_state(world, &mut $system_meta);
|
||||||
|
// The variable is being defined with non_snake_case here
|
||||||
|
let $param = $param::init_state(world, &mut system_meta.clone());
|
||||||
|
)*
|
||||||
|
// Make the ParamSet non-send if any of its parameters are non-send.
|
||||||
|
if false $(|| !$system_meta.is_send())* {
|
||||||
|
system_meta.set_non_send();
|
||||||
|
}
|
||||||
|
$(
|
||||||
|
system_meta
|
||||||
|
.component_access_set
|
||||||
|
.extend($system_meta.component_access_set);
|
||||||
|
system_meta
|
||||||
|
.archetype_component_access
|
||||||
|
.extend(&$system_meta.archetype_component_access);
|
||||||
|
)*
|
||||||
|
($($param,)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn new_archetype(state: &mut Self::State, archetype: &Archetype, system_meta: &mut SystemMeta) {
|
||||||
|
// SAFETY: The caller ensures that `archetype` is from the World the state was initialized from in `init_state`.
|
||||||
|
unsafe { <($($param,)*) as SystemParam>::new_archetype(state, archetype, system_meta); }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
|
||||||
|
<($($param,)*) as SystemParam>::apply(state, system_meta, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
|
||||||
|
<($($param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn validate_param<'w, 's>(
|
||||||
|
state: &'s Self::State,
|
||||||
|
system_meta: &SystemMeta,
|
||||||
|
world: UnsafeWorldCell<'w>,
|
||||||
|
) -> bool {
|
||||||
|
<($($param,)*) as SystemParam>::validate_param(state, system_meta, world)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn get_param<'w, 's>(
|
||||||
|
state: &'s mut Self::State,
|
||||||
|
system_meta: &SystemMeta,
|
||||||
|
world: UnsafeWorldCell<'w>,
|
||||||
|
change_tick: Tick,
|
||||||
|
) -> Self::Item<'w, 's> {
|
||||||
|
ParamSet {
|
||||||
|
param_states: state,
|
||||||
|
system_meta: system_meta.clone(),
|
||||||
|
world,
|
||||||
|
change_tick,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)>
|
||||||
|
{
|
||||||
|
$(
|
||||||
|
/// Gets exclusive access to the parameter at index
|
||||||
|
#[doc = stringify!($index)]
|
||||||
|
/// in this [`ParamSet`].
|
||||||
|
/// No other parameters may be accessed while this one is active.
|
||||||
|
pub fn $fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, $param> {
|
||||||
|
// SAFETY: systems run without conflicts with other systems.
|
||||||
|
// Conflicting params in ParamSet are not accessible at the same time
|
||||||
|
// ParamSets are guaranteed to not conflict with other SystemParams
|
||||||
|
unsafe {
|
||||||
|
$param::get_param(&mut self.param_states.$index, &self.system_meta, self.world, self.change_tick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
all_tuples_enumerated!(impl_param_set, 1, 8, P, m, p);
|
||||||
|
|
||||||
/// A type that can be inserted into a [`World`] as a singleton.
|
/// A type that can be inserted into a [`World`] as a singleton.
|
||||||
///
|
///
|
||||||
|
@ -75,7 +75,7 @@ uuid = { version = "1.0", default-features = false, optional = true, features =
|
|||||||
"v4",
|
"v4",
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
variadics_please = "1.0"
|
variadics_please = "1.1"
|
||||||
wgpu-types = { version = "23", features = ["serde"], optional = true }
|
wgpu-types = { version = "23", features = ["serde"], optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -92,7 +92,7 @@ async-channel = "2.3.0"
|
|||||||
nonmax = "0.5"
|
nonmax = "0.5"
|
||||||
smallvec = { version = "1.11", features = ["const_new"] }
|
smallvec = { version = "1.11", features = ["const_new"] }
|
||||||
offset-allocator = "0.2"
|
offset-allocator = "0.2"
|
||||||
variadics_please = "1.0"
|
variadics_please = "1.1"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
# Omit the `glsl` feature in non-WebAssembly by default.
|
# Omit the `glsl` feature in non-WebAssembly by default.
|
||||||
|
@ -23,7 +23,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
|||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", optional = true }
|
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", optional = true }
|
||||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true }
|
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true }
|
||||||
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev", optional = true }
|
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev", optional = true }
|
||||||
variadics_please = "1.0"
|
variadics_please = "1.1"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
Loading…
Reference in New Issue
Block a user