1#![allow(clippy::too_many_arguments)]
8
9use std::ops::{Deref, DerefMut};
10
11use crate::Resource;
12use crate::callback::Callback;
13use crate::resource::{Res, ResMut, Seq, SeqMut};
14use crate::shutdown::Shutdown;
15use crate::world::{Registry, ResourceId, World};
16
17pub trait Param {
47 type State: Send;
53
54 type Item<'w>;
56
57 fn init(registry: &Registry) -> Self::State;
63
64 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Self::State) -> Self::Item<'w>;
72
73 fn resource_id(state: &Self::State) -> Option<ResourceId> {
79 let _ = state;
80 None
81 }
82}
83
84impl<T: Resource> Param for Res<'_, T> {
87 type State = ResourceId;
88 type Item<'w> = Res<'w, T>;
89
90 fn init(registry: &Registry) -> ResourceId {
91 registry.id::<T>()
92 }
93
94 #[inline(always)]
95 unsafe fn fetch<'w>(world: &'w World, state: &'w mut ResourceId) -> Res<'w, T> {
96 let id = *state;
97 #[cfg(debug_assertions)]
98 world.track_borrow(id);
99 unsafe { Res::new(world.get::<T>(id)) }
102 }
103
104 fn resource_id(state: &ResourceId) -> Option<ResourceId> {
105 Some(*state)
106 }
107}
108
109impl<T: Resource> Param for ResMut<'_, T> {
112 type State = ResourceId;
113 type Item<'w> = ResMut<'w, T>;
114
115 fn init(registry: &Registry) -> ResourceId {
116 registry.id::<T>()
117 }
118
119 #[inline(always)]
120 unsafe fn fetch<'w>(world: &'w World, state: &'w mut ResourceId) -> ResMut<'w, T> {
121 let id = *state;
122 #[cfg(debug_assertions)]
123 world.track_borrow(id);
124 unsafe { ResMut::new(world.get_mut::<T>(id)) }
127 }
128
129 fn resource_id(state: &ResourceId) -> Option<ResourceId> {
130 Some(*state)
131 }
132}
133
134impl<T: Resource> Param for Option<Res<'_, T>> {
137 type State = Option<ResourceId>;
138 type Item<'w> = Option<Res<'w, T>>;
139
140 fn init(registry: &Registry) -> Option<ResourceId> {
141 registry.try_id::<T>()
142 }
143
144 #[inline(always)]
145 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Option<ResourceId>) -> Option<Res<'w, T>> {
146 state.map(|id| {
149 #[cfg(debug_assertions)]
150 world.track_borrow(id);
151 unsafe { Res::new(world.get::<T>(id)) }
152 })
153 }
154
155 fn resource_id(state: &Option<ResourceId>) -> Option<ResourceId> {
156 *state
157 }
158}
159
160impl<T: Resource> Param for Option<ResMut<'_, T>> {
163 type State = Option<ResourceId>;
164 type Item<'w> = Option<ResMut<'w, T>>;
165
166 fn init(registry: &Registry) -> Option<ResourceId> {
167 registry.try_id::<T>()
168 }
169
170 #[inline(always)]
171 unsafe fn fetch<'w>(
172 world: &'w World,
173 state: &'w mut Option<ResourceId>,
174 ) -> Option<ResMut<'w, T>> {
175 state.map(|id| {
178 #[cfg(debug_assertions)]
179 world.track_borrow(id);
180 unsafe { ResMut::new(world.get_mut::<T>(id)) }
181 })
182 }
183
184 fn resource_id(state: &Option<ResourceId>) -> Option<ResourceId> {
185 *state
186 }
187}
188
189impl Param for Seq {
192 type State = ();
193 type Item<'w> = Seq;
194
195 fn init(_registry: &Registry) {}
196
197 #[inline(always)]
198 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> Seq {
199 Seq(world.current_sequence())
200 }
201}
202
203impl Param for SeqMut<'_> {
206 type State = ();
207 type Item<'w> = SeqMut<'w>;
208
209 fn init(_registry: &Registry) {}
210
211 #[inline(always)]
212 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> SeqMut<'w> {
213 SeqMut(world.sequence_cell())
214 }
215}
216
217impl Param for Shutdown<'_> {
220 type State = ();
221 type Item<'w> = Shutdown<'w>;
222
223 fn init(_registry: &Registry) {}
224
225 #[inline(always)]
226 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> Shutdown<'w> {
227 Shutdown(world.shutdown_flag())
230 }
231}
232
233impl Param for () {
239 type State = ();
240 type Item<'w> = ();
241
242 fn init(_registry: &Registry) {}
243
244 #[inline(always)]
245 unsafe fn fetch<'w>(_world: &'w World, _state: &'w mut ()) {}
246}
247
248macro_rules! impl_param_tuple {
249 ($($P:ident),+) => {
250 impl<$($P: Param),+> Param for ($($P,)+) {
251 type State = ($($P::State,)+);
252 type Item<'w> = ($($P::Item<'w>,)+);
253
254 fn init(registry: &Registry) -> Self::State {
255 ($($P::init(registry),)+)
256 }
257
258 #[inline(always)]
259 #[allow(non_snake_case)]
260 unsafe fn fetch<'w>(world: &'w World, state: &'w mut Self::State) -> Self::Item<'w> {
261 let ($($P,)+) = state;
262 unsafe { ($($P::fetch(world, $P),)+) }
264 }
265 }
266 };
267}
268
269all_tuples!(impl_param_tuple);
270
271pub struct Local<'s, T: Default + Send + 'static> {
293 value: &'s mut T,
294}
295
296impl<'s, T: Default + Send + 'static> Local<'s, T> {
297 pub(crate) fn new(value: &'s mut T) -> Self {
298 Self { value }
299 }
300}
301
302impl<T: Default + Send + std::fmt::Debug + 'static> std::fmt::Debug for Local<'_, T> {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 self.value.fmt(f)
305 }
306}
307
308impl<T: Default + Send + 'static> Deref for Local<'_, T> {
309 type Target = T;
310
311 #[inline(always)]
312 fn deref(&self) -> &T {
313 self.value
314 }
315}
316
317impl<T: Default + Send + 'static> DerefMut for Local<'_, T> {
318 #[inline(always)]
319 fn deref_mut(&mut self) -> &mut T {
320 self.value
321 }
322}
323
324impl<T: Default + Send + 'static> Param for Local<'_, T> {
325 type State = T;
326 type Item<'s> = Local<'s, T>;
327
328 fn init(_registry: &Registry) -> T {
329 T::default()
330 }
331
332 #[inline(always)]
333 unsafe fn fetch<'s>(_world: &'s World, state: &'s mut T) -> Local<'s, T> {
334 Local::new(state)
338 }
339}
340
341pub struct RegistryRef<'w> {
355 registry: &'w Registry,
356}
357
358impl Deref for RegistryRef<'_> {
359 type Target = Registry;
360
361 #[inline(always)]
362 fn deref(&self) -> &Registry {
363 self.registry
364 }
365}
366
367impl Param for RegistryRef<'_> {
368 type State = ();
369 type Item<'w> = RegistryRef<'w>;
370
371 fn init(_registry: &Registry) {}
372
373 #[inline(always)]
374 unsafe fn fetch<'w>(world: &'w World, _state: &'w mut ()) -> RegistryRef<'w> {
375 RegistryRef {
376 registry: world.registry(),
377 }
378 }
379}
380
381pub trait Handler<E>: Send {
400 fn run(&mut self, world: &mut World, event: E);
402
403 fn name(&self) -> &'static str {
408 "<unnamed>"
409 }
410}
411
412impl<E> Handler<E> for Box<dyn Handler<E>> {
413 fn run(&mut self, world: &mut World, event: E) {
414 (**self).run(world, event);
415 }
416
417 fn name(&self) -> &'static str {
418 (**self).name()
419 }
420}
421
422#[doc(hidden)]
436pub struct CtxFree<F>(pub(crate) F);
437
438pub struct NoEvent<F>(pub(crate) F);
461
462pub fn no_event<F>(f: F) -> NoEvent<F> {
494 NoEvent(f)
495}
496
497pub type HandlerFn<F, Params> = Callback<(), CtxFree<F>, Params>;
506
507#[diagnostic::on_unimplemented(
565 message = "this function cannot be converted into a handler",
566 note = "handler signature: `fn(Res<A>, ResMut<B>, ..., Event)` — resources first, event last",
567 note = "for Handler<()> with params, wrap with `no_event(fn_name)` to omit the event parameter",
568 note = "closures with resource parameters (Res<T>, ResMut<T>) are not supported — use a named `fn`",
569 note = "arity-0 closures (`fn(Event)` with no resources) ARE supported"
570)]
571pub trait IntoHandler<E, Params> {
572 type Handler: Handler<E> + 'static;
574
575 #[must_use = "the handler must be stored or dispatched — discarding it does nothing"]
577 fn into_handler(self, registry: &Registry) -> Self::Handler;
578}
579
580impl<E, F: FnMut(E) + Send + 'static> IntoHandler<E, ()> for F {
586 type Handler = Callback<(), CtxFree<F>, ()>;
587
588 fn into_handler(self, registry: &Registry) -> Self::Handler {
589 Callback {
590 ctx: (),
591 f: CtxFree(self),
592 state: <() as Param>::init(registry),
593 name: std::any::type_name::<F>(),
594 }
595 }
596}
597
598impl<E, F: FnMut(E) + Send + 'static> Handler<E> for Callback<(), CtxFree<F>, ()> {
599 fn run(&mut self, _world: &mut World, event: E) {
600 (self.f.0)(event);
601 }
602
603 fn name(&self) -> &'static str {
604 self.name
605 }
606}
607
608macro_rules! impl_into_handler {
609 ($($P:ident),+) => {
610 impl<E, F: Send + 'static, $($P: Param + 'static),+> IntoHandler<E, ($($P,)+)> for F
611 where
612 for<'a> &'a mut F: FnMut($($P,)+ E) + FnMut($($P::Item<'a>,)+ E),
619 {
620 type Handler = Callback<(), CtxFree<F>, ($($P,)+)>;
621
622 fn into_handler(self, registry: &Registry) -> Self::Handler {
623 let state = <($($P,)+) as Param>::init(registry);
624 {
625 #[allow(non_snake_case)]
626 let ($($P,)+) = &state;
627 registry.check_access(&[
628 $(
629 (<$P as Param>::resource_id($P),
630 std::any::type_name::<$P>()),
631 )+
632 ]);
633 }
634 Callback {
635 ctx: (),
636 f: CtxFree(self),
637 state,
638 name: std::any::type_name::<F>(),
639 }
640 }
641 }
642
643 impl<E, F: Send + 'static, $($P: Param + 'static),+> Handler<E>
644 for Callback<(), CtxFree<F>, ($($P,)+)>
645 where
646 for<'a> &'a mut F: FnMut($($P,)+ E) + FnMut($($P::Item<'a>,)+ E),
647 {
648 #[allow(non_snake_case)]
649 fn run(&mut self, world: &mut World, event: E) {
650 fn call_inner<$($P,)+ Ev>(
652 mut f: impl FnMut($($P,)+ Ev),
653 $($P: $P,)+
654 event: Ev,
655 ) {
656 f($($P,)+ event);
657 }
658
659 #[cfg(debug_assertions)]
663 world.clear_borrows();
664 let ($($P,)+) = unsafe {
665 <($($P,)+) as Param>::fetch(world, &mut self.state)
666 };
667 call_inner(&mut self.f.0, $($P,)+ event);
668 }
669
670 fn name(&self) -> &'static str {
671 self.name
672 }
673 }
674 };
675}
676
677all_tuples!(impl_into_handler);
678
679impl<F: FnMut() + Send + 'static> IntoHandler<(), NoEvent<F>> for F {
685 type Handler = Callback<(), CtxFree<NoEvent<F>>, ()>;
686
687 fn into_handler(self, registry: &Registry) -> Self::Handler {
688 Callback {
689 ctx: (),
690 f: CtxFree(NoEvent(self)),
691 state: <() as Param>::init(registry),
692 name: std::any::type_name::<F>(),
693 }
694 }
695}
696
697impl<F: FnMut() + Send + 'static> Handler<()> for Callback<(), CtxFree<NoEvent<F>>, ()> {
698 fn run(&mut self, _world: &mut World, _event: ()) {
699 (self.f.0.0)();
700 }
701
702 fn name(&self) -> &'static str {
703 self.name
704 }
705}
706
707macro_rules! impl_into_handler_no_event {
708 ($($P:ident),+) => {
709 impl<F: Send + 'static, $($P: Param + 'static),+>
710 IntoHandler<(), ($($P,)+)> for NoEvent<F>
711 where
712 for<'a> &'a mut F: FnMut($($P,)+) + FnMut($($P::Item<'a>,)+),
713 {
714 type Handler = Callback<(), CtxFree<NoEvent<F>>, ($($P,)+)>;
715
716 fn into_handler(self, registry: &Registry) -> Self::Handler {
717 let state = <($($P,)+) as Param>::init(registry);
718 {
719 #[allow(non_snake_case)]
720 let ($($P,)+) = &state;
721 registry.check_access(&[
722 $(
723 (<$P as Param>::resource_id($P),
724 std::any::type_name::<$P>()),
725 )+
726 ]);
727 }
728 Callback {
729 ctx: (),
730 f: CtxFree(self),
731 state,
732 name: std::any::type_name::<F>(),
733 }
734 }
735 }
736
737 impl<F: Send + 'static, $($P: Param + 'static),+> Handler<()>
738 for Callback<(), CtxFree<NoEvent<F>>, ($($P,)+)>
739 where
740 for<'a> &'a mut F: FnMut($($P,)+) + FnMut($($P::Item<'a>,)+),
741 {
742 #[allow(non_snake_case)]
743 fn run(&mut self, world: &mut World, _event: ()) {
744 fn call_inner<$($P),+>(
745 mut f: impl FnMut($($P),+),
746 $($P: $P,)+
747 ) {
748 f($($P),+)
749 }
750
751 #[cfg(debug_assertions)]
752 world.clear_borrows();
753 let ($($P,)+) = unsafe {
754 <($($P,)+) as Param>::fetch(world, &mut self.state)
755 };
756 call_inner(&mut self.f.0 .0, $($P,)+);
757 }
758
759 fn name(&self) -> &'static str {
760 self.name
761 }
762 }
763 };
764}
765
766all_tuples!(impl_into_handler_no_event);
767
768pub struct Opaque;
816
817pub struct Resolved;
833
834impl<E, H: Handler<E> + 'static> IntoHandler<E, Resolved> for H {
835 type Handler = H;
836
837 fn into_handler(self, _registry: &Registry) -> H {
838 self
839 }
840}
841
842pub struct OpaqueHandler<F> {
856 f: F,
857 name: &'static str,
858}
859
860impl<E, F: FnMut(&mut World, E) + Send + 'static> Handler<E> for OpaqueHandler<F> {
861 fn run(&mut self, world: &mut World, event: E) {
862 (self.f)(world, event);
863 }
864
865 fn name(&self) -> &'static str {
866 self.name
867 }
868}
869
870impl<E, F: FnMut(&mut World, E) + Send + 'static> IntoHandler<E, Opaque> for F {
871 type Handler = OpaqueHandler<F>;
872
873 fn into_handler(self, _registry: &Registry) -> Self::Handler {
874 OpaqueHandler {
875 f: self,
876 name: std::any::type_name::<F>(),
877 }
878 }
879}
880
881#[cfg(test)]
886mod tests {
887 use super::*;
888 use crate::WorldBuilder;
889 use crate::world::Sequence;
890
891 #[test]
894 fn res_param() {
895 let mut builder = WorldBuilder::new();
896 builder.register::<u64>(42);
897 let mut world = builder.build();
898
899 let mut state = <Res<u64> as Param>::init(world.registry_mut());
900 let res = unsafe { <Res<u64> as Param>::fetch(&world, &mut state) };
902 assert_eq!(*res, 42);
903 }
904
905 #[test]
906 fn res_mut_param() {
907 let mut builder = WorldBuilder::new();
908 builder.register::<u64>(1);
909 let mut world = builder.build();
910
911 let mut state = <ResMut<u64> as Param>::init(world.registry_mut());
912 unsafe {
914 let mut res = <ResMut<u64> as Param>::fetch(&world, &mut state);
915 *res = 99;
916 }
917 #[cfg(debug_assertions)]
919 world.clear_borrows();
920 unsafe {
921 let mut read_state = <Res<u64> as Param>::init(world.registry_mut());
922 let res = <Res<u64> as Param>::fetch(&world, &mut read_state);
923 assert_eq!(*res, 99);
924 }
925 }
926
927 #[test]
928 fn tuple_param() {
929 let mut builder = WorldBuilder::new();
930 builder.register::<u64>(10);
931 builder.register::<bool>(true);
932 let mut world = builder.build();
933
934 let mut state = <(Res<u64>, ResMut<bool>) as Param>::init(world.registry_mut());
935 unsafe {
937 let (counter, mut flag) =
938 <(Res<u64>, ResMut<bool>) as Param>::fetch(&world, &mut state);
939 assert_eq!(*counter, 10);
940 assert!(*flag);
941 *flag = false;
942 }
943 #[cfg(debug_assertions)]
945 world.clear_borrows();
946 unsafe {
947 let mut read_state = <Res<bool> as Param>::init(world.registry_mut());
948 let res = <Res<bool> as Param>::fetch(&world, &mut read_state);
949 assert!(!*res);
950 }
951 }
952
953 #[test]
954 fn empty_tuple_param() {
955 let mut world = WorldBuilder::new().build();
956 <() as Param>::init(world.registry_mut());
957 unsafe { <() as Param>::fetch(&world, &mut ()) };
959 }
960
961 fn event_only_handler(event: u32) {
964 assert_eq!(event, 42);
965 }
966
967 #[test]
968 fn event_only_dispatch() {
969 let mut world = WorldBuilder::new().build();
970 let mut sys = event_only_handler.into_handler(world.registry_mut());
971 sys.run(&mut world, 42u32);
972 }
973
974 fn one_res_handler(counter: Res<u64>, event: u32) {
975 assert_eq!(*counter, 10);
976 assert_eq!(event, 5);
977 }
978
979 #[test]
980 fn one_res_and_event() {
981 let mut builder = WorldBuilder::new();
982 builder.register::<u64>(10);
983 let mut world = builder.build();
984
985 let mut sys = one_res_handler.into_handler(world.registry_mut());
986 sys.run(&mut world, 5u32);
987 }
988
989 fn two_res_handler(counter: Res<u64>, flag: Res<bool>, event: u32) {
990 assert_eq!(*counter, 10);
991 assert!(*flag);
992 assert_eq!(event, 7);
993 }
994
995 #[test]
996 fn two_res_and_event() {
997 let mut builder = WorldBuilder::new();
998 builder.register::<u64>(10);
999 builder.register::<bool>(true);
1000 let mut world = builder.build();
1001
1002 let mut sys = two_res_handler.into_handler(world.registry_mut());
1003 sys.run(&mut world, 7u32);
1004 }
1005
1006 fn accumulate(mut counter: ResMut<u64>, event: u64) {
1007 *counter += event;
1008 }
1009
1010 #[test]
1011 fn mutation_through_res_mut() {
1012 let mut builder = WorldBuilder::new();
1013 builder.register::<u64>(0);
1014 let mut world = builder.build();
1015
1016 let mut sys = accumulate.into_handler(world.registry_mut());
1017
1018 sys.run(&mut world, 10u64);
1019 sys.run(&mut world, 5u64);
1020
1021 assert_eq!(*world.resource::<u64>(), 15);
1022 }
1023
1024 fn add_handler(mut counter: ResMut<u64>, event: u64) {
1025 *counter += event;
1026 }
1027
1028 fn mul_handler(mut counter: ResMut<u64>, event: u64) {
1029 *counter *= event;
1030 }
1031
1032 #[test]
1033 fn box_dyn_type_erasure() {
1034 let mut builder = WorldBuilder::new();
1035 builder.register::<u64>(0);
1036 let mut world = builder.build();
1037
1038 let sys_a = add_handler.into_handler(world.registry_mut());
1039 let sys_b = mul_handler.into_handler(world.registry_mut());
1040
1041 let mut handlers: Vec<Box<dyn Handler<u64>>> = vec![Box::new(sys_a), Box::new(sys_b)];
1042
1043 for h in &mut handlers {
1044 h.run(&mut world, 3u64);
1045 }
1046 assert_eq!(*world.resource::<u64>(), 9);
1048 }
1049
1050 fn local_counter(mut count: Local<u64>, _event: u32) {
1053 *count += 1;
1054 }
1055
1056 #[test]
1057 fn local_default_init() {
1058 let mut world = WorldBuilder::new().build();
1059 let mut sys = local_counter.into_handler(world.registry_mut());
1060 sys.run(&mut world, 1u32);
1062 }
1063
1064 #[test]
1065 fn local_persists_across_runs() {
1066 let mut builder = WorldBuilder::new();
1067 builder.register::<u64>(0);
1068 let mut world = builder.build();
1069
1070 fn accumulate_local(mut count: Local<u64>, mut total: ResMut<u64>, _event: u32) {
1071 *count += 1;
1072 *total = *count;
1073 }
1074
1075 let mut sys = accumulate_local.into_handler(world.registry_mut());
1076 sys.run(&mut world, 0u32);
1077 sys.run(&mut world, 0u32);
1078 sys.run(&mut world, 0u32);
1079
1080 assert_eq!(*world.resource::<u64>(), 3);
1081 }
1082
1083 #[test]
1084 fn local_independent_per_handler() {
1085 let mut builder = WorldBuilder::new();
1086 builder.register::<u64>(0);
1087 let mut world = builder.build();
1088
1089 fn inc_local(mut count: Local<u64>, mut total: ResMut<u64>, _event: u32) {
1090 *count += 1;
1091 *total += *count;
1092 }
1093
1094 let mut sys_a = inc_local.into_handler(world.registry_mut());
1095 let mut sys_b = inc_local.into_handler(world.registry_mut());
1096
1097 sys_a.run(&mut world, 0u32); sys_b.run(&mut world, 0u32); sys_a.run(&mut world, 0u32); assert_eq!(*world.resource::<u64>(), 4);
1102 }
1103
1104 #[test]
1107 fn option_res_none_when_missing() {
1108 let mut world = WorldBuilder::new().build();
1109 let mut state = <Option<Res<u64>> as Param>::init(world.registry_mut());
1110 let opt = unsafe { <Option<Res<u64>> as Param>::fetch(&world, &mut state) };
1111 assert!(opt.is_none());
1112 }
1113
1114 #[test]
1115 fn option_res_some_when_present() {
1116 let mut builder = WorldBuilder::new();
1117 builder.register::<u64>(42);
1118 let mut world = builder.build();
1119
1120 let mut state = <Option<Res<u64>> as Param>::init(world.registry_mut());
1121 let opt = unsafe { <Option<Res<u64>> as Param>::fetch(&world, &mut state) };
1122 assert_eq!(*opt.unwrap(), 42);
1123 }
1124
1125 #[test]
1126 fn option_res_mut_some_when_present() {
1127 let mut builder = WorldBuilder::new();
1128 builder.register::<u64>(1);
1129 let mut world = builder.build();
1130
1131 let mut state = <Option<ResMut<u64>> as Param>::init(world.registry_mut());
1132 unsafe {
1133 let opt = <Option<ResMut<u64>> as Param>::fetch(&world, &mut state);
1134 *opt.unwrap() = 99;
1135 }
1136 #[cfg(debug_assertions)]
1137 world.clear_borrows();
1138 unsafe {
1139 let mut read_state = <Res<u64> as Param>::init(world.registry_mut());
1140 let res = <Res<u64> as Param>::fetch(&world, &mut read_state);
1141 assert_eq!(*res, 99);
1142 }
1143 }
1144
1145 fn optional_handler(opt: Option<Res<String>>, _event: u32) {
1146 assert!(opt.is_none());
1147 }
1148
1149 #[test]
1150 fn option_in_handler() {
1151 let mut world = WorldBuilder::new().build();
1152 let mut sys = optional_handler.into_handler(world.registry_mut());
1153 sys.run(&mut world, 0u32);
1154 }
1155
1156 #[test]
1159 #[should_panic(expected = "conflicting access")]
1160 fn duplicate_res_panics() {
1161 let mut builder = WorldBuilder::new();
1162 builder.register::<u64>(0);
1163 let mut world = builder.build();
1164
1165 fn bad(a: Res<u64>, b: Res<u64>) {
1166 let _ = (*a, *b);
1167 }
1168
1169 let _sys = no_event(bad).into_handler(world.registry_mut());
1170 }
1171
1172 #[test]
1173 #[should_panic(expected = "conflicting access")]
1174 fn duplicate_res_mut_panics() {
1175 let mut builder = WorldBuilder::new();
1176 builder.register::<u64>(0);
1177 let mut world = builder.build();
1178
1179 fn bad(a: ResMut<u64>, b: ResMut<u64>) {
1180 let _ = (&*a, &*b);
1181 }
1182
1183 let _sys = no_event(bad).into_handler(world.registry_mut());
1184 }
1185
1186 #[test]
1187 #[should_panic(expected = "conflicting access")]
1188 fn duplicate_mixed_panics() {
1189 let mut builder = WorldBuilder::new();
1190 builder.register::<u64>(0);
1191 let mut world = builder.build();
1192
1193 fn bad(a: Res<u64>, b: ResMut<u64>) {
1194 let _ = (*a, &*b);
1195 }
1196
1197 let _sys = no_event(bad).into_handler(world.registry_mut());
1198 }
1199
1200 #[test]
1201 fn different_types_no_conflict() {
1202 let mut builder = WorldBuilder::new();
1203 builder.register::<u64>(0);
1204 builder.register::<u32>(0);
1205 let mut world = builder.build();
1206
1207 fn ok(a: Res<u64>, b: ResMut<u32>) {
1208 let _ = (*a, &*b);
1209 }
1210
1211 let _sys = no_event(ok).into_handler(world.registry_mut());
1212 }
1213
1214 #[test]
1215 fn local_no_conflict() {
1216 let mut builder = WorldBuilder::new();
1217 builder.register::<u64>(0);
1218 let mut world = builder.build();
1219
1220 fn ok(local: Local<u64>, val: ResMut<u64>) {
1221 let _ = (&*local, &*val);
1222 }
1223
1224 let _sys = no_event(ok).into_handler(world.registry_mut());
1225 }
1226
1227 #[test]
1230 fn opaque_handler_dispatch() {
1231 let mut builder = WorldBuilder::new();
1232 builder.register::<u64>(0);
1233 let mut world = builder.build();
1234
1235 let opaque_fn = |w: &mut World, event: u64| {
1236 let current = *w.resource::<u64>();
1237 *w.resource_mut::<u64>() = current + event;
1238 };
1239
1240 let mut h = opaque_fn.into_handler(world.registry_mut());
1241 h.run(&mut world, 10u64);
1242 h.run(&mut world, 5u64);
1243
1244 assert_eq!(*world.resource::<u64>(), 15);
1245 }
1246
1247 #[test]
1248 fn opaque_handler_boxed() {
1249 let mut builder = WorldBuilder::new();
1250 builder.register::<u64>(0);
1251 let mut world = builder.build();
1252
1253 let opaque_fn = |w: &mut World, event: u64| {
1254 *w.resource_mut::<u64>() += event;
1255 };
1256
1257 let mut h: Box<dyn Handler<u64>> = Box::new(opaque_fn.into_handler(world.registry_mut()));
1258 h.run(&mut world, 7u64);
1259
1260 assert_eq!(*world.resource::<u64>(), 7);
1261 }
1262
1263 #[test]
1266 fn seq_reads_current() {
1267 fn check(seq: Seq, mut out: ResMut<i64>) {
1268 *out = seq.get().as_i64();
1269 }
1270
1271 let mut builder = WorldBuilder::new();
1272 builder.register::<i64>(0);
1273 let mut world = builder.build();
1274 world.next_sequence(); let mut handler = no_event(check).into_handler(world.registry_mut());
1277 handler.run(&mut world, ());
1278 assert_eq!(*world.resource::<i64>(), 1);
1279 }
1280
1281 #[test]
1282 fn seq_mut_advances() {
1283 fn stamp(mut seq: SeqMut, mut counter: ResMut<u64>) {
1284 let a = seq.advance();
1285 let b = seq.advance();
1286 *counter = a.as_i64() as u64 * 100 + b.as_i64() as u64;
1287 }
1288
1289 let mut builder = WorldBuilder::new();
1290 builder.register::<u64>(0);
1291 let mut world = builder.build();
1292 let mut handler = no_event(stamp).into_handler(world.registry_mut());
1294 handler.run(&mut world, ());
1295 assert_eq!(*world.resource::<u64>(), 100 + 2);
1296 assert_eq!(world.current_sequence(), Sequence(2));
1298 }
1299
1300 #[test]
1301 fn seq_mut_persistent_across_dispatches() {
1302 fn advance(mut seq: SeqMut) {
1303 seq.advance();
1304 }
1305
1306 let builder = WorldBuilder::new();
1307 let mut world = builder.build();
1308 let mut handler = no_event(advance).into_handler(world.registry_mut());
1309 handler.run(&mut world, ());
1310 handler.run(&mut world, ());
1311 handler.run(&mut world, ());
1312 assert_eq!(world.current_sequence(), Sequence(3));
1313 }
1314
1315 #[test]
1318 fn seq_only_param() {
1319 fn handle(seq: Seq) {
1320 assert!(seq.get().as_i64() >= 0);
1321 }
1322
1323 let builder = WorldBuilder::new();
1324 let mut world = builder.build();
1325 let mut h = no_event(handle).into_handler(world.registry_mut());
1326 h.run(&mut world, ());
1327 }
1328
1329 #[test]
1330 fn seq_first_with_res() {
1331 fn handle(seq: Seq, config: Res<u64>, mut out: ResMut<i64>) {
1332 *out = seq.get().as_i64() + *config as i64;
1333 }
1334
1335 let mut builder = WorldBuilder::new();
1336 builder.register::<u64>(100);
1337 builder.register::<i64>(0);
1338 let mut world = builder.build();
1339 world.next_sequence();
1340 let mut h = no_event(handle).into_handler(world.registry_mut());
1341 h.run(&mut world, ());
1342 assert_eq!(*world.resource::<i64>(), 101);
1343 }
1344
1345 #[test]
1346 fn seq_middle_position() {
1347 fn handle(config: Res<u64>, seq: Seq, mut out: ResMut<i64>) {
1348 *out = *config as i64 + seq.get().as_i64();
1349 }
1350
1351 let mut builder = WorldBuilder::new();
1352 builder.register::<u64>(50);
1353 builder.register::<i64>(0);
1354 let mut world = builder.build();
1355 world.next_sequence(); let mut h = no_event(handle).into_handler(world.registry_mut());
1357 h.run(&mut world, ());
1358 assert_eq!(*world.resource::<i64>(), 51);
1359 }
1360
1361 #[test]
1362 fn seq_last_position() {
1363 fn handle(mut out: ResMut<i64>, seq: Seq) {
1364 *out = seq.get().as_i64();
1365 }
1366
1367 let mut builder = WorldBuilder::new();
1368 builder.register::<i64>(0);
1369 let mut world = builder.build();
1370 world.next_sequence();
1371 world.next_sequence(); let mut h = no_event(handle).into_handler(world.registry_mut());
1373 h.run(&mut world, ());
1374 assert_eq!(*world.resource::<i64>(), 2);
1375 }
1376
1377 #[test]
1378 fn seq_mut_only_param() {
1379 fn handle(mut seq: SeqMut) {
1380 seq.advance();
1381 }
1382
1383 let builder = WorldBuilder::new();
1384 let mut world = builder.build();
1385 let mut h = no_event(handle).into_handler(world.registry_mut());
1386 h.run(&mut world, ());
1387 assert_eq!(world.current_sequence(), Sequence(1));
1388 }
1389
1390 #[test]
1391 fn seq_mut_first_with_res() {
1392 fn handle(mut seq: SeqMut, mut out: ResMut<i64>) {
1393 let s = seq.advance();
1394 *out = s.0;
1395 }
1396
1397 let mut builder = WorldBuilder::new();
1398 builder.register::<i64>(0);
1399 let mut world = builder.build();
1400 let mut h = no_event(handle).into_handler(world.registry_mut());
1401 h.run(&mut world, ());
1402 assert_eq!(*world.resource::<i64>(), 1);
1403 }
1404
1405 #[test]
1406 fn seq_mut_middle_position() {
1407 fn handle(config: Res<u64>, mut seq: SeqMut, mut out: ResMut<i64>) {
1408 let s = seq.advance();
1409 *out = s.0 + *config as i64;
1410 }
1411
1412 let mut builder = WorldBuilder::new();
1413 builder.register::<u64>(10);
1414 builder.register::<i64>(0);
1415 let mut world = builder.build();
1416 let mut h = no_event(handle).into_handler(world.registry_mut());
1417 h.run(&mut world, ());
1418 assert_eq!(*world.resource::<i64>(), 11);
1419 }
1420
1421 #[test]
1422 fn seq_mut_last_position() {
1423 fn handle(mut out: ResMut<i64>, mut seq: SeqMut) {
1424 let s = seq.advance();
1425 *out = s.0;
1426 }
1427
1428 let mut builder = WorldBuilder::new();
1429 builder.register::<i64>(0);
1430 let mut world = builder.build();
1431 let mut h = no_event(handle).into_handler(world.registry_mut());
1432 h.run(&mut world, ());
1433 assert_eq!(*world.resource::<i64>(), 1);
1434 }
1435
1436 #[test]
1437 fn seq_mut_multiple_advances_in_one_dispatch() {
1438 fn handle(mut seq: SeqMut, mut out: ResMut<Vec<i64>>) {
1439 out.push(seq.advance().0);
1440 out.push(seq.advance().0);
1441 out.push(seq.advance().0);
1442 }
1443
1444 let mut builder = WorldBuilder::new();
1445 builder.register::<Vec<i64>>(Vec::new());
1446 let mut world = builder.build();
1447 let mut h = no_event(handle).into_handler(world.registry_mut());
1448 h.run(&mut world, ());
1449 assert_eq!(*world.resource::<Vec<i64>>(), vec![1, 2, 3]);
1450 assert_eq!(world.current_sequence(), Sequence(3));
1451 }
1452
1453 #[test]
1458 fn concrete_handler_satisfies_into_handler() {
1459 fn accept_into_handler<E, P>(h: impl IntoHandler<E, P>, reg: &Registry) -> impl Handler<E> {
1461 h.into_handler(reg)
1462 }
1463
1464 let mut builder = WorldBuilder::new();
1465 builder.register::<u64>(0);
1466 let world = builder.build();
1467
1468 fn bump(mut val: ResMut<u64>, event: u64) {
1469 *val += event;
1470 }
1471
1472 let handler = bump.into_handler(world.registry());
1474 let _resolved = accept_into_handler(handler, world.registry());
1475 }
1476
1477 #[test]
1478 fn handler_impl_into_handler_dispatches() {
1479 let mut builder = WorldBuilder::new();
1480 builder.register::<u64>(0);
1481
1482 fn add_event(mut val: ResMut<u64>, event: u64) {
1483 *val += event;
1484 }
1485
1486 let handler = add_event.into_handler(builder.registry());
1488 let mut resolved = handler.into_handler(builder.registry());
1489 let mut world = builder.build();
1490
1491 resolved.run(&mut world, 42);
1492 assert_eq!(*world.resource::<u64>(), 42);
1493 }
1494
1495 fn no_event_standalone() {}
1500
1501 #[test]
1502 fn no_event_arity_0() {
1503 let mut world = WorldBuilder::new().build();
1504 let mut h = no_event_standalone.into_handler(world.registry_mut());
1505 h.run(&mut world, ());
1506 }
1507
1508 fn no_event_tick(mut counter: ResMut<u64>) {
1509 *counter += 1;
1510 }
1511
1512 #[test]
1513 fn no_event_arity_1() {
1514 use crate::no_event;
1515
1516 let mut builder = WorldBuilder::new();
1517 builder.register::<u64>(0);
1518 let mut world = builder.build();
1519
1520 let mut h = no_event(no_event_tick).into_handler(world.registry_mut());
1521 h.run(&mut world, ());
1522 h.run(&mut world, ());
1523 assert_eq!(*world.resource::<u64>(), 2);
1524 }
1525
1526 fn no_event_two_params(src: Res<u32>, mut dst: ResMut<u64>) {
1527 *dst += *src as u64;
1528 }
1529
1530 #[test]
1531 fn no_event_arity_2() {
1532 use crate::no_event;
1533
1534 let mut builder = WorldBuilder::new();
1535 builder.register::<u32>(7);
1536 builder.register::<u64>(0);
1537 let mut world = builder.build();
1538
1539 let mut h = no_event(no_event_two_params).into_handler(world.registry_mut());
1540 h.run(&mut world, ());
1541 assert_eq!(*world.resource::<u64>(), 7);
1542 }
1543
1544 #[test]
1545 fn no_event_boxed() {
1546 use crate::no_event;
1547
1548 let mut builder = WorldBuilder::new();
1549 builder.register::<u64>(0);
1550 let mut world = builder.build();
1551
1552 let h = no_event(no_event_tick).into_handler(world.registry_mut());
1553 let mut boxed: Box<dyn Handler<()>> = Box::new(h);
1554 boxed.run(&mut world, ());
1555 assert_eq!(*world.resource::<u64>(), 1);
1556 }
1557
1558 #[test]
1559 fn no_event_coexists_with_event_handler() {
1560 use crate::no_event;
1561
1562 let mut builder = WorldBuilder::new();
1563 builder.register::<u64>(0);
1564 let mut world = builder.build();
1565
1566 let mut h1 = no_event(no_event_tick).into_handler(world.registry_mut());
1568 h1.run(&mut world, ());
1569 assert_eq!(*world.resource::<u64>(), 1);
1570
1571 fn add_event(mut val: ResMut<u64>, event: u64) {
1573 *val += event;
1574 }
1575 let mut h2 = add_event.into_handler(world.registry_mut());
1576 h2.run(&mut world, 10);
1577 assert_eq!(*world.resource::<u64>(), 11);
1578 }
1579}