11use bevy_utils:: tracing:: warn;
22use core:: fmt:: Debug ;
3+ use thiserror:: Error ;
34
45use crate :: {
56 archetype:: ArchetypeComponentId ,
@@ -269,7 +270,7 @@ where
269270/// let mut world = World::default();
270271/// let entity = world.run_system_once(|mut commands: Commands| {
271272/// commands.spawn_empty().id()
272- /// });
273+ /// }).unwrap() ;
273274/// # assert!(world.get_entity(entity).is_some());
274275/// ```
275276///
@@ -289,7 +290,7 @@ where
289290/// world.spawn(T(1));
290291/// let count = world.run_system_once(|query: Query<&T>| {
291292/// query.iter().filter(|t| t.0 == 1).count()
292- /// });
293+ /// }).unwrap() ;
293294///
294295/// # assert_eq!(count, 2);
295296/// ```
@@ -311,25 +312,25 @@ where
311312/// world.spawn(T(0));
312313/// world.spawn(T(1));
313314/// world.spawn(T(1));
314- /// let count = world.run_system_once(count);
315+ /// let count = world.run_system_once(count).unwrap() ;
315316///
316317/// # assert_eq!(count, 2);
317318/// ```
318319pub trait RunSystemOnce : Sized {
319- /// Runs a system and applies its deferred parameters.
320- fn run_system_once < T , Out , Marker > ( self , system : T ) -> Out
320+ /// Tries to run a system and apply its deferred parameters.
321+ fn run_system_once < T , Out , Marker > ( self , system : T ) -> Result < Out , RunSystemError >
321322 where
322323 T : IntoSystem < ( ) , Out , Marker > ,
323324 {
324325 self . run_system_once_with ( ( ) , system)
325326 }
326327
327- /// Runs a system with given input and applies its deferred parameters.
328+ /// Tries to run a system with given input and apply deferred parameters.
328329 fn run_system_once_with < T , In , Out , Marker > (
329330 self ,
330331 input : SystemIn < ' _ , T :: System > ,
331332 system : T ,
332- ) -> Out
333+ ) -> Result < Out , RunSystemError >
333334 where
334335 T : IntoSystem < In , Out , Marker > ,
335336 In : SystemInput ;
@@ -340,14 +341,36 @@ impl RunSystemOnce for &mut World {
340341 self ,
341342 input : SystemIn < ' _ , T :: System > ,
342343 system : T ,
343- ) -> Out
344+ ) -> Result < Out , RunSystemError >
344345 where
345346 T : IntoSystem < In , Out , Marker > ,
346347 In : SystemInput ,
347348 {
348349 let mut system: T :: System = IntoSystem :: into_system ( system) ;
349350 system. initialize ( self ) ;
350- system. run ( input, self )
351+ if system. validate_param ( self ) {
352+ Ok ( system. run ( input, self ) )
353+ } else {
354+ Err ( RunSystemError :: InvalidParams ( system. name ( ) ) )
355+ }
356+ }
357+ }
358+
359+ /// Running system failed.
360+ #[ derive( Error ) ]
361+ pub enum RunSystemError {
362+ /// System could not be run due to parameters that failed validation.
363+ ///
364+ /// This can occur because the data required by the system was not present in the world.
365+ #[ error( "The data required by the system {0:?} was not found in the world and the system did not run due to failed parameter validation." ) ]
366+ InvalidParams ( Cow < ' static , str > ) ,
367+ }
368+
369+ impl Debug for RunSystemError {
370+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
371+ match self {
372+ Self :: InvalidParams ( arg0) => f. debug_tuple ( "InvalidParams" ) . field ( arg0) . finish ( ) ,
373+ }
351374 }
352375}
353376
@@ -369,7 +392,7 @@ mod tests {
369392 }
370393
371394 let mut world = World :: default ( ) ;
372- let n = world. run_system_once_with ( 1 , system) ;
395+ let n = world. run_system_once_with ( 1 , system) . unwrap ( ) ;
373396 assert_eq ! ( n, 2 ) ;
374397 assert_eq ! ( world. resource:: <T >( ) . 0 , 1 ) ;
375398 }
@@ -387,9 +410,9 @@ mod tests {
387410 let mut world = World :: new ( ) ;
388411 world. init_resource :: < Counter > ( ) ;
389412 assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 0 ) ) ;
390- world. run_system_once ( count_up) ;
413+ world. run_system_once ( count_up) . unwrap ( ) ;
391414 assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 1 ) ) ;
392- world. run_system_once ( count_up) ;
415+ world. run_system_once ( count_up) . unwrap ( ) ;
393416 assert_eq ! ( * world. resource:: <Counter >( ) , Counter ( 2 ) ) ;
394417 }
395418
@@ -402,7 +425,7 @@ mod tests {
402425 fn command_processing ( ) {
403426 let mut world = World :: new ( ) ;
404427 assert_eq ! ( world. entities. len( ) , 0 ) ;
405- world. run_system_once ( spawn_entity) ;
428+ world. run_system_once ( spawn_entity) . unwrap ( ) ;
406429 assert_eq ! ( world. entities. len( ) , 1 ) ;
407430 }
408431
@@ -415,7 +438,20 @@ mod tests {
415438 let mut world = World :: new ( ) ;
416439 world. insert_non_send_resource ( Counter ( 10 ) ) ;
417440 assert_eq ! ( * world. non_send_resource:: <Counter >( ) , Counter ( 10 ) ) ;
418- world. run_system_once ( non_send_count_down) ;
441+ world. run_system_once ( non_send_count_down) . unwrap ( ) ;
419442 assert_eq ! ( * world. non_send_resource:: <Counter >( ) , Counter ( 9 ) ) ;
420443 }
444+
445+ #[ test]
446+ fn run_system_once_invalid_params ( ) {
447+ struct T ;
448+ impl Resource for T { }
449+ fn system ( _: Res < T > ) { }
450+
451+ let mut world = World :: default ( ) ;
452+ // This fails because `T` has not been added to the world yet.
453+ let result = world. run_system_once ( system) ;
454+
455+ assert ! ( matches!( result, Err ( RunSystemError :: InvalidParams ( _) ) ) ) ;
456+ }
421457}
0 commit comments