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
6604 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
$(#[$meta])*
104
impl<$($param: ExclusiveSystemParam),*> ExclusiveSystemParam for ($($param,)*) {
105
type State = ($($param::State,)*);
106
type Item<'s> = ($($param::Item<'s>,)*);
107
108
#[inline]
109
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
110
(($($param::init(world, system_meta),)*))
111
}
112
113
#[inline]
114
fn get_param<'s>(
115
state: &'s mut Self::State,
116
system_meta: &SystemMeta,
117
) -> Self::Item<'s> {
118
let ($($param,)*) = state;
119
#[allow(
120
clippy::unused_unit,
121
reason = "Zero-length tuples won't have any params to get."
122
)]
123
($($param::get_param($param, system_meta),)*)
124
}
125
}
126
};
127
}
128
129
all_tuples!(
130
#[doc(fake_variadic)]
131
impl_exclusive_system_param_tuple,
132
0,
133
16,
134
P
135
);
136
137
#[cfg(test)]
138
mod tests {
139
use crate::{schedule::Schedule, system::Local, world::World};
140
use alloc::vec::Vec;
141
use bevy_ecs_macros::Resource;
142
use core::marker::PhantomData;
143
144
#[test]
145
fn test_exclusive_system_params() {
146
#[derive(Resource, Default)]
147
struct Res {
148
test_value: u32,
149
}
150
151
fn my_system(world: &mut World, mut local: Local<u32>, _phantom: PhantomData<Vec<u32>>) {
152
assert_eq!(world.resource::<Res>().test_value, *local);
153
*local += 1;
154
world.resource_mut::<Res>().test_value += 1;
155
}
156
157
let mut schedule = Schedule::default();
158
schedule.add_systems(my_system);
159
160
let mut world = World::default();
161
world.init_resource::<Res>();
162
163
schedule.run(&mut world);
164
schedule.run(&mut world);
165
166
assert_eq!(2, world.get_resource::<Res>().unwrap().test_value);
167
}
168
}
169
170