use alloc::{vec, vec::Vec};
#[cfg(feature = "bevy_reflect")]
use bevy_ecs::reflect::ReflectResource;
use bevy_ecs::{
component::Component,
resource::Resource,
system::{Commands, ResMut, SystemParamItem},
world::{FromWorld, World},
};
use tiny_bail::prelude::*;
use crate::{
next_state::{NextState, NextStateMut},
state::State,
};
#[derive(Resource, Component, Debug)]
#[cfg_attr(
feature = "bevy_reflect",
derive(bevy_reflect::Reflect),
reflect(Resource)
)]
pub struct NextStateStack<S: State<Next = Self>> {
stack: Vec<Option<S>>,
bases: Vec<usize>,
}
impl<S: State<Next = Self>> NextState for NextStateStack<S> {
type State = S;
type Param = ();
fn empty() -> Self {
Self {
stack: Vec::new(),
bases: Vec::new(),
}
}
fn next_state<'s>(
&'s self,
_param: &'s SystemParamItem<Self::Param>,
) -> Option<&'s Self::State> {
self.get()
}
}
impl<S: State<Next = Self>> NextStateMut for NextStateStack<S> {
type ParamMut = ();
fn next_state_from_mut<'s>(
&'s self,
_param: &'s SystemParamItem<Self::ParamMut>,
) -> Option<&'s Self::State> {
self.get()
}
fn next_state_mut<'s>(
&'s mut self,
_param: &'s mut SystemParamItem<Self::ParamMut>,
) -> Option<&'s mut Self::State> {
self.get_mut()
}
fn set_next_state(
&mut self,
_param: &mut SystemParamItem<Self::ParamMut>,
state: Option<Self::State>,
) {
self.set(state);
}
}
impl<S: State<Next = Self> + FromWorld> FromWorld for NextStateStack<S> {
fn from_world(world: &mut World) -> Self {
Self::new(S::from_world(world))
}
}
impl<S: State<Next = Self>> NextStateStack<S> {
pub fn new(state: S) -> Self {
Self {
stack: vec![Some(state)],
bases: Vec::new(),
}
}
pub fn with_base(state: S) -> Self {
Self {
stack: vec![Some(state)],
bases: vec![1],
}
}
pub fn base(&self) -> usize {
self.bases.last().copied().unwrap_or_default()
}
pub fn acquire(&mut self) -> &mut Self {
self.bases.push(self.stack.len());
self
}
pub fn release(&mut self) -> &mut Self {
self.bases.pop();
self
}
pub fn get(&self) -> Option<&S> {
self.stack.last().and_then(|x| x.as_ref())
}
pub fn get_mut(&mut self) -> Option<&mut S> {
self.stack.last_mut().and_then(|x| x.as_mut())
}
pub fn set(&mut self, state: Option<S>) {
if self.stack.is_empty() {
self.stack.push(state);
} else {
*self.stack.last_mut().unwrap() = state;
}
}
pub fn clear(&mut self) -> &mut Self {
self.stack.drain(self.base()..);
self
}
pub fn pop(&mut self) -> &mut Self {
if self.stack.len() > self.base() {
self.stack.pop();
}
self
}
pub fn push(&mut self, state: S) -> &mut Self {
self.stack.push(Some(state));
self
}
}
pub trait NextStateStackMut: State<Next = NextStateStack<Self>> {
fn acquire(mut stack: ResMut<NextStateStack<Self>>) {
stack.acquire();
}
fn release(mut stack: ResMut<NextStateStack<Self>>) {
stack.release();
}
fn clear(mut stack: ResMut<NextStateStack<Self>>) {
stack.clear();
}
fn pop(mut stack: ResMut<NextStateStack<Self>>) {
stack.pop();
}
}
impl<S: State<Next = NextStateStack<S>>> NextStateStackMut for S {}
pub trait NextStateStackMutExtClone: NextStateStackMut + Clone {
fn push(self) -> impl Fn(ResMut<NextStateStack<Self>>) {
move |mut stack| {
stack.push(self.clone());
}
}
fn clear_push(self) -> impl Fn(ResMut<NextStateStack<Self>>) {
move |mut stack| {
stack.clear().push(self.clone());
}
}
fn pop_push(self) -> impl Fn(ResMut<NextStateStack<Self>>) {
move |mut stack| {
stack.pop().push(self.clone());
}
}
}
impl<S: NextStateStackMut + Clone> NextStateStackMutExtClone for S {}
pub trait NextStateStackCommandsExt {
fn state_stack_acquire<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self;
fn state_stack_release<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self;
fn state_stack_clear<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self;
fn state_stack_pop<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self;
fn state_stack_push<S: State<Next = NextStateStack<S>>>(&mut self, state: S) -> &mut Self;
fn state_stack_clear_push<S: State<Next = NextStateStack<S>>>(&mut self, state: S)
-> &mut Self;
fn state_stack_pop_push<S: State<Next = NextStateStack<S>>>(&mut self, state: S) -> &mut Self;
}
impl NextStateStackCommandsExt for Commands<'_, '_> {
fn state_stack_acquire<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>()).acquire();
});
self
}
fn state_stack_release<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>()).release();
});
self
}
fn state_stack_clear<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>()).clear();
});
self
}
fn state_stack_pop<S: State<Next = NextStateStack<S>>>(&mut self) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>()).pop();
});
self
}
fn state_stack_push<S: State<Next = NextStateStack<S>>>(&mut self, state: S) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>()).push(state);
});
self
}
fn state_stack_clear_push<S: State<Next = NextStateStack<S>>>(
&mut self,
state: S,
) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>())
.clear()
.push(state);
});
self
}
fn state_stack_pop_push<S: State<Next = NextStateStack<S>>>(&mut self, state: S) -> &mut Self {
self.queue(move |world: &mut World| {
r!(world.get_resource_mut::<NextStateStack<S>>())
.pop()
.push(state);
});
self
}
}