1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![allow(clippy::match_single_binding)] #![allow(clippy::match_like_matches_macro)]
5
6pub mod prelude {
8 pub use crate::{Behavior, BehaviorIndex, BehaviorItem, BehaviorMut, BehaviorRef};
9 pub use moonshine_kind::{Instance, InstanceCommands};
10
11 pub use crate::transition::{
12 transition, Interrupt, Interruption, Next, Previous, Transition, TransitionQueue,
13 };
14
15 pub use crate::events::{OnActivate, OnPause, OnResume, OnStart, OnStop};
16 pub use crate::plugin::BehaviorPlugin;
17
18 pub use crate::match_next;
19
20 #[allow(deprecated)]
21 pub use crate::transition::TransitionSequence;
22}
23
24pub mod events;
25pub mod transition;
26
27mod plugin;
28
29#[cfg(test)]
30mod tests;
31
32use std::fmt::Debug;
33use std::mem::{replace, swap};
34use std::ops::{Deref, DerefMut, Index, IndexMut};
35
36use bevy_derive::{Deref, DerefMut};
37use bevy_ecs::change_detection::{MaybeLocation, Tick};
38use bevy_ecs::component::Mutable;
39use bevy_ecs::event::EntityTrigger;
40use bevy_ecs::{prelude::*, query::QueryData};
41use bevy_log::prelude::*;
42use bevy_reflect::prelude::*;
43use moonshine_kind::prelude::*;
44
45pub use plugin::BehaviorPlugin;
46
47use crate::events::{Activate, Error, Pause, Resume, Start, Stop};
48
49use self::transition::*;
50
51pub trait Behavior: Component<Mutability = Mutable> + Debug + Sized {
58 fn filter_yield(&self, next: &Self) -> bool {
63 match_next! {
64 self => next,
65 _ => _,
66 }
67 }
68
69 fn filter_next(&self, next: &Self) -> bool {
74 match_next! {
75 self => next,
76 _ => _,
77 }
78 }
79
80 fn is_resumable(&self) -> bool {
85 match self {
86 _ => true,
87 }
88 }
89
90 fn on_start(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
92
93 fn on_pause(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
95
96 fn on_resume(&self, _previous: &Self, _commands: InstanceCommands<Self>) {}
98
99 fn on_stop(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
101
102 fn on_activate(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
104
105 fn on_suspend(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
107}
108
109#[doc(hidden)]
110trait BehaviorHooks: Behavior {
111 fn invoke_start(&self, previous: Option<&Self>, mut commands: InstanceCommands<Self>) {
112 self.on_start(previous, commands.reborrow());
113 self.on_activate(previous, commands);
114 }
115
116 fn invoke_pause(&self, current: &Self, mut commands: InstanceCommands<Self>) {
117 self.on_suspend(current, commands.reborrow());
118 self.on_pause(current, commands);
119 }
120
121 fn invoke_resume(&self, previous: &Self, mut commands: InstanceCommands<Self>) {
122 self.on_resume(previous, commands.reborrow());
123 self.on_activate(Some(previous), commands);
124 }
125
126 fn invoke_stop(&self, current: &Self, mut commands: InstanceCommands<Self>) {
127 self.on_suspend(current, commands.reborrow());
128 self.on_stop(current, commands);
129 }
130}
131
132impl<T: Behavior> BehaviorHooks for T {}
133
134pub trait BehaviorItem {
136 #[doc(hidden)]
137 type Behavior: Behavior;
138
139 fn current(&self) -> &Self::Behavior;
141
142 fn previous(&self) -> Option<&Self::Behavior>;
151
152 #[deprecated(since = "0.3.1", note = "use `current_index` instead")]
154 fn index(&self) -> BehaviorIndex {
155 self.current_index()
156 }
157
158 fn current_index(&self) -> BehaviorIndex;
160
161 fn has_index(&self, index: BehaviorIndex) -> bool {
163 index <= self.current_index()
164 }
165
166 fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &Self::Behavior)> + '_;
170
171 fn iter(&self) -> impl Iterator<Item = &Self::Behavior> + '_ {
175 self.enumerate().map(|(_, behavior)| behavior)
176 }
177
178 fn get(&self, index: BehaviorIndex) -> Option<&Self::Behavior>;
180
181 fn has_transition(&self) -> bool;
196}
197
198#[derive(QueryData)]
207pub struct BehaviorRef<T: Behavior> {
208 current: Ref<'static, T>,
209 memory: &'static Memory<T>,
210 transition: &'static Transition<T>,
211}
212
213impl<T: Behavior> BehaviorRef<T> {
214 pub fn from_entity(entity: EntityRef) -> Option<BehaviorRefItem<T>> {
216 Some(BehaviorRefItem {
217 current: entity.get_ref::<T>()?,
218 memory: entity.get::<Memory<T>>()?,
219 transition: entity.get::<Transition<T>>()?,
220 })
221 }
222}
223
224impl<T: Behavior> BehaviorItem for BehaviorRefItem<'_, '_, T> {
225 type Behavior = T;
226
227 fn current(&self) -> &T {
228 &self.current
229 }
230
231 fn current_index(&self) -> BehaviorIndex {
232 BehaviorIndex(self.memory.len())
233 }
234
235 fn previous(&self) -> Option<&T> {
236 self.memory.last()
237 }
238
239 fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &T)> + '_ {
240 self.memory
241 .iter()
242 .enumerate()
243 .map(|(index, item)| (BehaviorIndex(index), item))
244 .chain(std::iter::once((self.current_index(), self.current())))
245 }
246
247 fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
248 if index == self.memory.stack.len() {
249 Some(self.current())
250 } else {
251 self.memory.get(index)
252 }
253 }
254
255 fn has_transition(&self) -> bool {
256 !self.transition.is_none()
257 }
258}
259
260impl<T: Behavior> Deref for BehaviorRefItem<'_, '_, T> {
261 type Target = T;
262
263 fn deref(&self) -> &Self::Target {
264 self.current()
265 }
266}
267
268impl<T: Behavior> AsRef<T> for BehaviorRefItem<'_, '_, T> {
269 fn as_ref(&self) -> &T {
270 &self.current
271 }
272}
273
274impl<T: Behavior> DetectChanges for BehaviorRefItem<'_, '_, T> {
275 fn is_added(&self) -> bool {
276 self.current.is_added()
277 }
278
279 fn is_changed(&self) -> bool {
280 self.current.is_changed()
281 }
282
283 fn last_changed(&self) -> Tick {
284 self.current.last_changed()
285 }
286
287 fn added(&self) -> Tick {
288 self.current.added()
289 }
290
291 fn changed_by(&self) -> MaybeLocation {
292 self.current.changed_by()
293 }
294
295 fn is_added_after(&self, other: Tick) -> bool {
296 self.current.is_added_after(other)
297 }
298
299 fn is_changed_after(&self, other: Tick) -> bool {
300 self.current.is_changed_after(other)
301 }
302}
303
304impl<T: Behavior> Index<BehaviorIndex> for BehaviorRefItem<'_, '_, T> {
305 type Output = T;
306
307 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
308 if index == self.memory.stack.len() {
309 self.current()
310 } else {
311 &self.memory[index]
312 }
313 }
314}
315
316#[derive(QueryData)]
324#[query_data(mutable)]
325pub struct BehaviorMut<T: Behavior> {
326 current: Mut<'static, T>,
327 memory: &'static mut Memory<T>,
328 transition: &'static mut Transition<T>,
329}
330
331impl<T: Behavior> BehaviorItem for BehaviorMutReadOnlyItem<'_, '_, T> {
332 type Behavior = T;
333
334 fn current(&self) -> &T {
335 &self.current
336 }
337
338 fn current_index(&self) -> BehaviorIndex {
339 BehaviorIndex(self.memory.len())
340 }
341
342 fn previous(&self) -> Option<&T> {
343 self.memory.last()
344 }
345
346 fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &T)> + '_ {
347 self.memory
348 .iter()
349 .enumerate()
350 .map(|(index, item)| (BehaviorIndex(index), item))
351 .chain(std::iter::once((self.current_index(), self.current())))
352 }
353
354 fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
355 if index == self.memory.stack.len() {
356 Some(self.current())
357 } else {
358 self.memory.get(index)
359 }
360 }
361
362 fn has_transition(&self) -> bool {
363 !self.transition.is_none()
364 }
365}
366
367impl<T: Behavior> Deref for BehaviorMutReadOnlyItem<'_, '_, T> {
368 type Target = T;
369
370 fn deref(&self) -> &Self::Target {
371 self.current()
372 }
373}
374
375impl<T: Behavior> AsRef<T> for BehaviorMutReadOnlyItem<'_, '_, T> {
376 fn as_ref(&self) -> &T {
377 self.current.as_ref()
378 }
379}
380
381impl<T: Behavior> DetectChanges for BehaviorMutReadOnlyItem<'_, '_, T> {
382 fn is_added(&self) -> bool {
383 self.current.is_added()
384 }
385
386 fn is_changed(&self) -> bool {
387 self.current.is_changed()
388 }
389
390 fn last_changed(&self) -> Tick {
391 self.current.last_changed()
392 }
393
394 fn added(&self) -> Tick {
395 self.current.added()
396 }
397
398 fn changed_by(&self) -> MaybeLocation {
399 self.current.changed_by()
400 }
401
402 fn is_added_after(&self, other: Tick) -> bool {
403 self.current.is_added_after(other)
404 }
405
406 fn is_changed_after(&self, other: Tick) -> bool {
407 self.current.is_changed_after(other)
408 }
409}
410
411impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutReadOnlyItem<'_, '_, T> {
412 type Output = T;
413
414 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
415 if index == self.memory.stack.len() {
416 self.current()
417 } else {
418 &self.memory[index]
419 }
420 }
421}
422
423impl<T: Behavior> BehaviorItem for BehaviorMutItem<'_, '_, T> {
424 type Behavior = T;
425
426 fn current(&self) -> &T {
427 &self.current
428 }
429
430 fn current_index(&self) -> BehaviorIndex {
431 BehaviorIndex(self.memory.len())
432 }
433
434 fn previous(&self) -> Option<&T> {
435 self.memory.last()
436 }
437
438 fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &Self::Behavior)> + '_ {
439 self.memory
440 .iter()
441 .enumerate()
442 .map(|(index, item)| (BehaviorIndex(index), item))
443 .chain(std::iter::once((self.current_index(), self.current())))
444 }
445
446 fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
447 if index == self.memory.stack.len() {
448 Some(self.current())
449 } else {
450 self.memory.get(index)
451 }
452 }
453
454 fn has_transition(&self) -> bool {
455 !self.transition.is_none()
456 }
457}
458
459impl<T: Behavior> BehaviorMutItem<'_, '_, T> {
460 pub fn current_mut(&mut self) -> &mut T {
462 self.current.as_mut()
463 }
464
465 pub fn previous_mut(&mut self) -> Option<&mut T> {
469 self.memory.last_mut()
470 }
471
472 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
476 self.memory
477 .iter_mut()
478 .chain(std::iter::once(self.current.as_mut()))
479 }
480
481 pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (BehaviorIndex, &mut T)> + '_ {
485 let current_index = self.current_index();
486 self.memory
487 .iter_mut()
488 .enumerate()
489 .map(|(index, item)| (BehaviorIndex(index), item))
490 .chain(std::iter::once((current_index, self.current.as_mut())))
491 }
492
493 #[track_caller]
500 pub fn start(&mut self, next: T) {
501 self.start_with_caller(next, MaybeLocation::caller());
502 }
503
504 #[track_caller]
524 pub fn try_start(&mut self, next: T) -> Result<(), T> {
525 if self.has_transition() || !self.filter_next(&next) {
526 return Err(next);
527 }
528
529 self.start_with_caller(next, MaybeLocation::caller());
530 Ok(())
531 }
532
533 fn start_with_caller(&mut self, next: T, caller: MaybeLocation) {
534 self.set_transition(Next(next), caller);
535 }
536
537 #[track_caller]
549 pub fn interrupt_start(&mut self, next: T) {
550 self.interrupt_start_with_caller(next, MaybeLocation::caller());
551 }
552
553 #[track_caller]
557 pub fn try_interrupt_start(&mut self, next: T) -> Result<(), T> {
558 if self.has_transition() {
559 return Err(next);
560 }
561
562 self.interrupt_start_with_caller(next, MaybeLocation::caller());
563 Ok(())
564 }
565
566 fn interrupt_start_with_caller(&mut self, next: T, caller: MaybeLocation) {
567 self.set_transition(Interrupt(Interruption::Start(next)), caller);
568 }
569
570 #[track_caller]
576 pub fn interrupt_stop(&mut self, index: BehaviorIndex) {
577 self.interrupt_resume_with_caller(index.previous().unwrap(), MaybeLocation::caller());
578 }
579
580 #[track_caller]
587 pub fn try_interrupt_stop(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
588 if self.has_transition() || !self.has_index(index) {
589 return Err(index);
590 }
591
592 let Some(previous_index) = index.previous() else {
593 return Err(index);
594 };
595
596 self.interrupt_resume_with_caller(previous_index, MaybeLocation::caller());
597 Ok(())
598 }
599
600 #[track_caller]
604 pub fn interrupt_resume(&mut self, index: BehaviorIndex) {
605 self.interrupt_resume_with_caller(index, MaybeLocation::caller());
606 }
607
608 #[track_caller]
614 pub fn try_interrupt_resume(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
615 if self.has_transition() || !self.has_index(index) {
616 return Err(index);
617 }
618
619 self.interrupt_resume_with_caller(index, MaybeLocation::caller());
620 Ok(())
621 }
622
623 fn interrupt_resume_with_caller(&mut self, index: BehaviorIndex, caller: MaybeLocation) {
624 self.set_transition(Interrupt(Interruption::Resume(index)), caller);
625 }
626
627 #[track_caller]
634 pub fn stop(&mut self) {
635 self.stop_with_caller(MaybeLocation::caller());
636 }
637
638 #[track_caller]
644 pub fn try_stop(&mut self) -> bool {
645 if self.has_transition() || self.memory.is_empty() {
646 return false;
647 }
648
649 self.stop_with_caller(MaybeLocation::caller());
650 true
651 }
652
653 fn stop_with_caller(&mut self, caller: MaybeLocation) {
654 self.set_transition(Previous, caller);
655 }
656
657 #[track_caller]
662 pub fn reset(&mut self) {
663 self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
664 }
665
666 #[track_caller]
670 pub fn try_reset(&mut self) -> bool {
671 if self.has_transition() {
672 return false;
673 }
674
675 self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
676 true
677 }
678
679 fn set_transition(&mut self, transition: Transition<T>, caller: MaybeLocation) {
680 let previous = replace(self.transition.as_mut(), transition);
681 if !previous.is_none() {
682 warn!(
683 "transition override ({caller})): {previous:?} -> {:?}",
684 *self.transition
685 );
686 }
687 }
688
689 fn push(
690 &mut self,
691 instance: Instance<T>,
692 mut next: T,
693 initial: bool,
694 commands: &mut Commands,
695 ) -> bool {
696 if self.filter_next(&next) {
697 let previous = {
698 swap(self.current.as_mut(), &mut next);
699 next
700 };
701 self.invoke_start(Some(&previous), commands.instance(instance));
702 let index = self.memory.len();
703 if previous.is_resumable() {
704 let next_index = index + 1;
705 debug!(
706 "{instance:?}: {previous:?} (#{index}) -> {:?} (#{next_index})",
707 *self.current
708 );
709
710 previous.invoke_pause(&self.current, commands.instance(instance));
711
712 commands.queue(move |world: &mut World| {
713 world.trigger_with(
714 Pause {
715 instance,
716 index: BehaviorIndex(index),
717 },
718 EntityTrigger,
719 );
720 world.trigger_with(
721 Start {
722 instance,
723 index: BehaviorIndex(next_index),
724 initial,
725 },
726 EntityTrigger,
727 );
728 world.trigger_with(
729 Activate {
730 instance,
731 index: BehaviorIndex(next_index),
732 resume: false,
733 initial,
734 },
735 EntityTrigger,
736 );
737 });
738
739 self.memory.push(previous);
740 } else {
741 debug!(
742 "{instance:?}: {previous:?} (#{index}) -> {:?} (#{index})",
743 *self.current
744 );
745
746 previous.invoke_stop(&self.current, commands.instance(instance));
747
748 commands.queue(move |world: &mut World| {
749 world.trigger_with(
750 Stop {
751 instance,
752 index: BehaviorIndex(index),
753 behavior: previous,
754 interrupt: false,
755 },
756 EntityTrigger,
757 );
758 world.trigger_with(
759 Start {
760 instance,
761 index: BehaviorIndex(index),
762 initial,
763 },
764 EntityTrigger,
765 );
766 world.trigger_with(
767 Activate {
768 instance,
769 index: BehaviorIndex(index),
770 resume: false,
771 initial,
772 },
773 EntityTrigger,
774 );
775 })
776 }
777 true
778 } else {
779 warn!(
780 "{instance:?}: transition {:?} -> {next:?} is not allowed",
781 *self.current
782 );
783
784 commands.queue(move |world: &mut World| {
785 world.trigger_with(
786 Error {
787 instance,
788 error: TransitionError::RejectedNext(next),
789 },
790 EntityTrigger,
791 );
792 });
793
794 false
795 }
796 }
797
798 fn interrupt(&mut self, instance: Instance<T>, next: T, commands: &mut Commands) {
799 while self.filter_yield(&next) && !self.memory.is_empty() {
800 let index = self.memory.len();
801 if let Some(mut next) = self.memory.pop() {
802 let previous = {
803 swap(self.current.as_mut(), &mut next);
804 next
805 };
806 debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
807 previous.invoke_stop(&self.current, commands.instance(instance));
808
809 commands.queue(move |world: &mut World| {
810 world.trigger_with(
811 Stop {
812 instance,
813 index: BehaviorIndex(index),
814 behavior: previous,
815 interrupt: true,
816 },
817 EntityTrigger,
818 );
819 });
820 }
821 }
822
823 self.push(instance, next, false, commands);
824 }
825
826 fn pop(&mut self, instance: Instance<T>, commands: &mut Commands) -> bool {
827 let index = self.memory.len();
828
829 if let Some(mut next) = self.memory.pop() {
830 let next_index = self.memory.len();
831 debug!(
832 "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
833 *self.current
834 );
835 let previous = {
836 swap(self.current.as_mut(), &mut next);
837 next
838 };
839 self.invoke_resume(&previous, commands.instance(instance));
840 previous.invoke_stop(&self.current, commands.instance(instance));
841
842 commands.queue(move |world: &mut World| {
843 world.trigger_with(
844 Stop {
845 instance,
846 index: BehaviorIndex(index),
847 behavior: previous,
848 interrupt: false,
849 },
850 EntityTrigger,
851 );
852 world.trigger_with(
853 Resume {
854 instance,
855 index: BehaviorIndex(next_index),
856 },
857 EntityTrigger,
858 );
859 world.trigger_with(
860 Activate {
861 instance,
862 index: BehaviorIndex(next_index),
863 resume: true,
864 initial: false,
865 },
866 EntityTrigger,
867 );
868 });
869 true
870 } else {
871 warn!(
872 "{instance:?}: transition {:?} -> None is not allowed",
873 *self.current
874 );
875
876 commands.queue(move |world: &mut World| {
877 world.trigger_with(
878 Error {
879 instance,
880 error: TransitionError::<T>::NoPrevious,
881 },
882 EntityTrigger,
883 );
884 });
885
886 false
887 }
888 }
889
890 fn clear(&mut self, instance: Instance<T>, index: BehaviorIndex, commands: &mut Commands) {
891 while self.current_index() > index.next() {
893 let index = self.memory.len();
894 let previous = self.memory.pop().unwrap();
895 let next = self.memory.last().unwrap();
896 debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
897 previous.invoke_stop(next, commands.instance(instance));
898
899 commands.queue(move |world: &mut World| {
900 world.trigger_with(
901 Stop {
902 instance,
903 index: BehaviorIndex(index),
904 behavior: previous,
905 interrupt: true,
906 },
907 EntityTrigger,
908 );
909 });
910 }
911
912 self.pop(instance, commands);
914 }
915}
916
917impl<T: Behavior> Deref for BehaviorMutItem<'_, '_, T> {
918 type Target = T;
919
920 fn deref(&self) -> &Self::Target {
921 self.current()
922 }
923}
924
925impl<T: Behavior> DerefMut for BehaviorMutItem<'_, '_, T> {
926 fn deref_mut(&mut self) -> &mut Self::Target {
927 self.current_mut()
928 }
929}
930
931impl<T: Behavior> DetectChanges for BehaviorMutItem<'_, '_, T> {
932 fn is_added(&self) -> bool {
933 self.current.is_added()
934 }
935
936 fn is_changed(&self) -> bool {
937 self.current.is_changed()
938 }
939
940 fn last_changed(&self) -> Tick {
941 self.current.last_changed()
942 }
943
944 fn added(&self) -> Tick {
945 self.current.added()
946 }
947
948 fn changed_by(&self) -> MaybeLocation {
949 self.current.changed_by()
950 }
951
952 fn is_added_after(&self, other: Tick) -> bool {
953 self.current.is_added_after(other)
954 }
955
956 fn is_changed_after(&self, other: Tick) -> bool {
957 self.current.is_changed_after(other)
958 }
959}
960
961impl<T: Behavior> DetectChangesMut for BehaviorMutItem<'_, '_, T> {
962 type Inner = T;
963
964 fn set_changed(&mut self) {
965 self.current.set_changed()
966 }
967
968 fn set_last_changed(&mut self, last_changed: Tick) {
969 self.current.set_last_changed(last_changed)
970 }
971
972 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
973 self.current.bypass_change_detection()
974 }
975
976 fn set_added(&mut self) {
977 self.current.set_added()
978 }
979
980 fn set_last_added(&mut self, last_added: Tick) {
981 self.current.set_last_added(last_added)
982 }
983}
984
985impl<T: Behavior> AsRef<T> for BehaviorMutItem<'_, '_, T> {
986 fn as_ref(&self) -> &T {
987 self.current.as_ref()
988 }
989}
990
991impl<T: Behavior> AsMut<T> for BehaviorMutItem<'_, '_, T> {
992 fn as_mut(&mut self) -> &mut T {
993 self.current.as_mut()
994 }
995}
996
997impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
998 type Output = T;
999
1000 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
1001 if index == self.memory.stack.len() {
1002 self.current()
1003 } else {
1004 &self.memory[index]
1005 }
1006 }
1007}
1008
1009impl<T: Behavior> IndexMut<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
1010 fn index_mut(&mut self, BehaviorIndex(index): BehaviorIndex) -> &mut Self::Output {
1011 if index == self.memory.stack.len() {
1012 self.current_mut()
1013 } else {
1014 &mut self.memory[index]
1015 }
1016 }
1017}
1018
1019#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Reflect)]
1024pub struct BehaviorIndex(usize);
1025
1026impl BehaviorIndex {
1027 pub fn initial() -> Self {
1029 Self(0)
1030 }
1031
1032 pub fn previous(self) -> Option<Self> {
1034 if self == BehaviorIndex::initial() {
1035 return None;
1036 }
1037
1038 Some(Self(self.0.saturating_sub(1)))
1039 }
1040
1041 fn next(self) -> Self {
1042 Self(self.0.saturating_add(1))
1043 }
1044}
1045
1046#[derive(Component, Deref, DerefMut, Reflect)]
1047#[reflect(Component)]
1048struct Memory<T: Behavior> {
1049 stack: Vec<T>,
1050}
1051
1052impl<T: Behavior> Default for Memory<T> {
1053 fn default() -> Self {
1054 Self {
1055 stack: Vec::default(),
1056 }
1057 }
1058}
1059
1060#[macro_export]
1101macro_rules! match_next {
1102 { $curr:ident => $next:ident, $($from:pat => $to:pat),* $(,)? } => {
1103 match $curr {
1104 $(
1105 $from => matches!($next, $to),
1106 )*
1107 #[allow(unreachable_patterns)]
1108 _ => false,
1109 }
1110 };
1111}