1use std::ops::{Deref, DerefMut};
4
5use crate::Resource;
6use crate::callback::Callback;
7use crate::resource::{Res, ResMut, Seq, SeqMut};
8use crate::shutdown::Shutdown;
9use crate::world::{Registry, ResourceId, World};
10
11pub trait Param {
41 type State: Send;
47
48 type Item<'w>;
50
51 fn init(registry: &Registry) -> Self::State;
57
58 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Self::State) -> Self::Item<'w>;
66
67 fn resource_id(state: &Self::State) -> Option<ResourceId> {
73 let _ = state;
74 None
75 }
76}
77
78impl<T: Resource> Param for Res<'_, T> {
81 type State = ResourceId;
82 type Item<'w> = Res<'w, T>;
83
84 fn init(registry: &Registry) -> ResourceId {
85 registry.id::<T>()
86 }
87
88 #[inline(always)]
89 unsafe fn fetch<'w>(world: &'w World, state: &'w mut ResourceId) -> Res<'w, T> {
90 let id = *state;
91 #[cfg(debug_assertions)]
92 world.track_borrow(id);
93 unsafe { Res::new(world.get::<T>(id)) }
96 }
97
98 fn resource_id(state: &ResourceId) -> Option<ResourceId> {
99 Some(*state)
100 }
101}
102
103impl<T: Resource> Param for ResMut<'_, T> {
106 type State = ResourceId;
107 type Item<'w> = ResMut<'w, T>;
108
109 fn init(registry: &Registry) -> ResourceId {
110 registry.id::<T>()
111 }
112
113 #[inline(always)]
114 unsafe fn fetch<'w>(world: &'w World, state: &'w mut ResourceId) -> ResMut<'w, T> {
115 let id = *state;
116 #[cfg(debug_assertions)]
117 world.track_borrow(id);
118 unsafe { ResMut::new(world.get_mut::<T>(id)) }
121 }
122
123 fn resource_id(state: &ResourceId) -> Option<ResourceId> {
124 Some(*state)
125 }
126}
127
128impl<T: Resource> Param for Option<Res<'_, T>> {
131 type State = Option<ResourceId>;
132 type Item<'w> = Option<Res<'w, T>>;
133
134 fn init(registry: &Registry) -> Option<ResourceId> {
135 registry.try_id::<T>()
136 }
137
138 #[inline(always)]
139 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Option<ResourceId>) -> Option<Res<'w, T>> {
140 state.map(|id| {
143 #[cfg(debug_assertions)]
144 world.track_borrow(id);
145 unsafe { Res::new(world.get::<T>(id)) }
146 })
147 }
148
149 fn resource_id(state: &Option<ResourceId>) -> Option<ResourceId> {
150 *state
151 }
152}
153
154impl<T: Resource> Param for Option<ResMut<'_, T>> {
157 type State = Option<ResourceId>;
158 type Item<'w> = Option<ResMut<'w, T>>;
159
160 fn init(registry: &Registry) -> Option<ResourceId> {
161 registry.try_id::<T>()
162 }
163
164 #[inline(always)]
165 unsafe fn fetch<'w>(
166 world: &'w World,
167 state: &'w mut Option<ResourceId>,
168 ) -> Option<ResMut<'w, T>> {
169 state.map(|id| {
172 #[cfg(debug_assertions)]
173 world.track_borrow(id);
174 unsafe { ResMut::new(world.get_mut::<T>(id)) }
175 })
176 }
177
178 fn resource_id(state: &Option<ResourceId>) -> Option<ResourceId> {
179 *state
180 }
181}
182
183impl Param for Seq {
186 type State = ();
187 type Item<'w> = Seq;
188
189 fn init(_registry: &Registry) {}
190
191 #[inline(always)]
192 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> Seq {
193 Seq(world.current_sequence())
194 }
195}
196
197impl Param for SeqMut<'_> {
200 type State = ();
201 type Item<'w> = SeqMut<'w>;
202
203 fn init(_registry: &Registry) {}
204
205 #[inline(always)]
206 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> SeqMut<'w> {
207 SeqMut(world.sequence_cell())
208 }
209}
210
211impl Param for Shutdown<'_> {
214 type State = ();
215 type Item<'w> = Shutdown<'w>;
216
217 fn init(_registry: &Registry) {}
218
219 #[inline(always)]
220 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> Shutdown<'w> {
221 Shutdown(world.shutdown_flag())
224 }
225}
226
227impl Param for () {
233 type State = ();
234 type Item<'w> = ();
235
236 fn init(_registry: &Registry) {}
237
238 #[inline(always)]
239 unsafe fn fetch<'w>(_world: &'w World, _state: &'w mut ()) {}
240}
241
242macro_rules! impl_param_tuple {
243 ($($P:ident),+) => {
244 impl<$($P: Param),+> Param for ($($P,)+) {
245 type State = ($($P::State,)+);
246 type Item<'w> = ($($P::Item<'w>,)+);
247
248 fn init(registry: &Registry) -> Self::State {
249 ($($P::init(registry),)+)
250 }
251
252 #[inline(always)]
253 #[allow(non_snake_case)]
254 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Self::State) -> Self::Item<'w> {
255 let ($($P,)+) = state;
256 unsafe { ($($P::fetch(world, $P),)+) }
258 }
259 }
260 };
261}
262
263all_tuples!(impl_param_tuple);
264
265pub struct Local<'s, T: Default + Send + 'static> {
287 value: &'s mut T,
288}
289
290impl<'s, T: Default + Send + 'static> Local<'s, T> {
291 pub(crate) fn new(value: &'s mut T) -> Self {
292 Self { value }
293 }
294}
295
296impl<T: Default + Send + std::fmt::Debug + 'static> std::fmt::Debug for Local<'_, T> {
297 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298 self.value.fmt(f)
299 }
300}
301
302impl<T: Default + Send + 'static> Deref for Local<'_, T> {
303 type Target = T;
304
305 #[inline(always)]
306 fn deref(&self) -> &T {
307 self.value
308 }
309}
310
311impl<T: Default + Send + 'static> DerefMut for Local<'_, T> {
312 #[inline(always)]
313 fn deref_mut(&mut self) -> &mut T {
314 self.value
315 }
316}
317
318impl<T: Default + Send + 'static> Param for Local<'_, T> {
319 type State = T;
320 type Item<'s> = Local<'s, T>;
321
322 fn init(_registry: &Registry) -> T {
323 T::default()
324 }
325
326 #[inline(always)]
327 unsafe fn fetch<'s>(_world: &'s World, state: &'s mut T) -> Local<'s, T> {
328 Local::new(state)
332 }
333}
334
335pub struct RegistryRef<'w> {
349 registry: &'w Registry,
350}
351
352impl Deref for RegistryRef<'_> {
353 type Target = Registry;
354
355 #[inline(always)]
356 fn deref(&self) -> &Registry {
357 self.registry
358 }
359}
360
361impl Param for RegistryRef<'_> {
362 type State = ();
363 type Item<'w> = RegistryRef<'w>;
364
365 fn init(_registry: &Registry) {}
366
367 #[inline(always)]
368 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> RegistryRef<'w> {
369 RegistryRef {
370 registry: world.registry(),
371 }
372 }
373}
374
375pub trait Handler<E>: Send {
394 fn run(&mut self, world: &mut World, event: E);
396
397 fn name(&self) -> &'static str {
402 "<unnamed>"
403 }
404}
405
406impl<E> Handler<E> for Box<dyn Handler<E>> {
407 fn run(&mut self, world: &mut World, event: E) {
408 (**self).run(world, event);
409 }
410
411 fn name(&self) -> &'static str {
412 (**self).name()
413 }
414}
415
416#[doc(hidden)]
430pub struct CtxFree<F>(pub(crate) F);
431
432pub type HandlerFn<F, Params> = Callback<(), CtxFree<F>, Params>;
441
442#[diagnostic::on_unimplemented(
500 message = "this function cannot be converted into a handler",
501 note = "handler signature: `fn(Res<A>, ResMut<B>, ..., Event)` — resources first, event last",
502 note = "closures with resource parameters (Res<T>, ResMut<T>) are not supported — use a named `fn`",
503 note = "arity-0 closures (`fn(Event)` with no resources) ARE supported"
504)]
505pub trait IntoHandler<E, Params> {
506 type Handler: Handler<E> + 'static;
508
509 #[must_use = "the handler must be stored or dispatched — discarding it does nothing"]
511 fn into_handler(self, registry: &Registry) -> Self::Handler;
512}
513
514impl<E, F: FnMut(E) + Send + 'static> IntoHandler<E, ()> for F {
520 type Handler = Callback<(), CtxFree<F>, ()>;
521
522 fn into_handler(self, registry: &Registry) -> Self::Handler {
523 Callback {
524 ctx: (),
525 f: CtxFree(self),
526 state: <() as Param>::init(registry),
527 name: std::any::type_name::<F>(),
528 }
529 }
530}
531
532impl<E, F: FnMut(E) + Send + 'static> Handler<E> for Callback<(), CtxFree<F>, ()> {
533 fn run(&mut self, _world: &mut World, event: E) {
534 (self.f.0)(event);
535 }
536
537 fn name(&self) -> &'static str {
538 self.name
539 }
540}
541
542macro_rules! impl_into_handler {
543 ($($P:ident),+) => {
544 impl<E, F: Send + 'static, $($P: Param + 'static),+> IntoHandler<E, ($($P,)+)> for F
545 where
546 for<'a> &'a mut F: FnMut($($P,)+ E) + FnMut($($P::Item<'a>,)+ E),
553 {
554 type Handler = Callback<(), CtxFree<F>, ($($P,)+)>;
555
556 fn into_handler(self, registry: &Registry) -> Self::Handler {
557 let state = <($($P,)+) as Param>::init(registry);
558 {
559 #[allow(non_snake_case)]
560 let ($($P,)+) = &state;
561 registry.check_access(&[
562 $(
563 (<$P as Param>::resource_id($P),
564 std::any::type_name::<$P>()),
565 )+
566 ]);
567 }
568 Callback {
569 ctx: (),
570 f: CtxFree(self),
571 state,
572 name: std::any::type_name::<F>(),
573 }
574 }
575 }
576
577 impl<E, F: Send + 'static, $($P: Param + 'static),+> Handler<E>
578 for Callback<(), CtxFree<F>, ($($P,)+)>
579 where
580 for<'a> &'a mut F: FnMut($($P,)+ E) + FnMut($($P::Item<'a>,)+ E),
581 {
582 #[allow(non_snake_case)]
583 fn run(&mut self, world: &mut World, event: E) {
584 #[allow(clippy::too_many_arguments)]
586 fn call_inner<$($P,)+ Ev>(
587 mut f: impl FnMut($($P,)+ Ev),
588 $($P: $P,)+
589 event: Ev,
590 ) {
591 f($($P,)+ event);
592 }
593
594 #[cfg(debug_assertions)]
598 world.clear_borrows();
599 let ($($P,)+) = unsafe {
600 <($($P,)+) as Param>::fetch(world, &mut self.state)
601 };
602 call_inner(&mut self.f.0, $($P,)+ event);
603 }
604
605 fn name(&self) -> &'static str {
606 self.name
607 }
608 }
609 };
610}
611
612all_tuples!(impl_into_handler);
613
614pub struct Opaque;
662
663pub struct Resolved;
679
680impl<E, H: Handler<E> + 'static> IntoHandler<E, Resolved> for H {
681 type Handler = H;
682
683 fn into_handler(self, _registry: &Registry) -> H {
684 self
685 }
686}
687
688pub struct OpaqueHandler<F> {
702 f: F,
703 name: &'static str,
704}
705
706impl<E, F: FnMut(&mut World, E) + Send + 'static> Handler<E> for OpaqueHandler<F> {
707 fn run(&mut self, world: &mut World, event: E) {
708 (self.f)(world, event);
709 }
710
711 fn name(&self) -> &'static str {
712 self.name
713 }
714}
715
716impl<E, F: FnMut(&mut World, E) + Send + 'static> IntoHandler<E, Opaque> for F {
717 type Handler = OpaqueHandler<F>;
718
719 fn into_handler(self, _registry: &Registry) -> Self::Handler {
720 OpaqueHandler {
721 f: self,
722 name: std::any::type_name::<F>(),
723 }
724 }
725}
726
727#[cfg(test)]
732mod tests {
733 use super::*;
734 use crate::WorldBuilder;
735 use crate::world::Sequence;
736
737 #[test]
740 fn res_param() {
741 let mut builder = WorldBuilder::new();
742 builder.register::<u64>(42);
743 let mut world = builder.build();
744
745 let mut state = <Res<u64> as Param>::init(world.registry_mut());
746 let res = unsafe { <Res<u64> as Param>::fetch(&world, &mut state) };
748 assert_eq!(*res, 42);
749 }
750
751 #[test]
752 fn res_mut_param() {
753 let mut builder = WorldBuilder::new();
754 builder.register::<u64>(1);
755 let mut world = builder.build();
756
757 let mut state = <ResMut<u64> as Param>::init(world.registry_mut());
758 unsafe {
760 let mut res = <ResMut<u64> as Param>::fetch(&world, &mut state);
761 *res = 99;
762 }
763 #[cfg(debug_assertions)]
765 world.clear_borrows();
766 unsafe {
767 let mut read_state = <Res<u64> as Param>::init(world.registry_mut());
768 let res = <Res<u64> as Param>::fetch(&world, &mut read_state);
769 assert_eq!(*res, 99);
770 }
771 }
772
773 #[test]
774 fn tuple_param() {
775 let mut builder = WorldBuilder::new();
776 builder.register::<u64>(10);
777 builder.register::<bool>(true);
778 let mut world = builder.build();
779
780 let mut state = <(Res<u64>, ResMut<bool>) as Param>::init(world.registry_mut());
781 unsafe {
783 let (counter, mut flag) =
784 <(Res<u64>, ResMut<bool>) as Param>::fetch(&world, &mut state);
785 assert_eq!(*counter, 10);
786 assert!(*flag);
787 *flag = false;
788 }
789 #[cfg(debug_assertions)]
791 world.clear_borrows();
792 unsafe {
793 let mut read_state = <Res<bool> as Param>::init(world.registry_mut());
794 let res = <Res<bool> as Param>::fetch(&world, &mut read_state);
795 assert!(!*res);
796 }
797 }
798
799 #[test]
800 fn empty_tuple_param() {
801 let mut world = WorldBuilder::new().build();
802 <() as Param>::init(world.registry_mut());
803 unsafe { <() as Param>::fetch(&world, &mut ()) };
805 }
806
807 fn event_only_handler(event: u32) {
810 assert_eq!(event, 42);
811 }
812
813 #[test]
814 fn event_only_dispatch() {
815 let mut world = WorldBuilder::new().build();
816 let mut sys = event_only_handler.into_handler(world.registry_mut());
817 sys.run(&mut world, 42u32);
818 }
819
820 fn one_res_handler(counter: Res<u64>, event: u32) {
821 assert_eq!(*counter, 10);
822 assert_eq!(event, 5);
823 }
824
825 #[test]
826 fn one_res_and_event() {
827 let mut builder = WorldBuilder::new();
828 builder.register::<u64>(10);
829 let mut world = builder.build();
830
831 let mut sys = one_res_handler.into_handler(world.registry_mut());
832 sys.run(&mut world, 5u32);
833 }
834
835 fn two_res_handler(counter: Res<u64>, flag: Res<bool>, event: u32) {
836 assert_eq!(*counter, 10);
837 assert!(*flag);
838 assert_eq!(event, 7);
839 }
840
841 #[test]
842 fn two_res_and_event() {
843 let mut builder = WorldBuilder::new();
844 builder.register::<u64>(10);
845 builder.register::<bool>(true);
846 let mut world = builder.build();
847
848 let mut sys = two_res_handler.into_handler(world.registry_mut());
849 sys.run(&mut world, 7u32);
850 }
851
852 fn accumulate(mut counter: ResMut<u64>, event: u64) {
853 *counter += event;
854 }
855
856 #[test]
857 fn mutation_through_res_mut() {
858 let mut builder = WorldBuilder::new();
859 builder.register::<u64>(0);
860 let mut world = builder.build();
861
862 let mut sys = accumulate.into_handler(world.registry_mut());
863
864 sys.run(&mut world, 10u64);
865 sys.run(&mut world, 5u64);
866
867 assert_eq!(*world.resource::<u64>(), 15);
868 }
869
870 fn add_handler(mut counter: ResMut<u64>, event: u64) {
871 *counter += event;
872 }
873
874 fn mul_handler(mut counter: ResMut<u64>, event: u64) {
875 *counter *= event;
876 }
877
878 #[test]
879 fn box_dyn_type_erasure() {
880 let mut builder = WorldBuilder::new();
881 builder.register::<u64>(0);
882 let mut world = builder.build();
883
884 let sys_a = add_handler.into_handler(world.registry_mut());
885 let sys_b = mul_handler.into_handler(world.registry_mut());
886
887 let mut handlers: Vec<Box<dyn Handler<u64>>> = vec![Box::new(sys_a), Box::new(sys_b)];
888
889 for h in &mut handlers {
890 h.run(&mut world, 3u64);
891 }
892 assert_eq!(*world.resource::<u64>(), 9);
894 }
895
896 fn local_counter(mut count: Local<u64>, _event: u32) {
899 *count += 1;
900 }
901
902 #[test]
903 fn local_default_init() {
904 let mut world = WorldBuilder::new().build();
905 let mut sys = local_counter.into_handler(world.registry_mut());
906 sys.run(&mut world, 1u32);
908 }
909
910 #[test]
911 fn local_persists_across_runs() {
912 let mut builder = WorldBuilder::new();
913 builder.register::<u64>(0);
914 let mut world = builder.build();
915
916 fn accumulate_local(mut count: Local<u64>, mut total: ResMut<u64>, _event: u32) {
917 *count += 1;
918 *total = *count;
919 }
920
921 let mut sys = accumulate_local.into_handler(world.registry_mut());
922 sys.run(&mut world, 0u32);
923 sys.run(&mut world, 0u32);
924 sys.run(&mut world, 0u32);
925
926 assert_eq!(*world.resource::<u64>(), 3);
927 }
928
929 #[test]
930 fn local_independent_per_handler() {
931 let mut builder = WorldBuilder::new();
932 builder.register::<u64>(0);
933 let mut world = builder.build();
934
935 fn inc_local(mut count: Local<u64>, mut total: ResMut<u64>, _event: u32) {
936 *count += 1;
937 *total += *count;
938 }
939
940 let mut sys_a = inc_local.into_handler(world.registry_mut());
941 let mut sys_b = inc_local.into_handler(world.registry_mut());
942
943 sys_a.run(&mut world, 0u32); sys_b.run(&mut world, 0u32); sys_a.run(&mut world, 0u32); assert_eq!(*world.resource::<u64>(), 4);
948 }
949
950 #[test]
953 fn option_res_none_when_missing() {
954 let mut world = WorldBuilder::new().build();
955 let mut state = <Option<Res<u64>> as Param>::init(world.registry_mut());
956 let opt = unsafe { <Option<Res<u64>> as Param>::fetch(&world, &mut state) };
957 assert!(opt.is_none());
958 }
959
960 #[test]
961 fn option_res_some_when_present() {
962 let mut builder = WorldBuilder::new();
963 builder.register::<u64>(42);
964 let mut world = builder.build();
965
966 let mut state = <Option<Res<u64>> as Param>::init(world.registry_mut());
967 let opt = unsafe { <Option<Res<u64>> as Param>::fetch(&world, &mut state) };
968 assert_eq!(*opt.unwrap(), 42);
969 }
970
971 #[test]
972 fn option_res_mut_some_when_present() {
973 let mut builder = WorldBuilder::new();
974 builder.register::<u64>(1);
975 let mut world = builder.build();
976
977 let mut state = <Option<ResMut<u64>> as Param>::init(world.registry_mut());
978 unsafe {
979 let opt = <Option<ResMut<u64>> as Param>::fetch(&world, &mut state);
980 *opt.unwrap() = 99;
981 }
982 #[cfg(debug_assertions)]
983 world.clear_borrows();
984 unsafe {
985 let mut read_state = <Res<u64> as Param>::init(world.registry_mut());
986 let res = <Res<u64> as Param>::fetch(&world, &mut read_state);
987 assert_eq!(*res, 99);
988 }
989 }
990
991 fn optional_handler(opt: Option<Res<String>>, _event: u32) {
992 assert!(opt.is_none());
993 }
994
995 #[test]
996 fn option_in_handler() {
997 let mut world = WorldBuilder::new().build();
998 let mut sys = optional_handler.into_handler(world.registry_mut());
999 sys.run(&mut world, 0u32);
1000 }
1001
1002 #[test]
1005 #[should_panic(expected = "conflicting access")]
1006 fn duplicate_res_panics() {
1007 let mut builder = WorldBuilder::new();
1008 builder.register::<u64>(0);
1009 let mut world = builder.build();
1010
1011 fn bad(a: Res<u64>, b: Res<u64>, _e: ()) {
1012 let _ = (*a, *b);
1013 }
1014
1015 let _sys = bad.into_handler(world.registry_mut());
1016 }
1017
1018 #[test]
1019 #[should_panic(expected = "conflicting access")]
1020 fn duplicate_res_mut_panics() {
1021 let mut builder = WorldBuilder::new();
1022 builder.register::<u64>(0);
1023 let mut world = builder.build();
1024
1025 fn bad(a: ResMut<u64>, b: ResMut<u64>, _e: ()) {
1026 let _ = (&*a, &*b);
1027 }
1028
1029 let _sys = bad.into_handler(world.registry_mut());
1030 }
1031
1032 #[test]
1033 #[should_panic(expected = "conflicting access")]
1034 fn duplicate_mixed_panics() {
1035 let mut builder = WorldBuilder::new();
1036 builder.register::<u64>(0);
1037 let mut world = builder.build();
1038
1039 fn bad(a: Res<u64>, b: ResMut<u64>, _e: ()) {
1040 let _ = (*a, &*b);
1041 }
1042
1043 let _sys = bad.into_handler(world.registry_mut());
1044 }
1045
1046 #[test]
1047 fn different_types_no_conflict() {
1048 let mut builder = WorldBuilder::new();
1049 builder.register::<u64>(0);
1050 builder.register::<u32>(0);
1051 let mut world = builder.build();
1052
1053 fn ok(a: Res<u64>, b: ResMut<u32>, _e: ()) {
1054 let _ = (*a, &*b);
1055 }
1056
1057 let _sys = ok.into_handler(world.registry_mut());
1058 }
1059
1060 #[test]
1061 fn local_no_conflict() {
1062 let mut builder = WorldBuilder::new();
1063 builder.register::<u64>(0);
1064 let mut world = builder.build();
1065
1066 fn ok(local: Local<u64>, val: ResMut<u64>, _e: ()) {
1067 let _ = (&*local, &*val);
1068 }
1069
1070 let _sys = ok.into_handler(world.registry_mut());
1071 }
1072
1073 #[test]
1076 fn opaque_handler_dispatch() {
1077 let mut builder = WorldBuilder::new();
1078 builder.register::<u64>(0);
1079 let mut world = builder.build();
1080
1081 let opaque_fn = |w: &mut World, event: u64| {
1082 let current = *w.resource::<u64>();
1083 *w.resource_mut::<u64>() = current + event;
1084 };
1085
1086 let mut h = opaque_fn.into_handler(world.registry_mut());
1087 h.run(&mut world, 10u64);
1088 h.run(&mut world, 5u64);
1089
1090 assert_eq!(*world.resource::<u64>(), 15);
1091 }
1092
1093 #[test]
1094 fn opaque_handler_boxed() {
1095 let mut builder = WorldBuilder::new();
1096 builder.register::<u64>(0);
1097 let mut world = builder.build();
1098
1099 let opaque_fn = |w: &mut World, event: u64| {
1100 *w.resource_mut::<u64>() += event;
1101 };
1102
1103 let mut h: Box<dyn Handler<u64>> = Box::new(opaque_fn.into_handler(world.registry_mut()));
1104 h.run(&mut world, 7u64);
1105
1106 assert_eq!(*world.resource::<u64>(), 7);
1107 }
1108
1109 #[test]
1112 fn seq_reads_current() {
1113 fn check(seq: Seq, mut out: ResMut<i64>, _event: ()) {
1114 *out = seq.get().as_i64();
1115 }
1116
1117 let mut builder = WorldBuilder::new();
1118 builder.register::<i64>(0);
1119 let mut world = builder.build();
1120 world.next_sequence(); let mut handler = check.into_handler(world.registry_mut());
1123 handler.run(&mut world, ());
1124 assert_eq!(*world.resource::<i64>(), 1);
1125 }
1126
1127 #[test]
1128 fn seq_mut_advances() {
1129 fn stamp(mut seq: SeqMut, mut counter: ResMut<u64>, _event: ()) {
1130 let a = seq.advance();
1131 let b = seq.advance();
1132 *counter = a.as_i64() as u64 * 100 + b.as_i64() as u64;
1133 }
1134
1135 let mut builder = WorldBuilder::new();
1136 builder.register::<u64>(0);
1137 let mut world = builder.build();
1138 let mut handler = stamp.into_handler(world.registry_mut());
1140 handler.run(&mut world, ());
1141 assert_eq!(*world.resource::<u64>(), 100 + 2);
1142 assert_eq!(world.current_sequence(), Sequence(2));
1144 }
1145
1146 #[test]
1147 fn seq_mut_persistent_across_dispatches() {
1148 fn advance(mut seq: SeqMut, _event: ()) {
1149 seq.advance();
1150 }
1151
1152 let builder = WorldBuilder::new();
1153 let mut world = builder.build();
1154 let mut handler = advance.into_handler(world.registry_mut());
1155 handler.run(&mut world, ());
1156 handler.run(&mut world, ());
1157 handler.run(&mut world, ());
1158 assert_eq!(world.current_sequence(), Sequence(3));
1159 }
1160
1161 #[test]
1164 fn seq_only_param() {
1165 fn handle(seq: Seq, _event: ()) {
1166 assert!(seq.get().as_i64() >= 0);
1167 }
1168
1169 let builder = WorldBuilder::new();
1170 let mut world = builder.build();
1171 let mut h = handle.into_handler(world.registry_mut());
1172 h.run(&mut world, ());
1173 }
1174
1175 #[test]
1176 fn seq_first_with_res() {
1177 fn handle(seq: Seq, config: Res<u64>, mut out: ResMut<i64>, _event: ()) {
1178 *out = seq.get().as_i64() + *config as i64;
1179 }
1180
1181 let mut builder = WorldBuilder::new();
1182 builder.register::<u64>(100);
1183 builder.register::<i64>(0);
1184 let mut world = builder.build();
1185 world.next_sequence();
1186 let mut h = handle.into_handler(world.registry_mut());
1187 h.run(&mut world, ());
1188 assert_eq!(*world.resource::<i64>(), 101);
1189 }
1190
1191 #[test]
1192 fn seq_middle_position() {
1193 fn handle(config: Res<u64>, seq: Seq, mut out: ResMut<i64>, _event: ()) {
1194 *out = *config as i64 + seq.get().as_i64();
1195 }
1196
1197 let mut builder = WorldBuilder::new();
1198 builder.register::<u64>(50);
1199 builder.register::<i64>(0);
1200 let mut world = builder.build();
1201 world.next_sequence(); let mut h = handle.into_handler(world.registry_mut());
1203 h.run(&mut world, ());
1204 assert_eq!(*world.resource::<i64>(), 51);
1205 }
1206
1207 #[test]
1208 fn seq_last_position() {
1209 fn handle(mut out: ResMut<i64>, seq: Seq, _event: ()) {
1210 *out = seq.get().as_i64();
1211 }
1212
1213 let mut builder = WorldBuilder::new();
1214 builder.register::<i64>(0);
1215 let mut world = builder.build();
1216 world.next_sequence();
1217 world.next_sequence(); let mut h = handle.into_handler(world.registry_mut());
1219 h.run(&mut world, ());
1220 assert_eq!(*world.resource::<i64>(), 2);
1221 }
1222
1223 #[test]
1224 fn seq_mut_only_param() {
1225 fn handle(mut seq: SeqMut, _event: ()) {
1226 seq.advance();
1227 }
1228
1229 let builder = WorldBuilder::new();
1230 let mut world = builder.build();
1231 let mut h = handle.into_handler(world.registry_mut());
1232 h.run(&mut world, ());
1233 assert_eq!(world.current_sequence(), Sequence(1));
1234 }
1235
1236 #[test]
1237 fn seq_mut_first_with_res() {
1238 fn handle(mut seq: SeqMut, mut out: ResMut<i64>, _event: ()) {
1239 let s = seq.advance();
1240 *out = s.0;
1241 }
1242
1243 let mut builder = WorldBuilder::new();
1244 builder.register::<i64>(0);
1245 let mut world = builder.build();
1246 let mut h = handle.into_handler(world.registry_mut());
1247 h.run(&mut world, ());
1248 assert_eq!(*world.resource::<i64>(), 1);
1249 }
1250
1251 #[test]
1252 fn seq_mut_middle_position() {
1253 fn handle(config: Res<u64>, mut seq: SeqMut, mut out: ResMut<i64>, _event: ()) {
1254 let s = seq.advance();
1255 *out = s.0 + *config as i64;
1256 }
1257
1258 let mut builder = WorldBuilder::new();
1259 builder.register::<u64>(10);
1260 builder.register::<i64>(0);
1261 let mut world = builder.build();
1262 let mut h = handle.into_handler(world.registry_mut());
1263 h.run(&mut world, ());
1264 assert_eq!(*world.resource::<i64>(), 11);
1265 }
1266
1267 #[test]
1268 fn seq_mut_last_position() {
1269 fn handle(mut out: ResMut<i64>, mut seq: SeqMut, _event: ()) {
1270 let s = seq.advance();
1271 *out = s.0;
1272 }
1273
1274 let mut builder = WorldBuilder::new();
1275 builder.register::<i64>(0);
1276 let mut world = builder.build();
1277 let mut h = handle.into_handler(world.registry_mut());
1278 h.run(&mut world, ());
1279 assert_eq!(*world.resource::<i64>(), 1);
1280 }
1281
1282 #[test]
1283 fn seq_mut_multiple_advances_in_one_dispatch() {
1284 fn handle(mut seq: SeqMut, mut out: ResMut<Vec<i64>>, _event: ()) {
1285 out.push(seq.advance().0);
1286 out.push(seq.advance().0);
1287 out.push(seq.advance().0);
1288 }
1289
1290 let mut builder = WorldBuilder::new();
1291 builder.register::<Vec<i64>>(Vec::new());
1292 let mut world = builder.build();
1293 let mut h = handle.into_handler(world.registry_mut());
1294 h.run(&mut world, ());
1295 assert_eq!(*world.resource::<Vec<i64>>(), vec![1, 2, 3]);
1296 assert_eq!(world.current_sequence(), Sequence(3));
1297 }
1298
1299 #[test]
1304 fn concrete_handler_satisfies_into_handler() {
1305 fn accept_into_handler<E, P>(h: impl IntoHandler<E, P>, reg: &Registry) -> impl Handler<E> {
1307 h.into_handler(reg)
1308 }
1309
1310 let mut builder = WorldBuilder::new();
1311 builder.register::<u64>(0);
1312 let world = builder.build();
1313
1314 fn bump(mut val: ResMut<u64>, event: u64) {
1315 *val += event;
1316 }
1317
1318 let handler = bump.into_handler(world.registry());
1320 let _resolved = accept_into_handler(handler, world.registry());
1321 }
1322
1323 #[test]
1324 fn handler_impl_into_handler_dispatches() {
1325 let mut builder = WorldBuilder::new();
1326 builder.register::<u64>(0);
1327
1328 fn add_event(mut val: ResMut<u64>, event: u64) {
1329 *val += event;
1330 }
1331
1332 let handler = add_event.into_handler(builder.registry());
1334 let mut resolved = handler.into_handler(builder.registry());
1335 let mut world = builder.build();
1336
1337 resolved.run(&mut world, 42);
1338 assert_eq!(*world.resource::<u64>(), 42);
1339 }
1340}