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;
38use bevy_ecs::component::{Mutable, Tick};
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
296impl<T: Behavior> Index<BehaviorIndex> for BehaviorRefItem<'_, '_, T> {
297 type Output = T;
298
299 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
300 if index == self.memory.stack.len() {
301 self.current()
302 } else {
303 &self.memory[index]
304 }
305 }
306}
307
308#[derive(QueryData)]
316#[query_data(mutable)]
317pub struct BehaviorMut<T: Behavior> {
318 current: Mut<'static, T>,
319 memory: &'static mut Memory<T>,
320 transition: &'static mut Transition<T>,
321}
322
323impl<T: Behavior> BehaviorItem for BehaviorMutReadOnlyItem<'_, '_, T> {
324 type Behavior = T;
325
326 fn current(&self) -> &T {
327 &self.current
328 }
329
330 fn current_index(&self) -> BehaviorIndex {
331 BehaviorIndex(self.memory.len())
332 }
333
334 fn previous(&self) -> Option<&T> {
335 self.memory.last()
336 }
337
338 fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &T)> + '_ {
339 self.memory
340 .iter()
341 .enumerate()
342 .map(|(index, item)| (BehaviorIndex(index), item))
343 .chain(std::iter::once((self.current_index(), self.current())))
344 }
345
346 fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
347 if index == self.memory.stack.len() {
348 Some(self.current())
349 } else {
350 self.memory.get(index)
351 }
352 }
353
354 fn has_transition(&self) -> bool {
355 !self.transition.is_none()
356 }
357}
358
359impl<T: Behavior> Deref for BehaviorMutReadOnlyItem<'_, '_, T> {
360 type Target = T;
361
362 fn deref(&self) -> &Self::Target {
363 self.current()
364 }
365}
366
367impl<T: Behavior> AsRef<T> for BehaviorMutReadOnlyItem<'_, '_, T> {
368 fn as_ref(&self) -> &T {
369 self.current.as_ref()
370 }
371}
372
373impl<T: Behavior> DetectChanges for BehaviorMutReadOnlyItem<'_, '_, T> {
374 fn is_added(&self) -> bool {
375 self.current.is_added()
376 }
377
378 fn is_changed(&self) -> bool {
379 self.current.is_changed()
380 }
381
382 fn last_changed(&self) -> Tick {
383 self.current.last_changed()
384 }
385
386 fn added(&self) -> Tick {
387 self.current.added()
388 }
389
390 fn changed_by(&self) -> MaybeLocation {
391 self.current.changed_by()
392 }
393}
394
395impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutReadOnlyItem<'_, '_, T> {
396 type Output = T;
397
398 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
399 if index == self.memory.stack.len() {
400 self.current()
401 } else {
402 &self.memory[index]
403 }
404 }
405}
406
407impl<T: Behavior> BehaviorItem for BehaviorMutItem<'_, '_, T> {
408 type Behavior = T;
409
410 fn current(&self) -> &T {
411 &self.current
412 }
413
414 fn current_index(&self) -> BehaviorIndex {
415 BehaviorIndex(self.memory.len())
416 }
417
418 fn previous(&self) -> Option<&T> {
419 self.memory.last()
420 }
421
422 fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &Self::Behavior)> + '_ {
423 self.memory
424 .iter()
425 .enumerate()
426 .map(|(index, item)| (BehaviorIndex(index), item))
427 .chain(std::iter::once((self.current_index(), self.current())))
428 }
429
430 fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
431 if index == self.memory.stack.len() {
432 Some(self.current())
433 } else {
434 self.memory.get(index)
435 }
436 }
437
438 fn has_transition(&self) -> bool {
439 !self.transition.is_none()
440 }
441}
442
443impl<T: Behavior> BehaviorMutItem<'_, '_, T> {
444 pub fn current_mut(&mut self) -> &mut T {
446 self.current.as_mut()
447 }
448
449 pub fn previous_mut(&mut self) -> Option<&mut T> {
453 self.memory.last_mut()
454 }
455
456 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
460 self.memory
461 .iter_mut()
462 .chain(std::iter::once(self.current.as_mut()))
463 }
464
465 pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (BehaviorIndex, &mut T)> + '_ {
469 let current_index = self.current_index();
470 self.memory
471 .iter_mut()
472 .enumerate()
473 .map(|(index, item)| (BehaviorIndex(index), item))
474 .chain(std::iter::once((current_index, self.current.as_mut())))
475 }
476
477 #[track_caller]
484 pub fn start(&mut self, next: T) {
485 self.start_with_caller(next, MaybeLocation::caller());
486 }
487
488 #[track_caller]
508 pub fn try_start(&mut self, next: T) -> Result<(), T> {
509 if self.has_transition() || !self.filter_next(&next) {
510 return Err(next);
511 }
512
513 self.start_with_caller(next, MaybeLocation::caller());
514 Ok(())
515 }
516
517 fn start_with_caller(&mut self, next: T, caller: MaybeLocation) {
518 self.set_transition(Next(next), caller);
519 }
520
521 #[track_caller]
533 pub fn interrupt_start(&mut self, next: T) {
534 self.interrupt_start_with_caller(next, MaybeLocation::caller());
535 }
536
537 #[track_caller]
541 pub fn try_interrupt_start(&mut self, next: T) -> Result<(), T> {
542 if self.has_transition() {
543 return Err(next);
544 }
545
546 self.interrupt_start_with_caller(next, MaybeLocation::caller());
547 Ok(())
548 }
549
550 fn interrupt_start_with_caller(&mut self, next: T, caller: MaybeLocation) {
551 self.set_transition(Interrupt(Interruption::Start(next)), caller);
552 }
553
554 #[track_caller]
560 pub fn interrupt_stop(&mut self, index: BehaviorIndex) {
561 self.interrupt_resume_with_caller(index.previous().unwrap(), MaybeLocation::caller());
562 }
563
564 #[track_caller]
571 pub fn try_interrupt_stop(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
572 if self.has_transition() || !self.has_index(index) {
573 return Err(index);
574 }
575
576 let Some(previous_index) = index.previous() else {
577 return Err(index);
578 };
579
580 self.interrupt_resume_with_caller(previous_index, MaybeLocation::caller());
581 Ok(())
582 }
583
584 #[track_caller]
588 pub fn interrupt_resume(&mut self, index: BehaviorIndex) {
589 self.interrupt_resume_with_caller(index, MaybeLocation::caller());
590 }
591
592 #[track_caller]
598 pub fn try_interrupt_resume(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
599 if self.has_transition() || !self.has_index(index) {
600 return Err(index);
601 }
602
603 self.interrupt_resume_with_caller(index, MaybeLocation::caller());
604 Ok(())
605 }
606
607 fn interrupt_resume_with_caller(&mut self, index: BehaviorIndex, caller: MaybeLocation) {
608 self.set_transition(Interrupt(Interruption::Resume(index)), caller);
609 }
610
611 #[track_caller]
618 pub fn stop(&mut self) {
619 self.stop_with_caller(MaybeLocation::caller());
620 }
621
622 #[track_caller]
628 pub fn try_stop(&mut self) -> bool {
629 if self.has_transition() || self.memory.is_empty() {
630 return false;
631 }
632
633 self.stop_with_caller(MaybeLocation::caller());
634 true
635 }
636
637 fn stop_with_caller(&mut self, caller: MaybeLocation) {
638 self.set_transition(Previous, caller);
639 }
640
641 #[track_caller]
646 pub fn reset(&mut self) {
647 self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
648 }
649
650 #[track_caller]
654 pub fn try_reset(&mut self) -> bool {
655 if self.has_transition() {
656 return false;
657 }
658
659 self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
660 true
661 }
662
663 fn set_transition(&mut self, transition: Transition<T>, caller: MaybeLocation) {
664 let previous = replace(self.transition.as_mut(), transition);
665 if !previous.is_none() {
666 warn!(
667 "transition override ({caller})): {previous:?} -> {:?}",
668 *self.transition
669 );
670 }
671 }
672
673 fn push(
674 &mut self,
675 instance: Instance<T>,
676 mut next: T,
677 initial: bool,
678 commands: &mut Commands,
679 ) -> bool {
680 if self.filter_next(&next) {
681 let previous = {
682 swap(self.current.as_mut(), &mut next);
683 next
684 };
685 self.invoke_start(Some(&previous), commands.instance(instance));
686 let index = self.memory.len();
687 if previous.is_resumable() {
688 let next_index = index + 1;
689 debug!(
690 "{instance:?}: {previous:?} (#{index}) -> {:?} (#{next_index})",
691 *self.current
692 );
693
694 previous.invoke_pause(&self.current, commands.instance(instance));
695
696 commands.queue(move |world: &mut World| {
697 world.trigger_with(
698 Pause {
699 instance,
700 index: BehaviorIndex(index),
701 },
702 EntityTrigger,
703 );
704 world.trigger_with(
705 Start {
706 instance,
707 index: BehaviorIndex(next_index),
708 initial,
709 },
710 EntityTrigger,
711 );
712 world.trigger_with(
713 Activate {
714 instance,
715 index: BehaviorIndex(next_index),
716 resume: false,
717 initial,
718 },
719 EntityTrigger,
720 );
721 });
722
723 self.memory.push(previous);
724 } else {
725 debug!(
726 "{instance:?}: {previous:?} (#{index}) -> {:?} (#{index})",
727 *self.current
728 );
729
730 previous.invoke_stop(&self.current, commands.instance(instance));
731
732 commands.queue(move |world: &mut World| {
733 world.trigger_with(
734 Stop {
735 instance,
736 index: BehaviorIndex(index),
737 behavior: previous,
738 interrupt: false,
739 },
740 EntityTrigger,
741 );
742 world.trigger_with(
743 Start {
744 instance,
745 index: BehaviorIndex(index),
746 initial,
747 },
748 EntityTrigger,
749 );
750 world.trigger_with(
751 Activate {
752 instance,
753 index: BehaviorIndex(index),
754 resume: false,
755 initial,
756 },
757 EntityTrigger,
758 );
759 })
760 }
761 true
762 } else {
763 warn!(
764 "{instance:?}: transition {:?} -> {next:?} is not allowed",
765 *self.current
766 );
767
768 commands.queue(move |world: &mut World| {
769 world.trigger_with(
770 Error {
771 instance,
772 error: TransitionError::RejectedNext(next),
773 },
774 EntityTrigger,
775 );
776 });
777
778 false
779 }
780 }
781
782 fn interrupt(&mut self, instance: Instance<T>, next: T, commands: &mut Commands) {
783 while self.filter_yield(&next) && !self.memory.is_empty() {
784 let index = self.memory.len();
785 if let Some(mut next) = self.memory.pop() {
786 let previous = {
787 swap(self.current.as_mut(), &mut next);
788 next
789 };
790 debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
791 previous.invoke_stop(&self.current, commands.instance(instance));
792
793 commands.queue(move |world: &mut World| {
794 world.trigger_with(
795 Stop {
796 instance,
797 index: BehaviorIndex(index),
798 behavior: previous,
799 interrupt: true,
800 },
801 EntityTrigger,
802 );
803 });
804 }
805 }
806
807 self.push(instance, next, false, commands);
808 }
809
810 fn pop(&mut self, instance: Instance<T>, commands: &mut Commands) -> bool {
811 let index = self.memory.len();
812
813 if let Some(mut next) = self.memory.pop() {
814 let next_index = self.memory.len();
815 debug!(
816 "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
817 *self.current
818 );
819 let previous = {
820 swap(self.current.as_mut(), &mut next);
821 next
822 };
823 self.invoke_resume(&previous, commands.instance(instance));
824 previous.invoke_stop(&self.current, commands.instance(instance));
825
826 commands.queue(move |world: &mut World| {
827 world.trigger_with(
828 Stop {
829 instance,
830 index: BehaviorIndex(index),
831 behavior: previous,
832 interrupt: false,
833 },
834 EntityTrigger,
835 );
836 world.trigger_with(
837 Resume {
838 instance,
839 index: BehaviorIndex(next_index),
840 },
841 EntityTrigger,
842 );
843 world.trigger_with(
844 Activate {
845 instance,
846 index: BehaviorIndex(next_index),
847 resume: true,
848 initial: false,
849 },
850 EntityTrigger,
851 );
852 });
853 true
854 } else {
855 warn!(
856 "{instance:?}: transition {:?} -> None is not allowed",
857 *self.current
858 );
859
860 commands.queue(move |world: &mut World| {
861 world.trigger_with(
862 Error {
863 instance,
864 error: TransitionError::<T>::NoPrevious,
865 },
866 EntityTrigger,
867 );
868 });
869
870 false
871 }
872 }
873
874 fn clear(&mut self, instance: Instance<T>, index: BehaviorIndex, commands: &mut Commands) {
875 while self.current_index() > index.next() {
877 let index = self.memory.len();
878 let previous = self.memory.pop().unwrap();
879 let next = self.memory.last().unwrap();
880 debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
881 previous.invoke_stop(next, commands.instance(instance));
882
883 commands.queue(move |world: &mut World| {
884 world.trigger_with(
885 Stop {
886 instance,
887 index: BehaviorIndex(index),
888 behavior: previous,
889 interrupt: true,
890 },
891 EntityTrigger,
892 );
893 });
894 }
895
896 self.pop(instance, commands);
898 }
899}
900
901impl<T: Behavior> Deref for BehaviorMutItem<'_, '_, T> {
902 type Target = T;
903
904 fn deref(&self) -> &Self::Target {
905 self.current()
906 }
907}
908
909impl<T: Behavior> DerefMut for BehaviorMutItem<'_, '_, T> {
910 fn deref_mut(&mut self) -> &mut Self::Target {
911 self.current_mut()
912 }
913}
914
915impl<T: Behavior> DetectChanges for BehaviorMutItem<'_, '_, T> {
916 fn is_added(&self) -> bool {
917 self.current.is_added()
918 }
919
920 fn is_changed(&self) -> bool {
921 self.current.is_changed()
922 }
923
924 fn last_changed(&self) -> Tick {
925 self.current.last_changed()
926 }
927
928 fn added(&self) -> Tick {
929 self.current.added()
930 }
931
932 fn changed_by(&self) -> MaybeLocation {
933 self.current.changed_by()
934 }
935}
936
937impl<T: Behavior> DetectChangesMut for BehaviorMutItem<'_, '_, T> {
938 type Inner = T;
939
940 fn set_changed(&mut self) {
941 self.current.set_changed()
942 }
943
944 fn set_last_changed(&mut self, last_changed: Tick) {
945 self.current.set_last_changed(last_changed)
946 }
947
948 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
949 self.current.bypass_change_detection()
950 }
951
952 fn set_added(&mut self) {
953 self.current.set_added()
954 }
955
956 fn set_last_added(&mut self, last_added: Tick) {
957 self.current.set_last_added(last_added)
958 }
959}
960
961impl<T: Behavior> AsRef<T> for BehaviorMutItem<'_, '_, T> {
962 fn as_ref(&self) -> &T {
963 self.current.as_ref()
964 }
965}
966
967impl<T: Behavior> AsMut<T> for BehaviorMutItem<'_, '_, T> {
968 fn as_mut(&mut self) -> &mut T {
969 self.current.as_mut()
970 }
971}
972
973impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
974 type Output = T;
975
976 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
977 if index == self.memory.stack.len() {
978 self.current()
979 } else {
980 &self.memory[index]
981 }
982 }
983}
984
985impl<T: Behavior> IndexMut<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
986 fn index_mut(&mut self, BehaviorIndex(index): BehaviorIndex) -> &mut Self::Output {
987 if index == self.memory.stack.len() {
988 self.current_mut()
989 } else {
990 &mut self.memory[index]
991 }
992 }
993}
994
995#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Reflect)]
1000pub struct BehaviorIndex(usize);
1001
1002impl BehaviorIndex {
1003 pub fn initial() -> Self {
1005 Self(0)
1006 }
1007
1008 pub fn previous(self) -> Option<Self> {
1010 if self == BehaviorIndex::initial() {
1011 return None;
1012 }
1013
1014 Some(Self(self.0.saturating_sub(1)))
1015 }
1016
1017 fn next(self) -> Self {
1018 Self(self.0.saturating_add(1))
1019 }
1020}
1021
1022#[derive(Component, Deref, DerefMut, Reflect)]
1023#[reflect(Component)]
1024struct Memory<T: Behavior> {
1025 stack: Vec<T>,
1026}
1027
1028impl<T: Behavior> Default for Memory<T> {
1029 fn default() -> Self {
1030 Self {
1031 stack: Vec::default(),
1032 }
1033 }
1034}
1035
1036#[macro_export]
1077macro_rules! match_next {
1078 { $curr:ident => $next:ident, $($from:pat => $to:pat),* $(,)? } => {
1079 match $curr {
1080 $(
1081 $from => matches!($next, $to),
1082 )*
1083 #[allow(unreachable_patterns)]
1084 _ => false,
1085 }
1086 };
1087}