@@ -7,18 +7,18 @@ use thiserror::Error;
7
7
8
8
/// A small wrapper for [`BoxedSystem`] that also keeps track whether or not the system has been initialized.
9
9
#[ derive( Component ) ]
10
- struct RegisteredSystem {
10
+ struct RegisteredSystem < I > {
11
11
initialized : bool ,
12
- system : BoxedSystem ,
12
+ system : BoxedSystem < I > ,
13
13
}
14
14
15
15
/// A system that has been removed from the registry.
16
16
/// It contains the system and whether or not it has been initialized.
17
17
///
18
18
/// This struct is returned by [`World::remove_system`].
19
- pub struct RemovedSystem {
19
+ pub struct RemovedSystem < I = ( ) > {
20
20
initialized : bool ,
21
- system : BoxedSystem ,
21
+ system : BoxedSystem < I > ,
22
22
}
23
23
24
24
impl RemovedSystem {
@@ -38,8 +38,35 @@ impl RemovedSystem {
38
38
///
39
39
/// These are opaque identifiers, keyed to a specific [`World`],
40
40
/// and are created via [`World::register_system`].
41
- #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
42
- pub struct SystemId ( Entity ) ;
41
+ #[ derive( Eq ) ]
42
+ pub struct SystemId < I = ( ) > ( Entity , std:: marker:: PhantomData < I > ) ;
43
+
44
+ // A manual impl is used because the trait bounds should ignore the `I` phantom parameter.
45
+ impl < I > Copy for SystemId < I > { }
46
+ // A manual impl is used because the trait bounds should ignore the `I` phantom parameter.
47
+ impl < I > Clone for SystemId < I > {
48
+ fn clone ( & self ) -> Self {
49
+ * self
50
+ }
51
+ }
52
+ // A manual impl is used because the trait bounds should ignore the `I` phantom parameter.
53
+ impl < I > PartialEq for SystemId < I > {
54
+ fn eq ( & self , other : & Self ) -> bool {
55
+ self . 0 == other. 0 && self . 1 == other. 1
56
+ }
57
+ }
58
+ // A manual impl is used because the trait bounds should ignore the `I` phantom parameter.
59
+ impl < I > std:: hash:: Hash for SystemId < I > {
60
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
61
+ self . 0 . hash ( state) ;
62
+ }
63
+ }
64
+ impl < I > std:: fmt:: Debug for SystemId < I > {
65
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
66
+ // The PhantomData field is omitted for simplicity.
67
+ f. debug_tuple ( "SystemId" ) . field ( & self . 0 ) . finish ( )
68
+ }
69
+ }
43
70
44
71
impl World {
45
72
/// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`].
@@ -51,16 +78,17 @@ impl World {
51
78
/// This allows for running systems in a pushed-based fashion.
52
79
/// Using a [`Schedule`](crate::schedule::Schedule) is still preferred for most cases
53
80
/// due to its better performance and abillity to run non-conflicting systems simultaneously.
54
- pub fn register_system < M , S : IntoSystem < ( ) , ( ) , M > + ' static > (
81
+ pub fn register_system < I : ' static , M , S : IntoSystem < I , ( ) , M > + ' static > (
55
82
& mut self ,
56
83
system : S ,
57
- ) -> SystemId {
84
+ ) -> SystemId < I > {
58
85
SystemId (
59
86
self . spawn ( RegisteredSystem {
60
87
initialized : false ,
61
88
system : Box :: new ( IntoSystem :: into_system ( system) ) ,
62
89
} )
63
90
. id ( ) ,
91
+ std:: marker:: PhantomData ,
64
92
)
65
93
}
66
94
@@ -70,11 +98,14 @@ impl World {
70
98
///
71
99
/// If no system corresponds to the given [`SystemId`], this method returns an error.
72
100
/// Systems are also not allowed to remove themselves, this returns an error too.
73
- pub fn remove_system ( & mut self , id : SystemId ) -> Result < RemovedSystem , RegisteredSystemError > {
101
+ pub fn remove_system < I : ' static > (
102
+ & mut self ,
103
+ id : SystemId < I > ,
104
+ ) -> Result < RemovedSystem < I > , RegisteredSystemError < I > > {
74
105
match self . get_entity_mut ( id. 0 ) {
75
106
Some ( mut entity) => {
76
107
let registered_system = entity
77
- . take :: < RegisteredSystem > ( )
108
+ . take :: < RegisteredSystem < I > > ( )
78
109
. ok_or ( RegisteredSystemError :: SelfRemove ( id) ) ?;
79
110
entity. despawn ( ) ;
80
111
Ok ( RemovedSystem {
@@ -92,9 +123,10 @@ impl World {
92
123
/// This is different from [`RunSystemOnce::run_system_once`](crate::system::RunSystemOnce::run_system_once),
93
124
/// because it keeps local state between calls and change detection works correctly.
94
125
///
126
+ /// In order to run a chained system with an input, use [`World::run_system_with_input`] instead.
127
+ ///
95
128
/// # Limitations
96
129
///
97
- /// - Stored systems cannot be chained: they can neither have an [`In`](crate::system::In) nor return any values.
98
130
/// - Stored systems cannot be recursive, they cannot call themselves through [`Commands::run_system`](crate::system::Commands).
99
131
/// - Exclusive systems cannot be used.
100
132
///
@@ -142,6 +174,44 @@ impl World {
142
174
/// let _ = world.run_system(detector); // -> Something happened!
143
175
/// ```
144
176
pub fn run_system ( & mut self , id : SystemId ) -> Result < ( ) , RegisteredSystemError > {
177
+ self . run_system_with_input ( id, ( ) )
178
+ }
179
+
180
+ /// Run a stored chained system by its [`SystemId`], providing an input value.
181
+ /// Before running a system, it must first be registered.
182
+ /// The method [`World::register_system`] stores a given system and returns a [`SystemId`].
183
+ ///
184
+ /// # Limitations
185
+ ///
186
+ /// - Stored systems cannot be recursive, they cannot call themselves through [`Commands::run_system`](crate::system::Commands).
187
+ /// - Exclusive systems cannot be used.
188
+ ///
189
+ /// # Examples
190
+ ///
191
+ /// ```rust
192
+ /// # use bevy_ecs::prelude::*;
193
+ /// #[derive(Resource, Default)]
194
+ /// struct Counter(u8);
195
+ ///
196
+ /// fn increment(In(increment_by): In<u8> mut counter: Local<Counter>) {
197
+ /// counter.0 += increment_by;
198
+ /// println!("{}", counter.0);
199
+ /// }
200
+ ///
201
+ /// let mut world = World::default();
202
+ /// let counter_one = world.register_system(increment);
203
+ /// let counter_two = world.register_system(increment);
204
+ /// world.run_system_with_input(counter_one, 1); // -> 1
205
+ /// world.run_system_with_input(counter_one, 20); // -> 21
206
+ /// world.run_system_with_input(counter_two, 30); // -> 51
207
+ /// ```
208
+ ///
209
+ /// See [`World::run_system`] for more examples.
210
+ pub fn run_system_with_input < I : ' static > (
211
+ & mut self ,
212
+ id : SystemId < I > ,
213
+ input : I ,
214
+ ) -> Result < ( ) , RegisteredSystemError < I > > {
145
215
// lookup
146
216
let mut entity = self
147
217
. get_entity_mut ( id. 0 )
@@ -152,20 +222,20 @@ impl World {
152
222
mut initialized,
153
223
mut system,
154
224
} = entity
155
- . take :: < RegisteredSystem > ( )
225
+ . take :: < RegisteredSystem < I > > ( )
156
226
. ok_or ( RegisteredSystemError :: Recursive ( id) ) ?;
157
227
158
228
// run the system
159
229
if !initialized {
160
230
system. initialize ( self ) ;
161
231
initialized = true ;
162
232
}
163
- system. run ( ( ) , self ) ;
233
+ system. run ( input , self ) ;
164
234
system. apply_deferred ( self ) ;
165
235
166
236
// return ownership of system trait object (if entity still exists)
167
237
if let Some ( mut entity) = self . get_entity_mut ( id. 0 ) {
168
- entity. insert :: < RegisteredSystem > ( RegisteredSystem {
238
+ entity. insert :: < RegisteredSystem < I > > ( RegisteredSystem {
169
239
initialized,
170
240
system,
171
241
} ) ;
@@ -198,19 +268,31 @@ impl Command for RunSystem {
198
268
}
199
269
200
270
/// An operation with stored systems failed.
201
- #[ derive( Debug , Error ) ]
202
- pub enum RegisteredSystemError {
271
+ #[ derive( Error ) ]
272
+ pub enum RegisteredSystemError < I = ( ) > {
203
273
/// A system was run by id, but no system with that id was found.
204
274
///
205
275
/// Did you forget to register it?
206
276
#[ error( "System {0:?} was not registered" ) ]
207
- SystemIdNotRegistered ( SystemId ) ,
277
+ SystemIdNotRegistered ( SystemId < I > ) ,
208
278
/// A system tried to run itself recursively.
209
279
#[ error( "System {0:?} tried to run itself recursively" ) ]
210
- Recursive ( SystemId ) ,
280
+ Recursive ( SystemId < I > ) ,
211
281
/// A system tried to remove itself.
212
282
#[ error( "System {0:?} tried to remove itself" ) ]
213
- SelfRemove ( SystemId ) ,
283
+ SelfRemove ( SystemId < I > ) ,
284
+ }
285
+
286
+ impl < I > std:: fmt:: Debug for RegisteredSystemError < I > {
287
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
288
+ match self {
289
+ Self :: SystemIdNotRegistered ( arg0) => {
290
+ f. debug_tuple ( "SystemIdNotRegistered" ) . field ( arg0) . finish ( )
291
+ }
292
+ Self :: Recursive ( arg0) => f. debug_tuple ( "Recursive" ) . field ( arg0) . finish ( ) ,
293
+ Self :: SelfRemove ( arg0) => f. debug_tuple ( "SelfRemove" ) . field ( arg0) . finish ( ) ,
294
+ }
295
+ }
214
296
}
215
297
216
298
mod tests {
@@ -240,14 +322,14 @@ mod tests {
240
322
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 0 ) ) ;
241
323
// Resources are changed when they are first added.
242
324
let id = world. register_system ( count_up_iff_changed) ;
243
- let _ = world. run_system ( id) ;
325
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
244
326
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
245
327
// Nothing changed
246
- let _ = world. run_system ( id) ;
328
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
247
329
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
248
330
// Making a change
249
331
world. resource_mut :: < ChangeDetector > ( ) . set_changed ( ) ;
250
- let _ = world. run_system ( id) ;
332
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
251
333
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 2 ) ) ;
252
334
}
253
335
@@ -263,16 +345,54 @@ mod tests {
263
345
world. insert_resource ( Counter ( 1 ) ) ;
264
346
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
265
347
let id = world. register_system ( doubling) ;
266
- let _ = world. run_system ( id) ;
348
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
267
349
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
268
- let _ = world. run_system ( id) ;
350
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
269
351
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 2 ) ) ;
270
- let _ = world. run_system ( id) ;
352
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
271
353
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 4 ) ) ;
272
- let _ = world. run_system ( id) ;
354
+ world. run_system ( id) . expect ( "system runs successfully" ) ;
273
355
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 8 ) ) ;
274
356
}
275
357
358
+ #[ test]
359
+ fn input_values ( ) {
360
+ // Verify that a non-Copy, non-Clone type can be passed in.
361
+ struct NonCopy ( u8 ) ;
362
+
363
+ fn increment_sys ( In ( NonCopy ( increment_by) ) : In < NonCopy > , mut counter : ResMut < Counter > ) {
364
+ counter. 0 += increment_by;
365
+ }
366
+
367
+ let mut world = World :: new ( ) ;
368
+
369
+ let id = world. register_system ( increment_sys) ;
370
+
371
+ // Insert the resource after registering the system.
372
+ world. insert_resource ( Counter ( 1 ) ) ;
373
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
374
+
375
+ world
376
+ . run_system_with_input ( id, NonCopy ( 1 ) )
377
+ . expect ( "system runs successfully" ) ;
378
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 2 ) ) ;
379
+
380
+ world
381
+ . run_system_with_input ( id, NonCopy ( 1 ) )
382
+ . expect ( "system runs successfully" ) ;
383
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 3 ) ) ;
384
+
385
+ world
386
+ . run_system_with_input ( id, NonCopy ( 20 ) )
387
+ . expect ( "system runs successfully" ) ;
388
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 23 ) ) ;
389
+
390
+ world
391
+ . run_system_with_input ( id, NonCopy ( 1 ) )
392
+ . expect ( "system runs successfully" ) ;
393
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 24 ) ) ;
394
+ }
395
+
276
396
#[ test]
277
397
fn nested_systems ( ) {
278
398
use crate :: system:: SystemId ;
0 commit comments