@@ -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 < I > {
10
+ struct RegisteredSystem < I , O > {
11
11
initialized : bool ,
12
- system : BoxedSystem < I > ,
12
+ system : BoxedSystem < I , O > ,
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 < I = ( ) > {
19
+ pub struct RemovedSystem < I = ( ) , O = ( ) > {
20
20
initialized : bool ,
21
- system : BoxedSystem < I > ,
21
+ system : BoxedSystem < I , O > ,
22
22
}
23
23
24
24
impl RemovedSystem {
@@ -39,29 +39,29 @@ impl RemovedSystem {
39
39
/// These are opaque identifiers, keyed to a specific [`World`],
40
40
/// and are created via [`World::register_system`].
41
41
#[ derive( Eq ) ]
42
- pub struct SystemId < I = ( ) > ( Entity , std:: marker:: PhantomData < I > ) ;
42
+ pub struct SystemId < I = ( ) , O = ( ) > ( Entity , std:: marker:: PhantomData < fn ( I ) -> O > ) ;
43
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 > {
44
+ // A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters .
45
+ impl < I , O > Copy for SystemId < I , O > { }
46
+ // A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters .
47
+ impl < I , O > Clone for SystemId < I , O > {
48
48
fn clone ( & self ) -> Self {
49
49
* self
50
50
}
51
51
}
52
- // A manual impl is used because the trait bounds should ignore the `I` phantom parameter .
53
- impl < I > PartialEq for SystemId < I > {
52
+ // A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters .
53
+ impl < I , O > PartialEq for SystemId < I , O > {
54
54
fn eq ( & self , other : & Self ) -> bool {
55
55
self . 0 == other. 0 && self . 1 == other. 1
56
56
}
57
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 > {
58
+ // A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters .
59
+ impl < I , O > std:: hash:: Hash for SystemId < I , O > {
60
60
fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
61
61
self . 0 . hash ( state) ;
62
62
}
63
63
}
64
- impl < I > std:: fmt:: Debug for SystemId < I > {
64
+ impl < I , O > std:: fmt:: Debug for SystemId < I , O > {
65
65
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
66
66
// The PhantomData field is omitted for simplicity.
67
67
f. debug_tuple ( "SystemId" ) . field ( & self . 0 ) . finish ( )
@@ -78,10 +78,10 @@ impl World {
78
78
/// This allows for running systems in a pushed-based fashion.
79
79
/// Using a [`Schedule`](crate::schedule::Schedule) is still preferred for most cases
80
80
/// due to its better performance and abillity to run non-conflicting systems simultaneously.
81
- pub fn register_system < I : ' static , M , S : IntoSystem < I , ( ) , M > + ' static > (
81
+ pub fn register_system < I : ' static , O : ' static , M , S : IntoSystem < I , O , M > + ' static > (
82
82
& mut self ,
83
83
system : S ,
84
- ) -> SystemId < I > {
84
+ ) -> SystemId < I , O > {
85
85
SystemId (
86
86
self . spawn ( RegisteredSystem {
87
87
initialized : false ,
@@ -98,14 +98,14 @@ impl World {
98
98
///
99
99
/// If no system corresponds to the given [`SystemId`], this method returns an error.
100
100
/// Systems are also not allowed to remove themselves, this returns an error too.
101
- pub fn remove_system < I : ' static > (
101
+ pub fn remove_system < I : ' static , O : ' static > (
102
102
& mut self ,
103
- id : SystemId < I > ,
104
- ) -> Result < RemovedSystem < I > , RegisteredSystemError < I > > {
103
+ id : SystemId < I , O > ,
104
+ ) -> Result < RemovedSystem < I , O > , RegisteredSystemError < I , O > > {
105
105
match self . get_entity_mut ( id. 0 ) {
106
106
Some ( mut entity) => {
107
107
let registered_system = entity
108
- . take :: < RegisteredSystem < I > > ( )
108
+ . take :: < RegisteredSystem < I , O > > ( )
109
109
. ok_or ( RegisteredSystemError :: SelfRemove ( id) ) ?;
110
110
entity. despawn ( ) ;
111
111
Ok ( RemovedSystem {
@@ -132,6 +132,8 @@ impl World {
132
132
///
133
133
/// # Examples
134
134
///
135
+ /// ## Running a system
136
+ ///
135
137
/// ```rust
136
138
/// # use bevy_ecs::prelude::*;
137
139
/// #[derive(Resource, Default)]
@@ -150,7 +152,7 @@ impl World {
150
152
/// world.run_system(counter_two); // -> 1
151
153
/// ```
152
154
///
153
- /// Change detection:
155
+ /// ## Change detection
154
156
///
155
157
/// ```rust
156
158
/// # use bevy_ecs::prelude::*;
@@ -173,7 +175,43 @@ impl World {
173
175
/// world.resource_mut::<ChangeDetector>().set_changed();
174
176
/// let _ = world.run_system(detector); // -> Something happened!
175
177
/// ```
176
- pub fn run_system ( & mut self , id : SystemId ) -> Result < ( ) , RegisteredSystemError > {
178
+ ///
179
+ /// ## Getting system output
180
+ ///
181
+ /// ```rust
182
+ /// # use bevy_ecs::prelude::*;
183
+ ///
184
+ /// #[derive(Resource)]
185
+ /// struct PlayerScore(i32);
186
+ ///
187
+ /// #[derive(Resource)]
188
+ /// struct OpponentScore(i32);
189
+ ///
190
+ /// fn get_player_score(player_score: Res<PlayerScore>) -> i32 {
191
+ /// player_score.0
192
+ /// }
193
+ ///
194
+ /// fn get_opponent_score(opponent_score: Res<OpponentScore>) -> i32 {
195
+ /// opponent_score.0
196
+ /// }
197
+ ///
198
+ /// let mut world = World::default();
199
+ /// world.insert_resource(PlayerScore(3));
200
+ /// world.insert_resource(OpponentScore(2));
201
+ ///
202
+ /// let scoring_systems = [
203
+ /// ("player", world.register_system(get_player_score)),
204
+ /// ("opponent", world.register_system(get_opponent_score)),
205
+ /// ];
206
+ ///
207
+ /// for (label, scoring_system) in scoring_systems {
208
+ /// println!("{label} has score {}", world.run_system(scoring_system).expect("system succeeded"));
209
+ /// }
210
+ /// ```
211
+ pub fn run_system < O : ' static > (
212
+ & mut self ,
213
+ id : SystemId < ( ) , O > ,
214
+ ) -> Result < O , RegisteredSystemError < ( ) , O > > {
177
215
self . run_system_with_input ( id, ( ) )
178
216
}
179
217
@@ -207,11 +245,11 @@ impl World {
207
245
/// ```
208
246
///
209
247
/// See [`World::run_system`] for more examples.
210
- pub fn run_system_with_input < I : ' static > (
248
+ pub fn run_system_with_input < I : ' static , O : ' static > (
211
249
& mut self ,
212
- id : SystemId < I > ,
250
+ id : SystemId < I , O > ,
213
251
input : I ,
214
- ) -> Result < ( ) , RegisteredSystemError < I > > {
252
+ ) -> Result < O , RegisteredSystemError < I , O > > {
215
253
// lookup
216
254
let mut entity = self
217
255
. get_entity_mut ( id. 0 )
@@ -222,25 +260,25 @@ impl World {
222
260
mut initialized,
223
261
mut system,
224
262
} = entity
225
- . take :: < RegisteredSystem < I > > ( )
263
+ . take :: < RegisteredSystem < I , O > > ( )
226
264
. ok_or ( RegisteredSystemError :: Recursive ( id) ) ?;
227
265
228
266
// run the system
229
267
if !initialized {
230
268
system. initialize ( self ) ;
231
269
initialized = true ;
232
270
}
233
- system. run ( input, self ) ;
271
+ let result = system. run ( input, self ) ;
234
272
system. apply_deferred ( self ) ;
235
273
236
274
// return ownership of system trait object (if entity still exists)
237
275
if let Some ( mut entity) = self . get_entity_mut ( id. 0 ) {
238
- entity. insert :: < RegisteredSystem < I > > ( RegisteredSystem {
276
+ entity. insert :: < RegisteredSystem < I , O > > ( RegisteredSystem {
239
277
initialized,
240
278
system,
241
279
} ) ;
242
280
}
243
- Ok ( ( ) )
281
+ Ok ( result )
244
282
}
245
283
}
246
284
@@ -269,21 +307,21 @@ impl Command for RunSystem {
269
307
270
308
/// An operation with stored systems failed.
271
309
#[ derive( Error ) ]
272
- pub enum RegisteredSystemError < I = ( ) > {
310
+ pub enum RegisteredSystemError < I = ( ) , O = ( ) > {
273
311
/// A system was run by id, but no system with that id was found.
274
312
///
275
313
/// Did you forget to register it?
276
314
#[ error( "System {0:?} was not registered" ) ]
277
- SystemIdNotRegistered ( SystemId < I > ) ,
315
+ SystemIdNotRegistered ( SystemId < I , O > ) ,
278
316
/// A system tried to run itself recursively.
279
317
#[ error( "System {0:?} tried to run itself recursively" ) ]
280
- Recursive ( SystemId < I > ) ,
318
+ Recursive ( SystemId < I , O > ) ,
281
319
/// A system tried to remove itself.
282
320
#[ error( "System {0:?} tried to remove itself" ) ]
283
- SelfRemove ( SystemId < I > ) ,
321
+ SelfRemove ( SystemId < I , O > ) ,
284
322
}
285
323
286
- impl < I > std:: fmt:: Debug for RegisteredSystemError < I > {
324
+ impl < I , O > std:: fmt:: Debug for RegisteredSystemError < I , O > {
287
325
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
288
326
match self {
289
327
Self :: SystemIdNotRegistered ( arg0) => {
@@ -393,6 +431,34 @@ mod tests {
393
431
assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 24 ) ) ;
394
432
}
395
433
434
+ #[ test]
435
+ fn output_values ( ) {
436
+ // Verify that a non-Copy, non-Clone type can be returned.
437
+ #[ derive( Eq , PartialEq , Debug ) ]
438
+ struct NonCopy ( u8 ) ;
439
+
440
+ fn increment_sys ( mut counter : ResMut < Counter > ) -> NonCopy {
441
+ counter. 0 += 1 ;
442
+ NonCopy ( counter. 0 )
443
+ }
444
+
445
+ let mut world = World :: new ( ) ;
446
+
447
+ let id = world. register_system ( increment_sys) ;
448
+
449
+ // Insert the resource after registering the system.
450
+ world. insert_resource ( Counter ( 1 ) ) ;
451
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
452
+
453
+ let output = world. run_system ( id) . expect ( "system runs successfully" ) ;
454
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 2 ) ) ;
455
+ assert_eq ! ( output, NonCopy ( 2 ) ) ;
456
+
457
+ let output = world. run_system ( id) . expect ( "system runs successfully" ) ;
458
+ assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 3 ) ) ;
459
+ assert_eq ! ( output, NonCopy ( 3 ) ) ;
460
+ }
461
+
396
462
#[ test]
397
463
fn nested_systems ( ) {
398
464
use crate :: system:: SystemId ;
0 commit comments