use bevy_ecs::system::{Res, ResMut, StaticSystemParam, SystemParam};
use crate::{
next_state::{NextState, NextStateMut, TriggerStateFlush},
pattern::{StatePattern, StateTransPattern},
state::{State, StateMut},
};
#[derive(SystemParam)]
pub struct CurrentRef<'w, S: State>(Option<Res<'w, S>>);
impl<S: State> CurrentRef<'_, S> {
pub fn get(&self) -> Option<&S> {
self.0.as_deref()
}
pub fn unwrap(&self) -> &S {
self.get().unwrap()
}
pub fn is_disabled(&self) -> bool {
self.0.is_none()
}
pub fn is_enabled(&self) -> bool {
self.0.is_some()
}
pub fn is_in<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), Some(x) if pattern.matches(x))
}
}
#[derive(SystemParam)]
pub struct CurrentMut<'w, S: State>(Option<ResMut<'w, S>>);
impl<S: State> CurrentMut<'_, S> {
pub fn get(&self) -> Option<&S> {
self.0.as_deref()
}
pub fn get_mut(&mut self) -> Option<&mut S> {
self.0.as_deref_mut()
}
pub fn unwrap(&self) -> &S {
self.get().unwrap()
}
pub fn unwrap_mut(&mut self) -> &mut S {
self.get_mut().unwrap()
}
pub fn is_disabled(&self) -> bool {
self.0.is_none()
}
pub fn is_enabled(&self) -> bool {
self.0.is_some()
}
pub fn is_in<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), Some(x) if pattern.matches(x))
}
}
#[derive(SystemParam)]
pub struct NextRef<'w, 's, S: State> {
next: Res<'w, <S as State>::Next>,
next_param: StaticSystemParam<'w, 's, <<S as State>::Next as NextState>::Param>,
trigger: Res<'w, TriggerStateFlush<S>>,
}
impl<S: State> NextRef<'_, '_, S> {
pub fn get(&self) -> Option<&S> {
self.next.next_state(&self.next_param)
}
pub fn unwrap(&self) -> &S {
self.get().unwrap()
}
pub fn will_be_disabled(&self) -> bool {
self.get().is_none()
}
pub fn will_be_enabled(&self) -> bool {
self.get().is_some()
}
pub fn will_be_in<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), Some(x) if pattern.matches(x))
}
pub fn is_triggered(&self) -> bool {
self.trigger.0
}
}
#[derive(SystemParam)]
pub struct NextMut<'w, 's, S: StateMut> {
next: ResMut<'w, <S as State>::Next>,
next_param: StaticSystemParam<'w, 's, <<S as State>::Next as NextStateMut>::ParamMut>,
trigger: ResMut<'w, TriggerStateFlush<S>>,
}
impl<S: StateMut + Default> NextMut<'_, '_, S> {
pub fn enable_default(&mut self) {
if self.will_be_disabled() {
self.enter(S::default())
}
}
pub fn toggle_default(&mut self) {
if self.will_be_disabled() {
self.enter_default();
} else {
self.disable();
}
}
pub fn enter_default(&mut self) {
self.enter(S::default());
}
}
impl<S: StateMut> NextMut<'_, '_, S> {
pub fn get(&self) -> Option<&S> {
self.next.next_state_from_mut(&self.next_param)
}
pub fn get_mut(&mut self) -> Option<&mut S> {
self.next.next_state_mut(&mut self.next_param)
}
pub fn set(&mut self, state: Option<S>) {
self.next.set_next_state(&mut self.next_param, state);
}
pub fn unwrap(&self) -> &S {
self.get().unwrap()
}
pub fn unwrap_mut(&mut self) -> &mut S {
self.get_mut().unwrap()
}
pub fn will_be_disabled(&self) -> bool {
self.get().is_none()
}
pub fn will_be_enabled(&self) -> bool {
self.get().is_some()
}
pub fn will_be_in<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), Some(x) if pattern.matches(x))
}
pub fn is_triggered(&self) -> bool {
self.trigger.0
}
pub fn trigger(&mut self) -> &mut Self {
self.trigger.0 = true;
self
}
pub fn reset_trigger(&mut self) -> &mut Self {
self.trigger.0 = false;
self
}
pub fn disable(&mut self) {
self.set(None);
}
pub fn enable(&mut self, value: S) {
if self.will_be_disabled() {
self.enter(value);
}
}
pub fn toggle(&mut self, value: S) {
if self.will_be_disabled() {
self.enter(value);
} else {
self.disable();
}
}
pub fn enter(&mut self, value: S) {
self.set(Some(value));
}
}
#[derive(SystemParam)]
pub struct FlushRef<'w, 's, S: State> {
pub current: CurrentRef<'w, S>,
pub next: NextRef<'w, 's, S>,
}
impl<S: State + Eq> FlushRef<'_, '_, S> {
pub fn will_refresh<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(
self.get(),
(Some(x), Some(y)) if x == y && pattern.matches(y),
)
}
pub fn will_change(&self) -> bool {
matches!(self.get(), (x, y) if x != y)
}
}
impl<S: State> FlushRef<'_, '_, S> {
pub fn get(&self) -> (Option<&S>, Option<&S>) {
(self.current.get(), self.next.get())
}
pub fn unwrap(&self) -> (&S, &S) {
let (current, next) = self.get();
(current.unwrap(), next.unwrap())
}
pub fn will_exit<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (Some(x), _) if pattern.matches(x))
}
pub fn will_disable<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (Some(x), None) if pattern.matches(x))
}
pub fn will_enter<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (_, Some(y)) if pattern.matches(y))
}
pub fn will_enable<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (None, Some(y)) if pattern.matches(y))
}
pub fn will_trans<P: StateTransPattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (Some(x), Some(y)) if pattern.matches(x, y))
}
}
#[derive(SystemParam)]
pub struct FlushMut<'w, 's, S: StateMut> {
pub current: CurrentRef<'w, S>,
pub next: NextMut<'w, 's, S>,
}
impl<S: StateMut + Clone> FlushMut<'_, '_, S> {
pub fn reset(&mut self) {
self.next.reset_trigger().set(self.current.get().cloned());
}
pub fn refresh(&mut self) {
self.next.trigger().set(self.current.get().cloned());
}
}
impl<S: StateMut + Eq> FlushMut<'_, '_, S> {
pub fn will_refresh<P: StatePattern<S>>(&mut self, pattern: &P) -> bool {
matches!(
self.get(),
(Some(x), Some(y)) if x == y && pattern.matches(y),
)
}
}
impl<S: StateMut> FlushMut<'_, '_, S> {
pub fn get(&self) -> (Option<&S>, Option<&S>) {
(self.current.get(), self.next.get())
}
pub fn get_mut(&mut self) -> (Option<&S>, Option<&mut S>) {
(self.current.get(), self.next.get_mut())
}
pub fn unwrap(&self) -> (&S, &S) {
(self.current.unwrap(), self.next.unwrap())
}
pub fn unwrap_mut(&mut self) -> (&S, &mut S) {
(self.current.unwrap(), self.next.unwrap_mut())
}
pub fn will_exit<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (Some(x), _) if pattern.matches(x))
}
pub fn will_disable<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (Some(x), None) if pattern.matches(x))
}
pub fn will_enter<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (_, Some(y)) if pattern.matches(y))
}
pub fn will_enable<P: StatePattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (None, Some(y)) if pattern.matches(y))
}
pub fn will_trans<P: StateTransPattern<S>>(&self, pattern: &P) -> bool {
matches!(self.get(), (Some(x), Some(y)) if pattern.matches(x, y))
}
pub fn disable(&mut self) {
self.next.disable();
}
pub fn enable(&mut self, value: S) {
if self.current.is_disabled() {
self.enter(value);
}
}
pub fn toggle(&mut self, value: S) {
if self.current.is_disabled() {
self.enter(value);
} else {
self.disable();
}
}
pub fn enter(&mut self, value: S) {
self.next.enter(value);
}
pub fn trigger(&mut self) -> &mut Self {
self.next.trigger();
self
}
pub fn reset_trigger(&mut self) -> &mut Self {
self.next.reset_trigger();
self
}
}
impl<S: StateMut + Default> FlushMut<'_, '_, S> {
pub fn enable_default(&mut self) {
if self.current.is_disabled() {
self.enter(S::default())
}
}
pub fn toggle_default(&mut self) {
if self.current.is_disabled() {
self.enter_default();
} else {
self.disable();
}
}
pub fn enter_default(&mut self) {
self.next.enter_default();
}
}