moonshine_behavior/
lib.rs

1pub mod prelude {
2    pub use crate::{Behavior, BehaviorMut, BehaviorRef};
3    pub use moonshine_kind::{Instance, InstanceCommands};
4
5    pub use crate::transition::{
6        transition, Next, Previous, Reset, Transition, TransitionSequence,
7    };
8
9    pub use crate::events::{BehaviorEvent, BehaviorEvents};
10    pub use crate::plugin::BehaviorPlugin;
11
12    pub use crate::match_next;
13}
14
15pub mod events;
16pub mod plugin;
17pub mod transition;
18
19#[cfg(test)]
20mod tests;
21
22use std::fmt::Debug;
23use std::mem::{replace, swap};
24use std::ops::{Deref, DerefMut, Index, IndexMut};
25
26use bevy_derive::{Deref, DerefMut};
27use bevy_ecs::change_detection::MaybeLocation;
28use bevy_ecs::component::{Mutable, Tick};
29use bevy_ecs::{prelude::*, query::QueryData};
30use bevy_log::prelude::*;
31use bevy_reflect::prelude::*;
32use events::BehaviorEventsMut;
33use moonshine_kind::prelude::*;
34
35use crate::events::BehaviorEvent;
36
37use self::transition::*;
38
39pub trait Behavior: Component<Mutability = Mutable> + Debug + Sized {
40    /// Called when an interrupt is requested.
41    ///
42    /// If this returns `true`, the current behavior will stop to allow the next behavior to start.
43    /// The initial behavior is never allowed to yield.
44    fn filter_yield(&self, next: &Self) -> bool {
45        match_next! {
46            self => next,
47            _ => _,
48        }
49    }
50
51    /// Called before a new behavior is started.
52    ///
53    /// If this returns `false`, the transition fails.
54    /// See [`Error`](crate::events::BehaviorEvent) for details on how to handle transition failures.
55    fn filter_next(&self, next: &Self) -> bool {
56        match_next! {
57            self => next,
58            _ => _,
59        }
60    }
61
62    /// Called after a behavior is paused.
63    ///
64    /// If this returns `false`, the paused behavior will be stopped immediatedly and discarded.
65    /// No [`Pause`](crate::events::BehaviorEvent) event will be sent in this case.
66    fn is_resumable(&self) -> bool {
67        match self {
68            _ => true,
69        }
70    }
71
72    /// Called during [`transition`](transition::transition) just after the behavior is started.
73    fn on_start(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
74
75    /// Called during [`transition`](transition::transition) just after the behavior is paused.
76    fn on_pause(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
77
78    /// Called during [`transition`](transition::transition) just after the behavior is resumed.
79    fn on_resume(&self, _previous: &Self, _commands: InstanceCommands<Self>) {}
80
81    /// Called during [`transition`](transition::transition) just after the behavior is stopped.
82    fn on_stop(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
83
84    /// Called during [`transition`](transition::transition) just after the behavior is started *or* resumed.
85    fn on_activate(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
86
87    /// Called during [`transition`](transition::transition) just after the behavior is paused *or* stopped.
88    fn on_suspend(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
89}
90
91#[doc(hidden)]
92trait BehaviorHooks: Behavior {
93    fn invoke_start(&self, previous: Option<&Self>, mut commands: InstanceCommands<Self>) {
94        self.on_start(previous, commands.reborrow());
95        self.on_activate(previous, commands);
96    }
97
98    fn invoke_pause(&self, current: &Self, mut commands: InstanceCommands<Self>) {
99        self.on_suspend(current, commands.reborrow());
100        self.on_pause(current, commands);
101    }
102
103    fn invoke_resume(&self, previous: &Self, mut commands: InstanceCommands<Self>) {
104        self.on_resume(previous, commands.reborrow());
105        self.on_activate(Some(previous), commands);
106    }
107
108    fn invoke_stop(&self, current: &Self, mut commands: InstanceCommands<Self>) {
109        self.on_suspend(current, commands.reborrow());
110        self.on_stop(current, commands);
111    }
112}
113
114impl<T: Behavior> BehaviorHooks for T {}
115
116/// Query data for a [`Behavior`].
117///
118/// # Usage
119///
120/// This provides a read-only reference to the current behavior state and all previous states in the stack.
121///
122/// Additionally, it provides methods to check for pending transitions ([`has_transition`](BehaviorRefItem::has_transition)),
123/// active transition sequences ([`has_sequence`](BehaviorRefItem::has_sequence)) and the current
124/// behavior index ([`index`](BehaviorRefItem::index)).
125#[derive(QueryData)]
126pub struct BehaviorRef<T: Behavior> {
127    current: Ref<'static, T>,
128    memory: &'static Memory<T>,
129    transition: &'static Transition<T>,
130    sequence: Has<TransitionSequence<T>>,
131}
132
133impl<T: Behavior> BehaviorRef<T> {
134    /// Creates a new [`BehaviorRef`] item from an [`EntityRef`].
135    pub fn from_entity(entity: EntityRef) -> Option<BehaviorRefItem<T>> {
136        Some(BehaviorRefItem {
137            current: entity.get_ref::<T>()?,
138            memory: entity.get::<Memory<T>>()?,
139            transition: entity.get::<Transition<T>>()?,
140            sequence: entity.contains::<TransitionSequence<T>>(),
141        })
142    }
143}
144
145impl<T: Behavior> BehaviorRefItem<'_, T> {
146    /// Returns the current [`Behavior`] state.
147    pub fn current(&self) -> &T {
148        &self.current
149    }
150
151    /// Returns the index associated with the current [`Behavior`] state.
152    ///
153    /// # Usage
154    ///
155    /// Each behavior state is associated with an index which corresponds to their position in the stack.
156    ///
157    /// The current behavior is always at the top of the stack.
158    /// The initial behavior always has the index of `0``.
159    ///
160    /// This index may be used to identify the exact unique behavior state when multiple similar states are in the stack.
161    pub fn index(&self) -> usize {
162        self.memory.len()
163    }
164
165    /// Returns the previous [`Behavior`] state in the stack.
166    ///
167    /// # Usage
168    ///
169    /// Note that this is **NOT** the previously active state.
170    /// Instead, this is the previous state which was active before the current one was started.
171    ///
172    /// To access the previously active state, handle [`Stop`](crate::events::BehaviorEvent::Stop) instead.
173    pub fn previous(&self) -> Option<&T> {
174        self.memory.last()
175    }
176
177    /// Returns an iterator over all [`Behavior`] states in the stack, including the current one.
178    ///
179    /// The iterator is ordered from the initial behavior (index = 0) to the current one.
180    pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
181        self.memory.iter().chain(std::iter::once(self.current()))
182    }
183
184    /// Returns `true` if there is any pending [`Transition`] for this [`Behavior`].
185    ///
186    /// # Usage
187    ///
188    /// By design, only one transition is allowed per [`transition`](crate::transition::transition) cycle.
189    ///
190    /// The only exception to this rule is if the behavior is interrupted or reset where multiple states
191    /// may be stopped within a single cycle.
192    ///
193    /// If a transition is requested while another is pending, it would be overriden.
194    /// The transition helper methods [`start`](BehaviorMutItem::start), [`interrupt_start`](BehaviorMutItem::interrupt_start),
195    /// [`stop`](BehaviorMutItem::stop) and [`reset`](BehaviorMutItem::reset) all trigger a warning in this case.
196    ///
197    /// Because of this, this method is useful to avoid unintentional transition overrides.
198    pub fn has_transition(&self) -> bool {
199        !self.transition.is_none()
200    }
201
202    /// Returns `true` if there is any [`TransitionSequence`] running on this [`Behavior`].
203    ///
204    /// This is useful to allow transition sequences to finish before starting a new behavior.
205    pub fn has_sequence(&self) -> bool {
206        self.sequence
207    }
208}
209
210impl<T: Behavior> Deref for BehaviorRefItem<'_, T> {
211    type Target = T;
212
213    fn deref(&self) -> &Self::Target {
214        self.current()
215    }
216}
217
218impl<T: Behavior> AsRef<T> for BehaviorRefItem<'_, T> {
219    fn as_ref(&self) -> &T {
220        &self.current
221    }
222}
223
224impl<T: Behavior> DetectChanges for BehaviorRefItem<'_, T> {
225    fn is_added(&self) -> bool {
226        self.current.is_added()
227    }
228
229    fn is_changed(&self) -> bool {
230        self.current.is_changed()
231    }
232
233    fn last_changed(&self) -> Tick {
234        self.current.last_changed()
235    }
236
237    fn added(&self) -> Tick {
238        self.current.added()
239    }
240
241    fn changed_by(&self) -> MaybeLocation {
242        self.current.changed_by()
243    }
244}
245
246impl<T: Behavior> Index<usize> for BehaviorRefItem<'_, T> {
247    type Output = T;
248
249    fn index(&self, index: usize) -> &Self::Output {
250        if index == self.memory.stack.len() {
251            self.current()
252        } else {
253            &self.memory[index]
254        }
255    }
256}
257
258/// Query data for a [`Behavior`] with mutable access.
259///
260/// # Usage
261///
262/// This provides a mutable reference to the current behavior state and all previous states in the stack.
263///
264/// See [`BehaviorRef`] for more details.
265#[derive(QueryData)]
266#[query_data(mutable)]
267pub struct BehaviorMut<T: Behavior> {
268    current: Mut<'static, T>,
269    memory: &'static mut Memory<T>,
270    transition: &'static mut Transition<T>,
271    sequence: Has<TransitionSequence<T>>,
272}
273
274impl<T: Behavior> BehaviorMutReadOnlyItem<'_, T> {
275    /// See [`BehaviorRefItem::current`].
276    pub fn current(&self) -> &T {
277        &self.current
278    }
279
280    /// See [`BehaviorRefItem::previous`].
281    pub fn previous(&self) -> Option<&T> {
282        self.memory.last()
283    }
284
285    /// See [`BehaviorRefItem::iter`].
286    pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
287        self.memory.iter().chain(std::iter::once(self.current()))
288    }
289
290    /// See [`BehaviorRefItem::index`].
291    pub fn index(&self) -> usize {
292        self.memory.len()
293    }
294
295    /// See [`BehaviorRefItem::has_transition`].
296    pub fn has_transition(&self) -> bool {
297        !self.transition.is_none()
298    }
299
300    /// See [`BehaviorRefItem::has_sequence`].
301    pub fn has_sequence(&self) -> bool {
302        self.sequence
303    }
304}
305
306impl<T: Behavior> Deref for BehaviorMutReadOnlyItem<'_, T> {
307    type Target = T;
308
309    fn deref(&self) -> &Self::Target {
310        self.current()
311    }
312}
313
314impl<T: Behavior> AsRef<T> for BehaviorMutReadOnlyItem<'_, T> {
315    fn as_ref(&self) -> &T {
316        self.current.as_ref()
317    }
318}
319
320impl<T: Behavior> DetectChanges for BehaviorMutReadOnlyItem<'_, T> {
321    fn is_added(&self) -> bool {
322        self.current.is_added()
323    }
324
325    fn is_changed(&self) -> bool {
326        self.current.is_changed()
327    }
328
329    fn last_changed(&self) -> Tick {
330        self.current.last_changed()
331    }
332
333    fn added(&self) -> Tick {
334        self.current.added()
335    }
336
337    fn changed_by(&self) -> MaybeLocation {
338        self.current.changed_by()
339    }
340}
341
342impl<T: Behavior> Index<usize> for BehaviorMutReadOnlyItem<'_, T> {
343    type Output = T;
344
345    fn index(&self, index: usize) -> &Self::Output {
346        if index == self.memory.stack.len() {
347            self.current()
348        } else {
349            &self.memory[index]
350        }
351    }
352}
353
354impl<T: Behavior> BehaviorMutItem<'_, T> {
355    /// Returns the current [`Behavior`] state.
356    pub fn current(&self) -> &T {
357        &self.current
358    }
359
360    /// Returns the current [`Behavior`] state as a mutable.
361    pub fn current_mut(&mut self) -> &mut T {
362        self.current.as_mut()
363    }
364
365    /// See [`BehaviorRefItem::previous`].
366    pub fn previous(&self) -> Option<&T> {
367        self.memory.last()
368    }
369
370    /// Returns the previous [`Behavior`] state as a mutable.
371    ///
372    /// See [`BehaviorRefItem::previous`] for more details.
373    pub fn previous_mut(&mut self) -> Option<&mut T> {
374        self.memory.last_mut()
375    }
376
377    /// See [`BehaviorRefItem::iter`].
378    pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
379        self.memory.iter().chain(std::iter::once(self.current()))
380    }
381
382    /// Returns a mutable iterator over all [`Behavior`] states in the stack, including the current one.
383    ///
384    /// See [`BehaviorRefItem::iter`] for more details.
385    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
386        self.memory
387            .iter_mut()
388            .chain(std::iter::once(self.current.as_mut()))
389    }
390
391    /// See [`BehaviorRefItem::index`].
392    pub fn index(&self) -> usize {
393        self.memory.len()
394    }
395
396    /// See [`BehaviorRefItem::has_transition`].
397    pub fn has_transition(&self) -> bool {
398        !self.transition.is_none()
399    }
400
401    /// See [`BehaviorRefItem::has_sequence`].
402    pub fn has_sequence(&self) -> bool {
403        self.sequence
404    }
405
406    /// Starts the given `next` behavior.
407    ///
408    /// This operation pushes the current behavior onto the stack and inserts the new behavior.
409    ///
410    /// Note that this will fail if the current behavior rejects `next` through [`Behavior::filter_next`].
411    /// See [`Error`](crate::events::BehaviorEvent) for details on how to handle transition failures.
412    pub fn start(&mut self, next: T) {
413        self.set_transition(Next(next));
414    }
415
416    /// Attempts to start the given `next` behavior if there are no pending transitions and the
417    /// current behavior allows it.
418    ///
419    /// Note that it's still possible for the transition to fail if the current behavior mutates
420    /// in such a way as to no longer allow the transition between the time this function is called
421    /// and when the [`transition`](crate::transition::transition) system runs.
422    ///
423    /// Do **NOT** use this method to react to transition failures.
424    /// See [`Error`](crate::events::BehaviorEvent) for details on how to correctly handle transition failures.
425    ///
426    /// # Usage
427    ///
428    /// This is similar to [`start`](BehaviorMutItem::start) but will return an error containing
429    /// the given `next` behavior if it fails.
430    ///
431    /// This is useful for fire-and-forget transitions where you don't want to override a
432    /// pending transition or may expect a transition failure.
433    ///
434    /// If multiple systems call this method before transition, only the first one will succeed.
435    pub fn try_start(&mut self, next: T) -> Result<(), T> {
436        if self.has_transition() || !self.filter_next(&next) {
437            return Err(next);
438        }
439
440        self.start(next);
441        Ok(())
442    }
443
444    /// Interrupts the current behavior and starts the given `next` behavior.
445    ///
446    /// This operation stops all behaviors which yield to the new behavior and pushes it onto the stack.
447    /// See [`Behavior::filter_yield`] for details on how to define how states yield to each other.
448    ///
449    /// This also removes any remaining [`TransitionSequence`] steps.
450    ///
451    /// The initial behavior is never allowed to yield.
452    ///
453    /// Note that this will fail if the first non-yielding behavior rejects `next` through [`Behavior::filter_next`].
454    /// See [`Error`](crate::events::BehaviorEvent) for details on how to handle transition failures.
455    pub fn interrupt_start(&mut self, next: T) {
456        self.set_transition(Interrupt(next));
457    }
458
459    /// Stops the current behavior.
460    ///
461    /// This operation pops the current behavior off the stack and resumes the previous behavior.
462    ///
463    /// Note that this will fail if the current behavior is the initial behavior.
464    /// See [`Error`](crate::events::BehaviorEvent) for details on how to handle transition failures.
465    pub fn stop(&mut self) {
466        self.set_transition(Previous);
467    }
468
469    /// Stops the current and all previous behaviors and resumes the initial behavior.
470    ///
471    /// This operation clears the stack and resumes the initial behavior. It can never fail.
472    /// If the stack is empty (i.e. initial behavior), it does nothing.
473    pub fn reset(&mut self) {
474        self.set_transition(Reset);
475    }
476
477    fn set_transition(&mut self, transition: Transition<T>) {
478        let previous = replace(self.transition.as_mut(), transition);
479        if !previous.is_none() {
480            warn!(
481                "transition override: {previous:?} -> {:?}",
482                *self.transition
483            );
484        }
485    }
486
487    fn push(
488        &mut self,
489        instance: Instance<T>,
490        mut next: T,
491        events: &mut BehaviorEventsMut<T>,
492        commands: &mut Commands,
493    ) -> bool {
494        if self.filter_next(&next) {
495            let previous = {
496                swap(self.current.as_mut(), &mut next);
497                next
498            };
499            self.invoke_start(Some(&previous), commands.instance(instance));
500            let index = self.memory.len();
501            if previous.is_resumable() {
502                let new_index = index + 1;
503                debug!(
504                    "{instance:?}: {previous:?} (#{index}) -> {:?} (#{new_index})",
505                    *self.current
506                );
507                previous.invoke_pause(&self.current, commands.instance(instance));
508                events.write(BehaviorEvent::Pause { instance, index });
509                events.write(BehaviorEvent::Start {
510                    instance,
511                    index: new_index,
512                });
513                self.memory.push(previous);
514            } else {
515                debug!(
516                    "{instance:?}: {previous:?} (#{index}) -> {:?} (#{index})",
517                    *self.current
518                );
519                previous.invoke_stop(&self.current, commands.instance(instance));
520                events.write(BehaviorEvent::Start { instance, index });
521                events.write(BehaviorEvent::Stop {
522                    instance,
523                    behavior: previous,
524                });
525            }
526            true
527        } else {
528            warn!(
529                "{instance:?}: transition {:?} -> {next:?} is not allowed",
530                *self.current
531            );
532            events.write(BehaviorEvent::Error {
533                instance,
534                error: TransitionError::RejectedNext(next),
535            });
536            false
537        }
538    }
539
540    fn interrupt(
541        &mut self,
542        instance: Instance<T>,
543        next: T,
544        events: &mut BehaviorEventsMut<T>,
545        commands: &mut Commands,
546    ) {
547        while self.filter_yield(&next) && !self.memory.is_empty() {
548            let index = self.memory.len();
549            if let Some(mut next) = self.memory.pop() {
550                let next_index = self.memory.len();
551                debug!(
552                    "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
553                    *self.current
554                );
555                let previous = {
556                    swap(self.current.as_mut(), &mut next);
557                    next
558                };
559                previous.invoke_stop(&self.current, commands.instance(instance));
560                events.write(BehaviorEvent::Stop {
561                    instance,
562                    behavior: previous,
563                });
564            }
565        }
566
567        self.push(instance, next, events, commands);
568    }
569
570    fn pop(
571        &mut self,
572        instance: Instance<T>,
573        events: &mut BehaviorEventsMut<T>,
574        commands: &mut Commands,
575    ) -> bool {
576        let index = self.memory.len();
577        if let Some(mut next) = self.memory.pop() {
578            let next_index = self.memory.len();
579            debug!(
580                "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
581                *self.current
582            );
583            let previous = {
584                swap(self.current.as_mut(), &mut next);
585                next
586            };
587            self.invoke_resume(&previous, commands.instance(instance));
588            previous.invoke_stop(&self.current, commands.instance(instance));
589            events.write(BehaviorEvent::Resume {
590                instance,
591                index: next_index,
592            });
593            events.write(BehaviorEvent::Stop {
594                instance,
595                behavior: previous,
596            });
597            true
598        } else {
599            warn!(
600                "{instance:?}: transition {:?} -> None is not allowed",
601                *self.current
602            );
603            events.write(BehaviorEvent::Error {
604                instance,
605                error: TransitionError::NoPrevious,
606            });
607            false
608        }
609    }
610
611    fn clear(
612        &mut self,
613        instance: Instance<T>,
614        events: &mut BehaviorEventsMut<T>,
615        commands: &mut Commands,
616    ) {
617        while self.memory.len() > 1 {
618            let index = self.memory.len();
619            let previous = self.memory.pop().unwrap();
620            let next_index = self.memory.len();
621            let next = self.memory.last().unwrap();
622            debug!(
623                "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
624                *self.current
625            );
626            previous.invoke_stop(next, commands.instance(instance));
627            events.write(BehaviorEvent::Stop {
628                instance,
629                behavior: previous,
630            });
631        }
632
633        self.pop(instance, events, commands);
634    }
635}
636
637impl<T: Behavior> Deref for BehaviorMutItem<'_, T> {
638    type Target = T;
639
640    fn deref(&self) -> &Self::Target {
641        self.current()
642    }
643}
644
645impl<T: Behavior> DerefMut for BehaviorMutItem<'_, T> {
646    fn deref_mut(&mut self) -> &mut Self::Target {
647        self.current_mut()
648    }
649}
650
651impl<T: Behavior> DetectChanges for BehaviorMutItem<'_, T> {
652    fn is_added(&self) -> bool {
653        self.current.is_added()
654    }
655
656    fn is_changed(&self) -> bool {
657        self.current.is_changed()
658    }
659
660    fn last_changed(&self) -> Tick {
661        self.current.last_changed()
662    }
663
664    fn added(&self) -> Tick {
665        self.current.added()
666    }
667
668    fn changed_by(&self) -> MaybeLocation {
669        self.current.changed_by()
670    }
671}
672
673impl<T: Behavior> DetectChangesMut for BehaviorMutItem<'_, T> {
674    type Inner = T;
675
676    fn set_changed(&mut self) {
677        self.current.set_changed()
678    }
679
680    fn set_last_changed(&mut self, last_changed: Tick) {
681        self.current.set_last_changed(last_changed)
682    }
683
684    fn bypass_change_detection(&mut self) -> &mut Self::Inner {
685        self.current.bypass_change_detection()
686    }
687
688    fn set_added(&mut self) {
689        self.current.set_added()
690    }
691
692    fn set_last_added(&mut self, last_added: Tick) {
693        self.current.set_last_added(last_added)
694    }
695}
696
697impl<T: Behavior> AsRef<T> for BehaviorMutItem<'_, T> {
698    fn as_ref(&self) -> &T {
699        self.current.as_ref()
700    }
701}
702
703impl<T: Behavior> AsMut<T> for BehaviorMutItem<'_, T> {
704    fn as_mut(&mut self) -> &mut T {
705        self.current.as_mut()
706    }
707}
708
709impl<T: Behavior> Index<usize> for BehaviorMutItem<'_, T> {
710    type Output = T;
711
712    fn index(&self, index: usize) -> &Self::Output {
713        if index == self.memory.stack.len() {
714            self.current()
715        } else {
716            &self.memory[index]
717        }
718    }
719}
720
721impl<T: Behavior> IndexMut<usize> for BehaviorMutItem<'_, T> {
722    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
723        if index == self.memory.stack.len() {
724            self.current_mut()
725        } else {
726            &mut self.memory[index]
727        }
728    }
729}
730
731#[derive(Component, Deref, DerefMut, Reflect)]
732#[reflect(Component)]
733struct Memory<T: Behavior> {
734    stack: Vec<T>,
735}
736
737impl<T: Behavior> Default for Memory<T> {
738    fn default() -> Self {
739        Self {
740            stack: Vec::default(),
741        }
742    }
743}
744
745/// A convenient macro for implementation of [`Behavior::filter_next`].
746///
747/// # Usage
748/// For any given pair of states `curr` and `next`, this match expands into a match arm such that:
749/// ```rust,ignore
750/// match curr {
751///     From => matches!(next, To)
752/// }
753/// ```
754/// where `From` is the current possible state, and `To` is the next allowed state.
755///
756/// # Example
757///
758/// ```rust
759/// # use bevy::prelude::*;
760/// # use moonshine_behavior::prelude::*;
761/// #[derive(Component, Debug)]
762/// enum Soldier {
763///     Idle,
764///     Crouch,
765///     Fire,
766///     Sprint,
767///     Jump,
768/// }
769///
770/// impl Behavior for Soldier {
771///     fn filter_next(&self, next: &Self) -> bool {
772///         use Soldier::*;
773///         match_next! {
774///             self => next,
775///             Idle => Crouch | Sprint | Fire | Jump,
776///             Crouch => Sprint | Fire,
777///             Sprint => Jump,
778///         }
779///     }
780/// }
781///
782/// # assert!(Soldier::Idle.filter_next(&Soldier::Crouch));
783/// # assert!(!Soldier::Sprint.filter_next(&Soldier::Fire));
784/// ```
785#[macro_export]
786macro_rules! match_next {
787    { $curr:ident => $next:ident, $($from:pat => $to:pat),* $(,)? } => {
788        match $curr {
789            $(
790                $from => matches!($next, $to),
791            )*
792            #[allow(unreachable_patterns)]
793            _ => false,
794        }
795    };
796}