Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/input.rs
6604 views
1
use core::ops::{Deref, DerefMut};
2
3
use variadics_please::all_tuples;
4
5
use crate::{bundle::Bundle, event::Event, prelude::On, system::System};
6
7
/// Trait for types that can be used as input to [`System`]s.
8
///
9
/// Provided implementations are:
10
/// - `()`: No input
11
/// - [`In<T>`]: For values
12
/// - [`InRef<T>`]: For read-only references to values
13
/// - [`InMut<T>`]: For mutable references to values
14
/// - [`On<E, B>`]: For [`ObserverSystem`]s
15
/// - [`StaticSystemInput<I>`]: For arbitrary [`SystemInput`]s in generic contexts
16
/// - Tuples of [`SystemInput`]s up to 8 elements
17
///
18
/// For advanced usecases, you can implement this trait for your own types.
19
///
20
/// # Examples
21
///
22
/// ## Tuples of [`SystemInput`]s
23
///
24
/// ```
25
/// use bevy_ecs::prelude::*;
26
///
27
/// fn add((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
28
/// *a += b;
29
/// }
30
/// # let mut world = World::new();
31
/// # let mut add = IntoSystem::into_system(add);
32
/// # add.initialize(&mut world);
33
/// # let mut a = 12;
34
/// # let b = 24;
35
/// # add.run((&mut a, b), &mut world);
36
/// # assert_eq!(a, 36);
37
/// ```
38
///
39
/// [`ObserverSystem`]: crate::system::ObserverSystem
40
pub trait SystemInput: Sized {
41
/// The wrapper input type that is defined as the first argument to [`FunctionSystem`]s.
42
///
43
/// [`FunctionSystem`]: crate::system::FunctionSystem
44
type Param<'i>: SystemInput;
45
/// The inner input type that is passed to functions that run systems,
46
/// such as [`System::run`].
47
///
48
/// [`System::run`]: crate::system::System::run
49
type Inner<'i>;
50
51
/// Converts a [`SystemInput::Inner`] into a [`SystemInput::Param`].
52
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_>;
53
}
54
55
/// Shorthand way to get the [`System::In`] for a [`System`] as a [`SystemInput::Inner`].
56
pub type SystemIn<'a, S> = <<S as System>::In as SystemInput>::Inner<'a>;
57
58
/// A [`SystemInput`] type which denotes that a [`System`] receives
59
/// an input value of type `T` from its caller.
60
///
61
/// [`System`]s may take an optional input which they require to be passed to them when they
62
/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked
63
/// with this `In` type, but only the first param of a function may be tagged as an input. This also
64
/// means a system can only have one or zero input parameters.
65
///
66
/// See [`SystemInput`] to learn more about system inputs in general.
67
///
68
/// # Examples
69
///
70
/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.
71
///
72
/// ```
73
/// # use bevy_ecs::prelude::*;
74
/// #
75
/// fn square(In(input): In<usize>) -> usize {
76
/// input * input
77
/// }
78
///
79
/// let mut world = World::new();
80
/// let mut square_system = IntoSystem::into_system(square);
81
/// square_system.initialize(&mut world);
82
///
83
/// assert_eq!(square_system.run(12, &mut world).unwrap(), 144);
84
/// ```
85
///
86
/// [`SystemParam`]: crate::system::SystemParam
87
/// [`FunctionSystem`]: crate::system::FunctionSystem
88
#[derive(Debug)]
89
pub struct In<T>(pub T);
90
91
impl<T: 'static> SystemInput for In<T> {
92
type Param<'i> = In<T>;
93
type Inner<'i> = T;
94
95
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
96
In(this)
97
}
98
}
99
100
impl<T> Deref for In<T> {
101
type Target = T;
102
103
fn deref(&self) -> &Self::Target {
104
&self.0
105
}
106
}
107
108
impl<T> DerefMut for In<T> {
109
fn deref_mut(&mut self) -> &mut Self::Target {
110
&mut self.0
111
}
112
}
113
114
/// A [`SystemInput`] type which denotes that a [`System`] receives
115
/// a read-only reference to a value of type `T` from its caller.
116
///
117
/// This is similar to [`In`] but takes a reference to a value instead of the value itself.
118
/// See [`InMut`] for the mutable version.
119
///
120
/// See [`SystemInput`] to learn more about system inputs in general.
121
///
122
/// # Examples
123
///
124
/// Here is a simple example of a system that logs the passed in message.
125
///
126
/// ```
127
/// # use bevy_ecs::prelude::*;
128
/// # use std::fmt::Write as _;
129
/// #
130
/// #[derive(Resource, Default)]
131
/// struct Log(String);
132
///
133
/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {
134
/// writeln!(log.0, "{}", msg).unwrap();
135
/// }
136
///
137
/// let mut world = World::new();
138
/// world.init_resource::<Log>();
139
/// let mut log_system = IntoSystem::into_system(log);
140
/// log_system.initialize(&mut world);
141
///
142
/// log_system.run("Hello, world!", &mut world);
143
/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");
144
/// ```
145
///
146
/// [`SystemParam`]: crate::system::SystemParam
147
#[derive(Debug)]
148
pub struct InRef<'i, T: ?Sized>(pub &'i T);
149
150
impl<T: ?Sized + 'static> SystemInput for InRef<'_, T> {
151
type Param<'i> = InRef<'i, T>;
152
type Inner<'i> = &'i T;
153
154
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
155
InRef(this)
156
}
157
}
158
159
impl<'i, T: ?Sized> Deref for InRef<'i, T> {
160
type Target = T;
161
162
fn deref(&self) -> &Self::Target {
163
self.0
164
}
165
}
166
167
/// A [`SystemInput`] type which denotes that a [`System`] receives
168
/// a mutable reference to a value of type `T` from its caller.
169
///
170
/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.
171
/// See [`InRef`] for the read-only version.
172
///
173
/// See [`SystemInput`] to learn more about system inputs in general.
174
///
175
/// # Examples
176
///
177
/// Here is a simple example of a system that takes a `&mut usize` and squares it.
178
///
179
/// ```
180
/// # use bevy_ecs::prelude::*;
181
/// #
182
/// fn square(InMut(input): InMut<usize>) {
183
/// *input *= *input;
184
/// }
185
///
186
/// let mut world = World::new();
187
/// let mut square_system = IntoSystem::into_system(square);
188
/// square_system.initialize(&mut world);
189
///
190
/// let mut value = 12;
191
/// square_system.run(&mut value, &mut world);
192
/// assert_eq!(value, 144);
193
/// ```
194
///
195
/// [`SystemParam`]: crate::system::SystemParam
196
#[derive(Debug)]
197
pub struct InMut<'a, T: ?Sized>(pub &'a mut T);
198
199
impl<T: ?Sized + 'static> SystemInput for InMut<'_, T> {
200
type Param<'i> = InMut<'i, T>;
201
type Inner<'i> = &'i mut T;
202
203
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
204
InMut(this)
205
}
206
}
207
208
impl<'i, T: ?Sized> Deref for InMut<'i, T> {
209
type Target = T;
210
211
fn deref(&self) -> &Self::Target {
212
self.0
213
}
214
}
215
216
impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {
217
fn deref_mut(&mut self) -> &mut Self::Target {
218
self.0
219
}
220
}
221
222
/// Used for [`ObserverSystem`]s.
223
///
224
/// [`ObserverSystem`]: crate::system::ObserverSystem
225
impl<E: Event, B: Bundle> SystemInput for On<'_, '_, E, B> {
226
// Note: the fact that we must use a shared lifetime here is
227
// a key piece of the complicated safety story documented above
228
// the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in
229
// the `On` implementation.
230
type Param<'i> = On<'i, 'i, E, B>;
231
type Inner<'i> = On<'i, 'i, E, B>;
232
233
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
234
this
235
}
236
}
237
238
/// A helper for using [`SystemInput`]s in generic contexts.
239
///
240
/// This type is a [`SystemInput`] adapter which always has
241
/// `Self::Param == Self` (ignoring lifetimes for brevity),
242
/// no matter the argument [`SystemInput`] (`I`).
243
///
244
/// This makes it useful for having arbitrary [`SystemInput`]s in
245
/// function systems.
246
///
247
/// See [`SystemInput`] to learn more about system inputs in general.
248
pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);
249
250
impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {
251
type Param<'i> = StaticSystemInput<'i, I>;
252
type Inner<'i> = I::Inner<'i>;
253
254
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
255
StaticSystemInput(this)
256
}
257
}
258
259
macro_rules! impl_system_input_tuple {
260
($(#[$meta:meta])* $($name:ident),*) => {
261
$(#[$meta])*
262
impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {
263
type Param<'i> = ($($name::Param<'i>,)*);
264
type Inner<'i> = ($($name::Inner<'i>,)*);
265
266
#[expect(
267
clippy::allow_attributes,
268
reason = "This is in a macro; as such, the below lints may not always apply."
269
)]
270
#[allow(
271
non_snake_case,
272
reason = "Certain variable names are provided by the caller, not by us."
273
)]
274
#[allow(
275
clippy::unused_unit,
276
reason = "Zero-length tuples won't have anything to wrap."
277
)]
278
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
279
let ($($name,)*) = this;
280
($($name::wrap($name),)*)
281
}
282
}
283
};
284
}
285
286
all_tuples!(
287
#[doc(fake_variadic)]
288
impl_system_input_tuple,
289
0,
290
8,
291
I
292
);
293
294
#[cfg(test)]
295
mod tests {
296
use crate::{
297
system::{In, InMut, InRef, IntoSystem, System},
298
world::World,
299
};
300
301
#[test]
302
fn two_tuple() {
303
fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
304
a + b
305
}
306
fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {
307
*a + *b
308
}
309
fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
310
*a += b;
311
}
312
313
let mut world = World::new();
314
let mut by_value = IntoSystem::into_system(by_value);
315
let mut by_ref = IntoSystem::into_system(by_ref);
316
let mut by_mut = IntoSystem::into_system(by_mut);
317
318
by_value.initialize(&mut world);
319
by_ref.initialize(&mut world);
320
by_mut.initialize(&mut world);
321
322
let mut a = 12;
323
let b = 24;
324
325
assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);
326
assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);
327
by_mut.run((&mut a, b), &mut world).unwrap();
328
assert_eq!(a, 36);
329
}
330
}
331
332