double_dot_state 0.5.0

State management crate built for the Bevy game engine
Documentation
pub use bevy::prelude::*;
use bevy::state::state::FreelyMutableState;
pub use double_dot_macro::*;
use prelude::{DoubleStateEvent, DoubleStateTransition};

pub mod prelude {
    pub use bevy::prelude::*;
    use bevy::state::state::FreelyMutableState;
    pub use double_dot_macro::DoubleStates;

    use crate::watch_state_event;

    #[derive(Debug, Clone)]
    pub enum DoubleStateTransition<S>
    where
        S: DoubleStates,
    {
        Linear,
        Arbitrary(S),
    }

    pub enum DoubleStateSchedule<S>
    where
        S: DoubleStates + States,
    {
        OnEnter(OnEnter<S>),
        OnExit(OnExit<S>),
    }

    pub struct DoubleStateSystemConfig<S>
    where
        S: DoubleStates + States,
    {
        pub schedule: DoubleStateSchedule<S>,
        pub transition: DoubleStateTransition<S>,
    }

    #[derive(Debug, Clone, Message)]
    pub struct DoubleStateEvent<S: DoubleStates>(pub DoubleStateTransition<S>);
    pub trait AppExt {
        fn add_double_state<S: DoubleStates + States + FreelyMutableState>(&mut self) -> &mut Self;
    }

    impl AppExt for App {
        fn add_double_state<S: DoubleStates + States + FreelyMutableState>(&mut self) -> &mut Self {
            self.init_state::<S>()
                .add_message::<DoubleStateEvent<S>>()
                .add_systems(Update, watch_state_event::<S>)
        }
    }
}

fn watch_state_event<S: DoubleStates + States + FreelyMutableState>(
    mut state_event: MessageReader<DoubleStateEvent<S>>,
    mut next_state: ResMut<NextState<S>>,
    state: Res<State<S>>,
) {
    for event in state_event.read() {
        match &event.0 {
            DoubleStateTransition::Linear => {
                // info!("{:?}", state.0.linear_transition());
                next_state.set(state.linear_transition())
            }
            DoubleStateTransition::Arbitrary(arb_state) => {
                // info!("{:?}", state.0.arbitrary_transition(&arb_state));
                next_state.set(state.arbitrary_transition(&arb_state))
            }
        }
    }
}

/// Enum for Testing purposes
#[derive(Clone, Eq, PartialEq, Debug, Hash, DoubleStates, Default)]
#[allow(dead_code)]
enum TestState {
    #[linear(MainMenu)]
    Loading,
    #[arbitrary(Playing, Exit)]
    MainMenu,
    #[default]
    #[linear(Paused)]
    Playing,
    #[arbitrary(MainMenu, Exit)]
    Paused,
    Exit,
}