Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/input.rs
9366 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 type that may be constructed from the input of a [`System`].
59
/// This is used to allow systems whose first parameter is a `StaticSystemInput<In>`
60
/// to take an `In` as input, and can be implemented for user types to allow
61
/// similar conversions.
62
pub trait FromInput<In: SystemInput>: SystemInput {
63
/// Converts the system input's inner representation into this type's
64
/// inner representation.
65
fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i>;
66
}
67
68
impl<In: SystemInput> FromInput<In> for In {
69
#[inline]
70
fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {
71
inner
72
}
73
}
74
75
impl<'a, In: SystemInput> FromInput<In> for StaticSystemInput<'a, In> {
76
#[inline]
77
fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {
78
inner
79
}
80
}
81
82
/// A [`SystemInput`] type which denotes that a [`System`] receives
83
/// an input value of type `T` from its caller.
84
///
85
/// [`System`]s may take an optional input which they require to be passed to them when they
86
/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked
87
/// with this `In` type, but only the first param of a function may be tagged as an input. This also
88
/// means a system can only have one or zero input parameters.
89
///
90
/// See [`SystemInput`] to learn more about system inputs in general.
91
///
92
/// # Examples
93
///
94
/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.
95
///
96
/// ```
97
/// # use bevy_ecs::prelude::*;
98
/// #
99
/// fn square(In(input): In<usize>) -> usize {
100
/// input * input
101
/// }
102
///
103
/// let mut world = World::new();
104
/// let mut square_system = IntoSystem::into_system(square);
105
/// square_system.initialize(&mut world);
106
///
107
/// assert_eq!(square_system.run(12, &mut world).unwrap(), 144);
108
/// ```
109
///
110
/// [`SystemParam`]: crate::system::SystemParam
111
/// [`FunctionSystem`]: crate::system::FunctionSystem
112
#[derive(Debug)]
113
pub struct In<T>(pub T);
114
115
impl<T: 'static> SystemInput for In<T> {
116
type Param<'i> = In<T>;
117
type Inner<'i> = T;
118
119
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
120
In(this)
121
}
122
}
123
124
impl<T> Deref for In<T> {
125
type Target = T;
126
127
fn deref(&self) -> &Self::Target {
128
&self.0
129
}
130
}
131
132
impl<T> DerefMut for In<T> {
133
fn deref_mut(&mut self) -> &mut Self::Target {
134
&mut self.0
135
}
136
}
137
138
/// A [`SystemInput`] type which denotes that a [`System`] receives
139
/// a read-only reference to a value of type `T` from its caller.
140
///
141
/// This is similar to [`In`] but takes a reference to a value instead of the value itself.
142
/// See [`InMut`] for the mutable version.
143
///
144
/// See [`SystemInput`] to learn more about system inputs in general.
145
///
146
/// # Examples
147
///
148
/// Here is a simple example of a system that logs the passed in message.
149
///
150
/// ```
151
/// # use bevy_ecs::prelude::*;
152
/// # use std::fmt::Write as _;
153
/// #
154
/// #[derive(Resource, Default)]
155
/// struct Log(String);
156
///
157
/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {
158
/// writeln!(log.0, "{}", msg).unwrap();
159
/// }
160
///
161
/// let mut world = World::new();
162
/// world.init_resource::<Log>();
163
/// let mut log_system = IntoSystem::into_system(log);
164
/// log_system.initialize(&mut world);
165
///
166
/// log_system.run("Hello, world!", &mut world);
167
/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");
168
/// ```
169
///
170
/// [`SystemParam`]: crate::system::SystemParam
171
#[derive(Debug)]
172
pub struct InRef<'i, T: ?Sized>(pub &'i T);
173
174
impl<T: ?Sized + 'static> SystemInput for InRef<'_, T> {
175
type Param<'i> = InRef<'i, T>;
176
type Inner<'i> = &'i T;
177
178
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
179
InRef(this)
180
}
181
}
182
183
impl<'i, T: ?Sized> Deref for InRef<'i, T> {
184
type Target = T;
185
186
fn deref(&self) -> &Self::Target {
187
self.0
188
}
189
}
190
191
/// A [`SystemInput`] type which denotes that a [`System`] receives
192
/// a mutable reference to a value of type `T` from its caller.
193
///
194
/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.
195
/// See [`InRef`] for the read-only version.
196
///
197
/// See [`SystemInput`] to learn more about system inputs in general.
198
///
199
/// # Examples
200
///
201
/// Here is a simple example of a system that takes a `&mut usize` and squares it.
202
///
203
/// ```
204
/// # use bevy_ecs::prelude::*;
205
/// #
206
/// fn square(InMut(input): InMut<usize>) {
207
/// *input *= *input;
208
/// }
209
///
210
/// let mut world = World::new();
211
/// let mut square_system = IntoSystem::into_system(square);
212
/// square_system.initialize(&mut world);
213
///
214
/// let mut value = 12;
215
/// square_system.run(&mut value, &mut world);
216
/// assert_eq!(value, 144);
217
/// ```
218
///
219
/// [`SystemParam`]: crate::system::SystemParam
220
#[derive(Debug)]
221
pub struct InMut<'a, T: ?Sized>(pub &'a mut T);
222
223
impl<T: ?Sized + 'static> SystemInput for InMut<'_, T> {
224
type Param<'i> = InMut<'i, T>;
225
type Inner<'i> = &'i mut T;
226
227
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
228
InMut(this)
229
}
230
}
231
232
impl<'i, T: ?Sized> Deref for InMut<'i, T> {
233
type Target = T;
234
235
fn deref(&self) -> &Self::Target {
236
self.0
237
}
238
}
239
240
impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {
241
fn deref_mut(&mut self) -> &mut Self::Target {
242
self.0
243
}
244
}
245
246
/// Used for [`ObserverSystem`]s.
247
///
248
/// [`ObserverSystem`]: crate::system::ObserverSystem
249
impl<E: Event, B: Bundle> SystemInput for On<'_, '_, E, B> {
250
// Note: the fact that we must use a shared lifetime here is
251
// a key piece of the complicated safety story documented above
252
// the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in
253
// the `On` implementation.
254
type Param<'i> = On<'i, 'i, E, B>;
255
type Inner<'i> = On<'i, 'i, E, B>;
256
257
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
258
this
259
}
260
}
261
262
/// A helper for using [`SystemInput`]s in generic contexts.
263
///
264
/// This type is a [`SystemInput`] adapter which always has
265
/// `Self::Param == Self` (ignoring lifetimes for brevity),
266
/// no matter the argument [`SystemInput`] (`I`).
267
///
268
/// This makes it useful for having arbitrary [`SystemInput`]s in
269
/// function systems.
270
///
271
/// See [`SystemInput`] to learn more about system inputs in general.
272
pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);
273
274
impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {
275
type Param<'i> = StaticSystemInput<'i, I>;
276
type Inner<'i> = I::Inner<'i>;
277
278
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
279
StaticSystemInput(this)
280
}
281
}
282
283
macro_rules! impl_system_input_tuple {
284
($(#[$meta:meta])* $($name:ident),*) => {
285
$(#[$meta])*
286
impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {
287
type Param<'i> = ($($name::Param<'i>,)*);
288
type Inner<'i> = ($($name::Inner<'i>,)*);
289
290
#[expect(
291
clippy::allow_attributes,
292
reason = "This is in a macro; as such, the below lints may not always apply."
293
)]
294
#[allow(
295
non_snake_case,
296
reason = "Certain variable names are provided by the caller, not by us."
297
)]
298
#[allow(
299
clippy::unused_unit,
300
reason = "Zero-length tuples won't have anything to wrap."
301
)]
302
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
303
let ($($name,)*) = this;
304
($($name::wrap($name),)*)
305
}
306
}
307
};
308
}
309
310
all_tuples!(
311
#[doc(fake_variadic)]
312
impl_system_input_tuple,
313
0,
314
8,
315
I
316
);
317
318
#[cfg(test)]
319
mod tests {
320
use crate::{
321
system::{assert_is_system, In, InMut, InRef, IntoSystem, StaticSystemInput, System},
322
world::World,
323
};
324
325
#[test]
326
fn two_tuple() {
327
fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
328
a + b
329
}
330
fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {
331
*a + *b
332
}
333
fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
334
*a += b;
335
}
336
337
let mut world = World::new();
338
let mut by_value = IntoSystem::into_system(by_value);
339
let mut by_ref = IntoSystem::into_system(by_ref);
340
let mut by_mut = IntoSystem::into_system(by_mut);
341
342
by_value.initialize(&mut world);
343
by_ref.initialize(&mut world);
344
by_mut.initialize(&mut world);
345
346
let mut a = 12;
347
let b = 24;
348
349
assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);
350
assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);
351
by_mut.run((&mut a, b), &mut world).unwrap();
352
assert_eq!(a, 36);
353
}
354
355
#[test]
356
fn compatible_input() {
357
fn takes_usize(In(a): In<usize>) -> usize {
358
a
359
}
360
361
fn takes_static_usize(StaticSystemInput(b): StaticSystemInput<In<usize>>) -> usize {
362
b
363
}
364
365
assert_is_system::<In<usize>, usize, _>(takes_usize);
366
// test if StaticSystemInput is compatible with its inner type
367
assert_is_system::<In<usize>, usize, _>(takes_static_usize);
368
}
369
}
370
371