@@ -7,7 +7,7 @@ use crate::{
7
7
schedule:: SystemLabel ,
8
8
system:: {
9
9
check_system_change_tick, ReadOnlySystemParamFetch , System , SystemParam , SystemParamFetch ,
10
- SystemParamState ,
10
+ SystemParamItem , SystemParamState ,
11
11
} ,
12
12
world:: { World , WorldId } ,
13
13
} ;
@@ -346,6 +346,16 @@ where
346
346
}
347
347
}
348
348
349
+ impl < In , Out , Param , Marker , F > FunctionSystem < In , Out , Param , Marker , F >
350
+ where
351
+ Param : SystemParam ,
352
+ {
353
+ /// Message shown when a system isn't initialised
354
+ // When lines get too long, rustfmt can sometimes refuse to format them.
355
+ // Work around this by storing the message separately.
356
+ const PARAM_MESSAGE : & ' static str = "System's param_state was not found. Did you forget to initialize this system before running it?" ;
357
+ }
358
+
349
359
impl < In , Out , Param , Marker , F > System for FunctionSystem < In , Out , Param , Marker , F >
350
360
where
351
361
In : ' static ,
@@ -380,20 +390,25 @@ where
380
390
#[ inline]
381
391
unsafe fn run_unsafe ( & mut self , input : Self :: In , world : & World ) -> Self :: Out {
382
392
let change_tick = world. increment_change_tick ( ) ;
383
- let out = self . func . run (
384
- input,
385
- self . param_state . as_mut ( ) . expect ( "System's param_state was not found. Did you forget to initialize this system before running it?" ) ,
393
+
394
+ // Safety:
395
+ // We update the archetype component access correctly based on `Param`'s requirements
396
+ // in `update_archetype_component_access`.
397
+ // Our caller upholds the requirements.
398
+ let params = <Param as SystemParam >:: Fetch :: get_param (
399
+ self . param_state . as_mut ( ) . expect ( Self :: PARAM_MESSAGE ) ,
386
400
& self . system_meta ,
387
401
world,
388
402
change_tick,
389
403
) ;
404
+ let out = self . func . run ( input, params) ;
390
405
self . system_meta . last_change_tick = change_tick;
391
406
out
392
407
}
393
408
394
409
#[ inline]
395
410
fn apply_buffers ( & mut self , world : & mut World ) {
396
- let param_state = self . param_state . as_mut ( ) . expect ( "System's param_state was not found. Did you forget to initialize this system before running it?" ) ;
411
+ let param_state = self . param_state . as_mut ( ) . expect ( Self :: PARAM_MESSAGE ) ;
397
412
param_state. apply ( world) ;
398
413
}
399
414
@@ -474,19 +489,71 @@ impl<T> SystemLabel for SystemTypeIdLabel<T> {
474
489
}
475
490
476
491
/// A trait implemented for all functions that can be used as [`System`]s.
492
+ ///
493
+ /// This trait can be useful for making your own systems which accept other systems,
494
+ /// sometimes called higher order systems.
495
+ ///
496
+ /// This should be used in combination with [`ParamSet`] when calling other systems
497
+ /// within your system.
498
+ /// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.
499
+ ///
500
+ /// # Example
501
+ ///
502
+ /// To create something like [`ChainSystem`], but in entirely safe code.
503
+ ///
504
+ /// ```rust
505
+ /// use std::num::ParseIntError;
506
+ ///
507
+ /// use bevy_ecs::prelude::*;
508
+ /// use bevy_ecs::system::{SystemParam, SystemParamItem};
509
+ ///
510
+ /// // Unfortunately, we need all of these generics. `A` is the first system, with its
511
+ /// // parameters and marker type required for coherence. `B` is the second system, and
512
+ /// // the other generics are for the input/output types of A and B.
513
+ /// /// Chain creates a new system which calls `a`, then calls `b` with the output of `a`
514
+ /// pub fn chain<AIn, Shared, BOut, A, AParam, AMarker, B, BParam, BMarker>(
515
+ /// mut a: A,
516
+ /// mut b: B,
517
+ /// ) -> impl FnMut(In<AIn>, ParamSet<(SystemParamItem<AParam>, SystemParamItem<BParam>)>) -> BOut
518
+ /// where
519
+ /// // We need A and B to be systems, add those bounds
520
+ /// A: SystemParamFunction<AIn, Shared, AParam, AMarker>,
521
+ /// B: SystemParamFunction<Shared, BOut, BParam, BMarker>,
522
+ /// AParam: SystemParam,
523
+ /// BParam: SystemParam,
524
+ /// {
525
+ /// // The type of `params` is inferred based on the return of this function above
526
+ /// move |In(a_in), mut params| {
527
+ /// let shared = a.run(a_in, params.p0());
528
+ /// b.run(shared, params.p1())
529
+ /// }
530
+ /// }
531
+ ///
532
+ /// // Usage example for `chain`:
533
+ /// fn main() {
534
+ /// let mut world = World::default();
535
+ /// world.insert_resource(Message("42".to_string()));
536
+ ///
537
+ /// // chain the `parse_message_system`'s output into the `filter_system`s input
538
+ /// let mut chained_system = IntoSystem::into_system(chain(parse_message, filter));
539
+ /// chained_system.initialize(&mut world);
540
+ /// assert_eq!(chained_system.run((), &mut world), Some(42));
541
+ /// }
542
+ ///
543
+ /// struct Message(String);
544
+ ///
545
+ /// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
546
+ /// message.0.parse::<usize>()
547
+ /// }
548
+ ///
549
+ /// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
550
+ /// result.ok().filter(|&n| n < 100)
551
+ /// }
552
+ /// ```
553
+ /// [`ChainSystem`]: crate::system::ChainSystem
554
+ /// [`ParamSet`]: crate::system::ParamSet
477
555
pub trait SystemParamFunction < In , Out , Param : SystemParam , Marker > : Send + Sync + ' static {
478
- /// # Safety
479
- ///
480
- /// This call might access any of the input parameters in an unsafe way. Make sure the data
481
- /// access is safe in the context of the system scheduler.
482
- unsafe fn run (
483
- & mut self ,
484
- input : In ,
485
- state : & mut Param :: Fetch ,
486
- system_meta : & SystemMeta ,
487
- world : & World ,
488
- change_tick : u32 ,
489
- ) -> Out ;
556
+ fn run ( & mut self , input : In , param_value : SystemParamItem < Param > ) -> Out ;
490
557
}
491
558
492
559
macro_rules! impl_system_function {
@@ -496,20 +563,21 @@ macro_rules! impl_system_function {
496
563
where
497
564
for <' a> & ' a mut Func :
498
565
FnMut ( $( $param) ,* ) -> Out +
499
- FnMut ( $( << $param as SystemParam > :: Fetch as SystemParamFetch > :: Item ) ,* ) -> Out , Out : ' static
566
+ FnMut ( $( SystemParamItem < $param> ) ,* ) -> Out , Out : ' static
500
567
{
501
568
#[ inline]
502
- unsafe fn run( & mut self , _input: ( ) , state: & mut <( $( $param, ) * ) as SystemParam >:: Fetch , system_meta: & SystemMeta , world: & World , change_tick: u32 ) -> Out {
503
- // Yes, this is strange, but rustc fails to compile this impl
504
- // without using this function.
569
+ fn run( & mut self , _input: ( ) , param_value: SystemParamItem < ( $( $param, ) * ) >) -> Out {
570
+ // Yes, this is strange, but `rustc` fails to compile this impl
571
+ // without using this function. It fails to recognise that `func`
572
+ // is a function, potentially because of the multiple impls of `FnMut`
505
573
#[ allow( clippy:: too_many_arguments) ]
506
574
fn call_inner<Out , $( $param, ) * >(
507
575
mut f: impl FnMut ( $( $param, ) * ) ->Out ,
508
576
$( $param: $param, ) *
509
577
) ->Out {
510
578
f( $( $param, ) * )
511
579
}
512
- let ( $( $param, ) * ) = << ( $ ( $param , ) * ) as SystemParam > :: Fetch as SystemParamFetch > :: get_param ( state , system_meta , world , change_tick ) ;
580
+ let ( $( $param, ) * ) = param_value ;
513
581
call_inner( self , $( $param) ,* )
514
582
}
515
583
}
@@ -522,7 +590,7 @@ macro_rules! impl_system_function {
522
590
FnMut ( In <Input >, $( <<$param as SystemParam >:: Fetch as SystemParamFetch >:: Item ) ,* ) -> Out , Out : ' static
523
591
{
524
592
#[ inline]
525
- unsafe fn run( & mut self , input: Input , state : & mut < ( $( $param, ) * ) as SystemParam > :: Fetch , system_meta : & SystemMeta , world : & World , change_tick : u32 ) -> Out {
593
+ fn run( & mut self , input: Input , param_value : SystemParamItem < ( $( $param, ) * ) > ) -> Out {
526
594
#[ allow( clippy:: too_many_arguments) ]
527
595
fn call_inner<Input , Out , $( $param, ) * >(
528
596
mut f: impl FnMut ( In <Input >, $( $param, ) * ) ->Out ,
@@ -531,13 +599,15 @@ macro_rules! impl_system_function {
531
599
) ->Out {
532
600
f( input, $( $param, ) * )
533
601
}
534
- let ( $( $param, ) * ) = << ( $ ( $param , ) * ) as SystemParam > :: Fetch as SystemParamFetch > :: get_param ( state , system_meta , world , change_tick ) ;
602
+ let ( $( $param, ) * ) = param_value ;
535
603
call_inner( self , In ( input) , $( $param) ,* )
536
604
}
537
605
}
538
606
} ;
539
607
}
540
608
609
+ // Note that we rely on the highest impl to be <= the highest order of the tuple impls
610
+ // of `SystemParam` created.
541
611
all_tuples ! ( impl_system_function, 0 , 16 , F ) ;
542
612
543
613
/// Used to implicitly convert systems to their default labels. For example, it will convert
0 commit comments