1use std::ops::{Deref, DerefMut};
4
5use crate::callback::Callback;
6use crate::resource::{Res, ResMut};
7use crate::world::{Registry, ResourceId, World};
8
9pub trait SystemParam {
23 type State;
25
26 type Item<'w>;
28
29 fn init(registry: &Registry) -> Self::State;
35
36 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Self::State) -> Self::Item<'w>;
44
45 fn any_changed(state: &Self::State, world: &World) -> bool;
50
51 fn resource_id(state: &Self::State) -> Option<ResourceId> {
57 let _ = state;
58 None
59 }
60}
61
62impl<T: 'static> SystemParam for Res<'_, T> {
65 type State = ResourceId;
66 type Item<'w> = Res<'w, T>;
67
68 fn init(registry: &Registry) -> ResourceId {
69 registry.id::<T>()
70 }
71
72 #[inline(always)]
73 unsafe fn fetch<'w>(world: &'w World, state: &'w mut ResourceId) -> Res<'w, T> {
74 let id = *state;
75 unsafe {
78 Res::new(
79 world.get::<T>(id),
80 world.changed_at(id),
81 world.current_sequence(),
82 )
83 }
84 }
85
86 fn any_changed(state: &ResourceId, world: &World) -> bool {
87 unsafe { world.changed_at(*state) == world.current_sequence() }
89 }
90
91 fn resource_id(state: &ResourceId) -> Option<ResourceId> {
92 Some(*state)
93 }
94}
95
96impl<T: 'static> SystemParam for ResMut<'_, T> {
99 type State = ResourceId;
100 type Item<'w> = ResMut<'w, T>;
101
102 fn init(registry: &Registry) -> ResourceId {
103 registry.id::<T>()
104 }
105
106 #[inline(always)]
107 unsafe fn fetch<'w>(world: &'w World, state: &'w mut ResourceId) -> ResMut<'w, T> {
108 let id = *state;
109 unsafe {
112 ResMut::new(
113 world.get_mut::<T>(id),
114 world.changed_at_cell(id),
115 world.current_sequence(),
116 )
117 }
118 }
119
120 fn any_changed(state: &ResourceId, world: &World) -> bool {
121 unsafe { world.changed_at(*state) == world.current_sequence() }
123 }
124
125 fn resource_id(state: &ResourceId) -> Option<ResourceId> {
126 Some(*state)
127 }
128}
129
130impl<T: 'static> SystemParam for Option<Res<'_, T>> {
133 type State = Option<ResourceId>;
134 type Item<'w> = Option<Res<'w, T>>;
135
136 fn init(registry: &Registry) -> Option<ResourceId> {
137 registry.try_id::<T>()
138 }
139
140 #[inline(always)]
141 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Option<ResourceId>) -> Option<Res<'w, T>> {
142 state.map(|id| unsafe {
145 Res::new(
146 world.get::<T>(id),
147 world.changed_at(id),
148 world.current_sequence(),
149 )
150 })
151 }
152
153 fn any_changed(state: &Option<ResourceId>, world: &World) -> bool {
154 state.is_some_and(|id| {
155 unsafe { world.changed_at(id) == world.current_sequence() }
157 })
158 }
159
160 fn resource_id(state: &Option<ResourceId>) -> Option<ResourceId> {
161 *state
162 }
163}
164
165impl<T: 'static> SystemParam for Option<ResMut<'_, T>> {
168 type State = Option<ResourceId>;
169 type Item<'w> = Option<ResMut<'w, T>>;
170
171 fn init(registry: &Registry) -> Option<ResourceId> {
172 registry.try_id::<T>()
173 }
174
175 #[inline(always)]
176 unsafe fn fetch<'w>(
177 world: &'w World,
178 state: &'w mut Option<ResourceId>,
179 ) -> Option<ResMut<'w, T>> {
180 state.map(|id| unsafe {
183 ResMut::new(
184 world.get_mut::<T>(id),
185 world.changed_at_cell(id),
186 world.current_sequence(),
187 )
188 })
189 }
190
191 fn any_changed(state: &Option<ResourceId>, world: &World) -> bool {
192 state.is_some_and(|id| {
193 unsafe { world.changed_at(id) == world.current_sequence() }
195 })
196 }
197
198 fn resource_id(state: &Option<ResourceId>) -> Option<ResourceId> {
199 *state
200 }
201}
202
203impl SystemParam for () {
209 type State = ();
210 type Item<'w> = ();
211
212 fn init(_registry: &Registry) {}
213
214 #[inline(always)]
215 unsafe fn fetch<'w>(_world: &'w World, _state: &'w mut ()) {}
216
217 fn any_changed(_state: &(), _world: &World) -> bool {
218 false
219 }
220}
221
222macro_rules! impl_system_param_tuple {
223 ($($P:ident),+) => {
224 impl<$($P: SystemParam),+> SystemParam for ($($P,)+) {
225 type State = ($($P::State,)+);
226 type Item<'w> = ($($P::Item<'w>,)+);
227
228 fn init(registry: &Registry) -> Self::State {
229 ($($P::init(registry),)+)
230 }
231
232 #[inline(always)]
233 #[allow(non_snake_case)]
234 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Self::State) -> Self::Item<'w> {
235 let ($($P,)+) = state;
236 unsafe { ($($P::fetch(world, $P),)+) }
238 }
239
240 #[allow(non_snake_case)]
241 fn any_changed(state: &Self::State, world: &World) -> bool {
242 let ($($P,)+) = state;
243 $($P::any_changed($P, world))||+
244 }
245 }
246 };
247}
248
249macro_rules! all_tuples {
250 ($m:ident) => {
251 $m!(P0);
252 $m!(P0, P1);
253 $m!(P0, P1, P2);
254 $m!(P0, P1, P2, P3);
255 $m!(P0, P1, P2, P3, P4);
256 $m!(P0, P1, P2, P3, P4, P5);
257 $m!(P0, P1, P2, P3, P4, P5, P6);
258 $m!(P0, P1, P2, P3, P4, P5, P6, P7);
259 };
260}
261
262all_tuples!(impl_system_param_tuple);
263
264pub struct Local<'s, T: Default + 'static> {
284 value: &'s mut T,
285}
286
287impl<'s, T: Default + 'static> Local<'s, T> {
288 pub(crate) fn new(value: &'s mut T) -> Self {
289 Self { value }
290 }
291}
292
293impl<T: Default + 'static> Deref for Local<'_, T> {
294 type Target = T;
295
296 #[inline(always)]
297 fn deref(&self) -> &T {
298 self.value
299 }
300}
301
302impl<T: Default + 'static> DerefMut for Local<'_, T> {
303 #[inline(always)]
304 fn deref_mut(&mut self) -> &mut T {
305 self.value
306 }
307}
308
309impl<T: Default + 'static> SystemParam for Local<'_, T> {
310 type State = T;
311 type Item<'s> = Local<'s, T>;
312
313 fn init(_registry: &Registry) -> T {
314 T::default()
315 }
316
317 #[inline(always)]
318 unsafe fn fetch<'s>(_world: &'s World, state: &'s mut T) -> Local<'s, T> {
319 Local::new(state)
323 }
324
325 fn any_changed(_state: &T, _world: &World) -> bool {
326 false
328 }
329}
330
331pub trait Handler<E> {
343 fn run(&mut self, world: &mut World, event: E);
345
346 fn inputs_changed(&self, world: &World) -> bool {
351 let _ = world;
352 true
353 }
354
355 fn name(&self) -> &'static str {
360 "<unnamed>"
361 }
362}
363
364#[doc(hidden)]
378pub struct CtxFree<F>(pub(crate) F);
379
380pub type HandlerFn<F, Params> = Callback<(), CtxFree<F>, Params>;
385
386pub trait IntoHandler<E, Params> {
419 type Handler: Handler<E> + 'static;
421
422 fn into_handler(self, registry: &mut Registry) -> Self::Handler;
424}
425
426impl<E, F: FnMut(E) + 'static> IntoHandler<E, ()> for F {
432 type Handler = Callback<(), CtxFree<F>, ()>;
433
434 fn into_handler(self, registry: &mut Registry) -> Self::Handler {
435 Callback {
436 ctx: (),
437 f: CtxFree(self),
438 state: <() as SystemParam>::init(registry),
439 name: std::any::type_name::<F>(),
440 }
441 }
442}
443
444impl<E, F: FnMut(E) + 'static> Handler<E> for Callback<(), CtxFree<F>, ()> {
445 fn run(&mut self, _world: &mut World, event: E) {
446 (self.f.0)(event);
447 }
448
449 fn inputs_changed(&self, _world: &World) -> bool {
450 true
453 }
454
455 fn name(&self) -> &'static str {
456 self.name
457 }
458}
459
460macro_rules! impl_into_handler {
461 ($($P:ident),+) => {
462 impl<E, F: 'static, $($P: SystemParam + 'static),+> IntoHandler<E, ($($P,)+)> for F
463 where
464 for<'a> &'a mut F: FnMut($($P,)+ E) + FnMut($($P::Item<'a>,)+ E),
471 {
472 type Handler = Callback<(), CtxFree<F>, ($($P,)+)>;
473
474 fn into_handler(self, registry: &mut Registry) -> Self::Handler {
475 let state = <($($P,)+) as SystemParam>::init(registry);
476 {
477 #[allow(non_snake_case)]
478 let ($($P,)+) = &state;
479 registry.check_access(&[
480 $(
481 (<$P as SystemParam>::resource_id($P),
482 std::any::type_name::<$P>()),
483 )+
484 ]);
485 }
486 Callback {
487 ctx: (),
488 f: CtxFree(self),
489 state,
490 name: std::any::type_name::<F>(),
491 }
492 }
493 }
494
495 impl<E, F: 'static, $($P: SystemParam + 'static),+> Handler<E>
496 for Callback<(), CtxFree<F>, ($($P,)+)>
497 where
498 for<'a> &'a mut F: FnMut($($P,)+ E) + FnMut($($P::Item<'a>,)+ E),
499 {
500 #[allow(non_snake_case)]
501 fn run(&mut self, world: &mut World, event: E) {
502 #[allow(clippy::too_many_arguments)]
504 fn call_inner<$($P,)+ Ev>(
505 mut f: impl FnMut($($P,)+ Ev),
506 $($P: $P,)+
507 event: Ev,
508 ) {
509 f($($P,)+ event);
510 }
511
512 let ($($P,)+) = unsafe {
516 <($($P,)+) as SystemParam>::fetch(world, &mut self.state)
517 };
518 call_inner(&mut self.f.0, $($P,)+ event);
519 }
520
521 fn inputs_changed(&self, world: &World) -> bool {
522 <($($P,)+) as SystemParam>::any_changed(&self.state, world)
523 }
524
525 fn name(&self) -> &'static str {
526 self.name
527 }
528 }
529 };
530}
531
532all_tuples!(impl_into_handler);
533
534#[cfg(test)]
539mod tests {
540 use super::*;
541 use crate::WorldBuilder;
542
543 #[test]
546 fn res_system_param() {
547 let mut builder = WorldBuilder::new();
548 builder.register::<u64>(42);
549 let mut world = builder.build();
550
551 let mut state = <Res<u64> as SystemParam>::init(world.registry_mut());
552 let res = unsafe { <Res<u64> as SystemParam>::fetch(&world, &mut state) };
554 assert_eq!(*res, 42);
555 }
556
557 #[test]
558 fn res_mut_system_param() {
559 let mut builder = WorldBuilder::new();
560 builder.register::<u64>(1);
561 let mut world = builder.build();
562
563 let mut state = <ResMut<u64> as SystemParam>::init(world.registry_mut());
564 unsafe {
566 let mut res = <ResMut<u64> as SystemParam>::fetch(&world, &mut state);
567 *res = 99;
568 }
569 unsafe {
570 let mut read_state = <Res<u64> as SystemParam>::init(world.registry_mut());
571 let res = <Res<u64> as SystemParam>::fetch(&world, &mut read_state);
572 assert_eq!(*res, 99);
573 }
574 }
575
576 #[test]
577 fn tuple_system_param() {
578 let mut builder = WorldBuilder::new();
579 builder.register::<u64>(10).register::<bool>(true);
580 let mut world = builder.build();
581
582 let mut state = <(Res<u64>, ResMut<bool>) as SystemParam>::init(world.registry_mut());
583 unsafe {
585 let (counter, mut flag) =
586 <(Res<u64>, ResMut<bool>) as SystemParam>::fetch(&world, &mut state);
587 assert_eq!(*counter, 10);
588 assert!(*flag);
589 *flag = false;
590 }
591 unsafe {
592 let mut read_state = <Res<bool> as SystemParam>::init(world.registry_mut());
593 let res = <Res<bool> as SystemParam>::fetch(&world, &mut read_state);
594 assert!(!*res);
595 }
596 }
597
598 #[test]
599 fn empty_tuple_param() {
600 let mut world = WorldBuilder::new().build();
601 let mut state = <() as SystemParam>::init(world.registry_mut());
602 let () = unsafe { <() as SystemParam>::fetch(&world, &mut state) };
604 }
605
606 fn event_only_handler(event: u32) {
609 assert_eq!(event, 42);
610 }
611
612 #[test]
613 fn event_only_system() {
614 let mut world = WorldBuilder::new().build();
615 let mut sys = event_only_handler.into_handler(world.registry_mut());
616 sys.run(&mut world, 42u32);
617 }
618
619 fn one_res_handler(counter: Res<u64>, event: u32) {
620 assert_eq!(*counter, 10);
621 assert_eq!(event, 5);
622 }
623
624 #[test]
625 fn one_res_and_event() {
626 let mut builder = WorldBuilder::new();
627 builder.register::<u64>(10);
628 let mut world = builder.build();
629
630 let mut sys = one_res_handler.into_handler(world.registry_mut());
631 sys.run(&mut world, 5u32);
632 }
633
634 fn two_res_handler(counter: Res<u64>, flag: Res<bool>, event: u32) {
635 assert_eq!(*counter, 10);
636 assert!(*flag);
637 assert_eq!(event, 7);
638 }
639
640 #[test]
641 fn two_res_and_event() {
642 let mut builder = WorldBuilder::new();
643 builder.register::<u64>(10).register::<bool>(true);
644 let mut world = builder.build();
645
646 let mut sys = two_res_handler.into_handler(world.registry_mut());
647 sys.run(&mut world, 7u32);
648 }
649
650 fn accumulate(mut counter: ResMut<u64>, event: u64) {
651 *counter += event;
652 }
653
654 #[test]
655 fn mutation_through_res_mut() {
656 let mut builder = WorldBuilder::new();
657 builder.register::<u64>(0);
658 let mut world = builder.build();
659
660 let mut sys = accumulate.into_handler(world.registry_mut());
661
662 sys.run(&mut world, 10u64);
663 sys.run(&mut world, 5u64);
664
665 assert_eq!(*world.resource::<u64>(), 15);
666 }
667
668 fn add_handler(mut counter: ResMut<u64>, event: u64) {
669 *counter += event;
670 }
671
672 fn mul_handler(mut counter: ResMut<u64>, event: u64) {
673 *counter *= event;
674 }
675
676 #[test]
677 fn box_dyn_type_erasure() {
678 let mut builder = WorldBuilder::new();
679 builder.register::<u64>(0);
680 let mut world = builder.build();
681
682 let sys_a = add_handler.into_handler(world.registry_mut());
683 let sys_b = mul_handler.into_handler(world.registry_mut());
684
685 let mut handlers: Vec<Box<dyn Handler<u64>>> = vec![Box::new(sys_a), Box::new(sys_b)];
686
687 for h in handlers.iter_mut() {
688 h.run(&mut world, 3u64);
689 }
690 assert_eq!(*world.resource::<u64>(), 9);
692 }
693
694 fn local_counter(mut count: Local<u64>, _event: u32) {
697 *count += 1;
698 }
699
700 #[test]
701 fn local_default_init() {
702 let mut world = WorldBuilder::new().build();
703 let mut sys = local_counter.into_handler(world.registry_mut());
704 sys.run(&mut world, 1u32);
706 }
707
708 #[test]
709 fn local_persists_across_runs() {
710 let mut builder = WorldBuilder::new();
711 builder.register::<u64>(0);
712 let mut world = builder.build();
713
714 fn accumulate_local(mut count: Local<u64>, mut total: ResMut<u64>, _event: u32) {
715 *count += 1;
716 *total = *count;
717 }
718
719 let mut sys = accumulate_local.into_handler(world.registry_mut());
720 sys.run(&mut world, 0u32);
721 sys.run(&mut world, 0u32);
722 sys.run(&mut world, 0u32);
723
724 assert_eq!(*world.resource::<u64>(), 3);
725 }
726
727 #[test]
728 fn local_independent_per_system() {
729 let mut builder = WorldBuilder::new();
730 builder.register::<u64>(0);
731 let mut world = builder.build();
732
733 fn inc_local(mut count: Local<u64>, mut total: ResMut<u64>, _event: u32) {
734 *count += 1;
735 *total += *count;
736 }
737
738 let mut sys_a = inc_local.into_handler(world.registry_mut());
739 let mut sys_b = inc_local.into_handler(world.registry_mut());
740
741 sys_a.run(&mut world, 0u32); sys_b.run(&mut world, 0u32); sys_a.run(&mut world, 0u32); assert_eq!(*world.resource::<u64>(), 4);
746 }
747
748 #[test]
751 fn option_res_none_when_missing() {
752 let mut world = WorldBuilder::new().build();
753 let mut state = <Option<Res<u64>> as SystemParam>::init(world.registry_mut());
754 let opt = unsafe { <Option<Res<u64>> as SystemParam>::fetch(&world, &mut state) };
755 assert!(opt.is_none());
756 }
757
758 #[test]
759 fn option_res_some_when_present() {
760 let mut builder = WorldBuilder::new();
761 builder.register::<u64>(42);
762 let mut world = builder.build();
763
764 let mut state = <Option<Res<u64>> as SystemParam>::init(world.registry_mut());
765 let opt = unsafe { <Option<Res<u64>> as SystemParam>::fetch(&world, &mut state) };
766 assert_eq!(*opt.unwrap(), 42);
767 }
768
769 #[test]
770 fn option_res_mut_some_when_present() {
771 let mut builder = WorldBuilder::new();
772 builder.register::<u64>(1);
773 let mut world = builder.build();
774
775 let mut state = <Option<ResMut<u64>> as SystemParam>::init(world.registry_mut());
776 unsafe {
777 let opt = <Option<ResMut<u64>> as SystemParam>::fetch(&world, &mut state);
778 *opt.unwrap() = 99;
779 }
780 unsafe {
781 let mut read_state = <Res<u64> as SystemParam>::init(world.registry_mut());
782 let res = <Res<u64> as SystemParam>::fetch(&world, &mut read_state);
783 assert_eq!(*res, 99);
784 }
785 }
786
787 fn optional_handler(opt: Option<Res<String>>, _event: u32) {
788 assert!(opt.is_none());
789 }
790
791 #[test]
792 fn option_in_handler() {
793 let mut world = WorldBuilder::new().build();
794 let mut sys = optional_handler.into_handler(world.registry_mut());
795 sys.run(&mut world, 0u32);
796 }
797
798 #[test]
801 fn inputs_changed_true_when_resource_stamped() {
802 let mut builder = WorldBuilder::new();
803 builder.register::<u64>(0);
804 let mut world = builder.build();
805
806 fn reader(val: Res<u64>, _e: ()) {
807 let _ = *val;
808 }
809
810 let sys = reader.into_handler(world.registry_mut());
811
812 assert!(sys.inputs_changed(&world));
814
815 world.next_sequence(); assert!(!sys.inputs_changed(&world));
819
820 *world.resource_mut::<u64>() = 42;
822 assert!(sys.inputs_changed(&world));
823 }
824
825 #[test]
826 fn inputs_changed_false_when_not_stamped() {
827 let mut builder = WorldBuilder::new();
828 builder.register::<u64>(0).register::<bool>(false);
829 let mut world = builder.build();
830
831 fn reads_bool(flag: Res<bool>, _e: ()) {
832 let _ = *flag;
833 }
834
835 let sys = reads_bool.into_handler(world.registry_mut());
836
837 world.next_sequence(); *world.resource_mut::<u64>() = 42;
841
842 assert!(!sys.inputs_changed(&world));
844 }
845
846 #[test]
847 fn inputs_changed_with_optional_none() {
848 let mut world = WorldBuilder::new().build();
850
851 fn optional_sys(opt: Option<Res<String>>, _e: ()) {
852 let _ = opt;
853 }
854
855 let sys = optional_sys.into_handler(world.registry_mut());
856 assert!(!sys.inputs_changed(&world));
857 }
858
859 #[test]
860 fn inputs_changed_event_only_handler() {
861 let mut world = WorldBuilder::new().build();
862
863 fn event_handler(_e: u32) {}
864
865 let sys = event_handler.into_handler(world.registry_mut());
866 assert!(sys.inputs_changed(&world));
868 }
869
870 #[test]
873 #[should_panic(expected = "conflicting access")]
874 fn duplicate_res_panics() {
875 let mut builder = WorldBuilder::new();
876 builder.register::<u64>(0);
877 let mut world = builder.build();
878
879 fn bad(a: Res<u64>, b: Res<u64>, _e: ()) {
880 let _ = (*a, *b);
881 }
882
883 let _sys = bad.into_handler(world.registry_mut());
884 }
885
886 #[test]
887 #[should_panic(expected = "conflicting access")]
888 fn duplicate_res_mut_panics() {
889 let mut builder = WorldBuilder::new();
890 builder.register::<u64>(0);
891 let mut world = builder.build();
892
893 fn bad(a: ResMut<u64>, b: ResMut<u64>, _e: ()) {
894 let _ = (&*a, &*b);
895 }
896
897 let _sys = bad.into_handler(world.registry_mut());
898 }
899
900 #[test]
901 #[should_panic(expected = "conflicting access")]
902 fn duplicate_mixed_panics() {
903 let mut builder = WorldBuilder::new();
904 builder.register::<u64>(0);
905 let mut world = builder.build();
906
907 fn bad(a: Res<u64>, b: ResMut<u64>, _e: ()) {
908 let _ = (*a, &*b);
909 }
910
911 let _sys = bad.into_handler(world.registry_mut());
912 }
913
914 #[test]
915 fn different_types_no_conflict() {
916 let mut builder = WorldBuilder::new();
917 builder.register::<u64>(0);
918 builder.register::<u32>(0);
919 let mut world = builder.build();
920
921 fn ok(a: Res<u64>, b: ResMut<u32>, _e: ()) {
922 let _ = (*a, &*b);
923 }
924
925 let _sys = ok.into_handler(world.registry_mut());
926 }
927
928 #[test]
929 fn local_no_conflict() {
930 let mut builder = WorldBuilder::new();
931 builder.register::<u64>(0);
932 let mut world = builder.build();
933
934 fn ok(local: Local<u64>, val: ResMut<u64>, _e: ()) {
935 let _ = (&*local, &*val);
936 }
937
938 let _sys = ok.into_handler(world.registry_mut());
939 }
940
941 #[test]
942 fn end_to_end_change_detection() {
943 let mut builder = WorldBuilder::new();
944 builder.register::<u64>(0).register::<bool>(false);
945 let mut world = builder.build();
946
947 fn writer(mut val: ResMut<u64>, _e: ()) {
949 *val = 42;
950 }
951 fn observer(val: Res<u64>, flag: Res<bool>, _e: ()) {
952 let _ = (*val, *flag);
955 }
956
957 let mut writer_sys = writer.into_handler(world.registry_mut());
958 let mut observer_sys = observer.into_handler(world.registry_mut());
959
960 writer_sys.run(&mut world, ());
962 observer_sys.run(&mut world, ());
963
964 world.next_sequence(); writer_sys.run(&mut world, ());
969
970 let u64_id = world.id::<u64>();
971 let bool_id = world.id::<bool>();
972 unsafe {
973 assert_eq!(world.changed_at(u64_id), world.current_sequence());
974 assert_ne!(world.changed_at(bool_id), world.current_sequence());
975 }
976 }
977}