use core::{fmt::Debug, hash::Hash};
use bevy_ecs::schedule::Schedule;
use super::{state_set::StateSet, states::States};
pub trait ComputedStates: 'static + Send + Sync + Clone + PartialEq + Eq + Hash + Debug {
type SourceStates: StateSet;
const ALLOW_SAME_STATE_TRANSITIONS: bool = true;
fn compute(sources: Self::SourceStates) -> Option<Self>;
fn register_computed_state_systems(schedule: &mut Schedule) {
Self::SourceStates::register_computed_state_systems_in_schedule::<Self>(schedule);
}
}
impl<S: ComputedStates> States for S {
const DEPENDENCY_DEPTH: usize = S::SourceStates::SET_DEPENDENCY_DEPTH + 1;
}
#[cfg(test)]
mod tests {
use crate::{
app::{AppExtStates, StatesPlugin},
prelude::DespawnOnEnter,
state::{ComputedStates, StateTransition},
};
use bevy_app::App;
use bevy_ecs::component::Component;
use bevy_state_macros::States;
#[derive(Component)]
struct TestComponent;
#[derive(States, Default, PartialEq, Eq, Hash, Debug, Clone)]
struct TestState;
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
struct TestComputedState;
impl ComputedStates for TestComputedState {
type SourceStates = TestState;
fn compute(_: Self::SourceStates) -> Option<Self> {
Some(TestComputedState)
}
}
#[test]
fn computed_states_are_state_scoped_by_default() {
let mut app = App::new();
app.add_plugins(StatesPlugin);
app.insert_state(TestState);
app.add_computed_state::<TestComputedState>();
let world = app.world_mut();
world.spawn((DespawnOnEnter(TestComputedState), TestComponent));
assert!(world.query::<&TestComponent>().single(world).is_ok());
world.run_schedule(StateTransition);
assert_eq!(world.query::<&TestComponent>().iter(world).len(), 0);
}
}