use alloc::vec::Vec;
use core::marker::PhantomData;
#[cfg(feature = "bevy_reflect")]
use bevy_ecs::reflect::ReflectResource;
use bevy_ecs::{
component::Component,
resource::Resource,
system::{Res, ResMut, SystemParamItem, lifetimeless::SRes},
};
use crate::{next_state::NextState, state::State};
#[derive(Resource, Debug)]
#[cfg_attr(
feature = "bevy_reflect",
derive(bevy_reflect::Reflect),
reflect(Resource)
)]
pub struct NextStateSequence<S: State>(
pub Vec<Option<S>>,
);
impl<S: State> NextStateSequence<S> {
pub fn new(sequence: impl Into<Vec<Option<S>>>) -> Self {
Self(sequence.into())
}
}
#[derive(Resource, Component, Debug)]
#[cfg_attr(
feature = "bevy_reflect",
derive(bevy_reflect::Reflect),
reflect(Resource)
)]
pub struct NextStateIndex<S: State>(
pub Option<usize>,
PhantomData<S>,
);
impl<S: State> NextState for NextStateIndex<S> {
type State = S;
type Param = SRes<NextStateSequence<Self::State>>;
fn empty() -> Self {
Self(None, PhantomData)
}
fn next_state<'s>(
&'s self,
param: &'s SystemParamItem<Self::Param>,
) -> Option<&'s Self::State> {
self.0
.and_then(|index| param.0.get(index))
.and_then(Option::as_ref)
}
}
impl<S: State> Default for NextStateIndex<S> {
fn default() -> Self {
Self(Some(0), PhantomData)
}
}
impl<S: State> NextStateIndex<S> {
pub fn new(index: isize, len: usize) -> Self {
let mut this = Self::empty();
this.seek(index, len);
this
}
pub fn seek(&mut self, to: isize, len: usize) {
self.0 = (len > 0).then(|| to.clamp(0, len as isize - 1) as usize);
}
pub fn step(&mut self, by: isize, len: usize) {
self.seek(self.0.unwrap_or_default() as isize + by, len);
}
pub fn next(&mut self, len: usize) {
self.step(1, len);
}
pub fn prev(&mut self, len: usize) {
self.step(-1, len);
}
pub fn wrapping_seek(&mut self, to: isize, len: usize) {
self.0 = (len > 0).then(|| to.rem_euclid(len as isize) as usize);
}
pub fn wrapping_step(&mut self, by: isize, len: usize) {
self.wrapping_seek(self.0.unwrap_or_default() as isize + by, len);
}
pub fn wrapping_next(&mut self, len: usize) {
self.wrapping_step(1, len);
}
pub fn wrapping_prev(&mut self, len: usize) {
self.wrapping_step(-1, len);
}
}
pub trait NextStateIndexMut: State {
fn seek(
to: isize,
) -> impl 'static + Send + Sync + Fn(ResMut<NextStateIndex<Self>>, Res<NextStateSequence<Self>>)
{
move |mut index, sequence| index.seek(to, sequence.0.len())
}
fn step(
by: isize,
) -> impl 'static + Send + Sync + Fn(ResMut<NextStateIndex<Self>>, Res<NextStateSequence<Self>>)
{
move |mut index, sequence| index.step(by, sequence.0.len())
}
fn next(mut index: ResMut<NextStateIndex<Self>>, sequence: Res<NextStateSequence<Self>>) {
index.step(1, sequence.0.len());
}
fn prev(mut index: ResMut<NextStateIndex<Self>>, sequence: Res<NextStateSequence<Self>>) {
index.step(-1, sequence.0.len());
}
fn wrapping_seek(
to: isize,
) -> impl 'static + Send + Sync + Fn(ResMut<NextStateIndex<Self>>, Res<NextStateSequence<Self>>)
{
move |mut index, sequence| index.wrapping_seek(to, sequence.0.len())
}
fn wrapping_step(
by: isize,
) -> impl 'static + Send + Sync + Fn(ResMut<NextStateIndex<Self>>, Res<NextStateSequence<Self>>)
{
move |mut index, sequence| index.wrapping_step(by, sequence.0.len())
}
fn wrapping_next(
mut index: ResMut<NextStateIndex<Self>>,
sequence: Res<NextStateSequence<Self>>,
) {
index.wrapping_step(1, sequence.0.len());
}
fn wrapping_prev(
mut index: ResMut<NextStateIndex<Self>>,
sequence: Res<NextStateSequence<Self>>,
) {
index.wrapping_step(-1, sequence.0.len());
}
}
impl<S: State<Next = NextStateIndex<S>>> NextStateIndexMut for S {}