Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/exclusive_system_param.rs
9412 views
1
use crate::{
2
prelude::{FromWorld, QueryState},
3
query::{QueryData, QueryFilter},
4
system::{Local, SystemMeta, SystemParam, SystemState},
5
world::World,
6
};
7
use bevy_platform::cell::SyncCell;
8
use core::marker::PhantomData;
9
use variadics_please::all_tuples;
10
11
/// A parameter that can be used in an exclusive system (a system with an `&mut World` parameter).
12
/// Any parameters implementing this trait must come after the `&mut World` parameter.
13
#[diagnostic::on_unimplemented(
14
message = "`{Self}` can not be used as a parameter for an exclusive system",
15
label = "invalid system parameter"
16
)]
17
pub trait ExclusiveSystemParam: Sized {
18
/// Used to store data which persists across invocations of a system.
19
type State: Send + Sync + 'static;
20
/// The item type returned when constructing this system param.
21
/// See [`SystemParam::Item`].
22
type Item<'s>: ExclusiveSystemParam<State = Self::State>;
23
24
/// Creates a new instance of this param's [`State`](Self::State).
25
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self::State;
26
27
/// Creates a parameter to be passed into an [`ExclusiveSystemParamFunction`].
28
///
29
/// [`ExclusiveSystemParamFunction`]: super::ExclusiveSystemParamFunction
30
fn get_param<'s>(state: &'s mut Self::State, system_meta: &SystemMeta) -> Self::Item<'s>;
31
}
32
33
/// Shorthand way of accessing the associated type [`ExclusiveSystemParam::Item`]
34
/// for a given [`ExclusiveSystemParam`].
35
pub type ExclusiveSystemParamItem<'s, P> = <P as ExclusiveSystemParam>::Item<'s>;
36
37
impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> ExclusiveSystemParam
38
for &'a mut QueryState<D, F>
39
{
40
type State = QueryState<D, F>;
41
type Item<'s> = &'s mut QueryState<D, F>;
42
43
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
44
QueryState::new(world)
45
}
46
47
fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {
48
state
49
}
50
}
51
52
impl<'a, P: SystemParam + 'static> ExclusiveSystemParam for &'a mut SystemState<P> {
53
type State = SystemState<P>;
54
type Item<'s> = &'s mut SystemState<P>;
55
56
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
57
SystemState::new(world)
58
}
59
60
fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {
61
state
62
}
63
}
64
65
impl<'_s, T: FromWorld + Send + 'static> ExclusiveSystemParam for Local<'_s, T> {
66
type State = SyncCell<T>;
67
type Item<'s> = Local<'s, T>;
68
69
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
70
SyncCell::new(T::from_world(world))
71
}
72
73
fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {
74
Local(state.get())
75
}
76
}
77
78
impl<S: ?Sized> ExclusiveSystemParam for PhantomData<S> {
79
type State = ();
80
type Item<'s> = PhantomData<S>;
81
82
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {}
83
84
fn get_param<'s>(_state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {
85
PhantomData
86
}
87
}
88
89
macro_rules! impl_exclusive_system_param_tuple {
90
($(#[$meta:meta])* $($param: ident),*) => {
91
#[expect(
92
clippy::allow_attributes,
93
reason = "This is within a macro, and as such, the below lints may not always apply."
94
)]
95
#[allow(
96
non_snake_case,
97
reason = "Certain variable names are provided by the caller, not by us."
98
)]
99
#[allow(
100
unused_variables,
101
reason = "Zero-length tuples won't use any of the parameters."
102
)]
103
#[allow(clippy::unused_unit, reason = "Zero length tuple is unit.")]
104
$(#[$meta])*
105
impl<$($param: ExclusiveSystemParam),*> ExclusiveSystemParam for ($($param,)*) {
106
type State = ($($param::State,)*);
107
type Item<'s> = ($($param::Item<'s>,)*);
108
109
#[inline]
110
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
111
($($param::init(world, system_meta),)*)
112
}
113
114
#[inline]
115
fn get_param<'s>(
116
state: &'s mut Self::State,
117
system_meta: &SystemMeta,
118
) -> Self::Item<'s> {
119
let ($($param,)*) = state;
120
#[allow(
121
clippy::unused_unit,
122
reason = "Zero-length tuples won't have any params to get."
123
)]
124
($($param::get_param($param, system_meta),)*)
125
}
126
}
127
};
128
}
129
130
all_tuples!(
131
#[doc(fake_variadic)]
132
impl_exclusive_system_param_tuple,
133
0,
134
16,
135
P
136
);
137
138
#[cfg(test)]
139
mod tests {
140
use crate::{schedule::Schedule, system::Local, world::World};
141
use alloc::vec::Vec;
142
use bevy_ecs_macros::Resource;
143
use core::marker::PhantomData;
144
145
#[test]
146
fn test_exclusive_system_params() {
147
#[derive(Resource, Default)]
148
struct Res {
149
test_value: u32,
150
}
151
152
fn my_system(world: &mut World, mut local: Local<u32>, _phantom: PhantomData<Vec<u32>>) {
153
assert_eq!(world.resource::<Res>().test_value, *local);
154
*local += 1;
155
world.resource_mut::<Res>().test_value += 1;
156
}
157
158
let mut schedule = Schedule::default();
159
schedule.add_systems(my_system);
160
161
let mut world = World::default();
162
world.init_resource::<Res>();
163
164
schedule.run(&mut world);
165
schedule.run(&mut world);
166
167
assert_eq!(2, world.get_resource::<Res>().unwrap().test_value);
168
}
169
}
170
171