use std::any::TypeId;
use std::ops::{Deref, DerefMut};
use crate::{utils, Error, Result};
#[derive(Clone, Copy, PartialEq)]
pub struct Position
{
pub x: f32,
pub y: f32,
}
#[derive(Clone, Copy, PartialEq)]
pub struct Velocity
{
pub x: f32,
pub y: f32,
}
pub trait StateTrait
{
fn to_state(self) -> State;
}
#[derive(Clone, Copy, PartialEq)]
pub enum State
{
Position(Position),
Velocity(Velocity),
}
#[derive(Default, Clone, PartialEq)]
pub struct States(Vec<State>);
impl Deref for States
{
type Target = Vec<State>;
fn deref(&self) -> &Self::Target
{
&self.0
}
}
impl DerefMut for States
{
fn deref_mut(&mut self) -> &mut Self::Target
{
&mut self.0
}
}
macro_rules! build_states_getter {
($(#[$attr:meta])* => ($name:tt, $type:tt)) => {
$(#[$attr])*
pub fn $name(&self) -> Result<$type>
{
let res = self.0.iter().find_map(|x| match x
{
State::$type(p) => Some(p),
_ => None,
});
if res.is_none()
{
Err(Error::UnknownState(std::any::type_name::<$type>()))
}
else
{
Ok(*res.unwrap())
}
}
};
}
impl States
{
build_states_getter!(
=> (get_position, Position));
build_states_getter!(
=> (get_velocity, Velocity));
pub fn add_state<T: StateTrait + 'static>(&mut self, t: T) -> crate::Result<&mut States>
{
let it = self
.0
.iter()
.filter(|x| match x
{
State::Position(_) => TypeId::of::<Position>() == TypeId::of::<T>(),
State::Velocity(_) => TypeId::of::<Velocity>() == TypeId::of::<T>(),
})
.next();
if it.is_none()
{
self.push(t.to_state());
Ok(self)
}
else
{
Err(Error::DuplicateState(std::any::type_name::<T>()))
}
}
pub fn update_state<T: StateTrait + 'static>(&mut self, t: T) -> crate::Result<&mut States>
{
let it = self
.0
.iter()
.enumerate()
.filter(|(_, x)| match x
{
State::Position(_) => TypeId::of::<Position>() == TypeId::of::<T>(),
State::Velocity(_) => TypeId::of::<Velocity>() == TypeId::of::<T>(),
})
.next();
if let Some((index, _)) = it
{
self.remove(index);
self.push(t.to_state());
return Ok(self);
}
else
{
Err(Error::UnknownState(std::any::type_name::<T>()))
}
}
}
impl StateTrait for Position
{
fn to_state(self) -> State
{
return State::Position(self);
}
}
impl StateTrait for Velocity
{
fn to_state(self) -> State
{
return State::Velocity(self);
}
}
macro_rules! build_shared_states_getter {
($(#[$attr:meta])* => ($name:tt, $type:tt)) => {
$(#[$attr])*
pub fn $name(&self) -> Result<$type>
{
self.states.lock()?.$name()
}
};
}
#[derive(Clone)]
pub struct SharedStates
{
states: utils::ArcMutex<States>,
}
impl SharedStates
{
build_shared_states_getter!(
=> (get_position, Position));
build_shared_states_getter!(
=> (get_velocity, Velocity));
pub fn new(states: States) -> Self
{
Self {
states: utils::arc_mutex_new(states),
}
}
pub fn update_states(&self, updater: impl Fn(&mut crate::states::States)) -> Result<()>
{
let mut locked = self.states.lock()?;
updater(&mut locked);
Ok(())
}
pub fn update_state<T: crate::states::StateTrait + 'static>(&self, state: T)
-> crate::Result<()>
{
self.states.lock()?.update_state(state)?;
Ok(())
}
pub fn to_owned_states(&self) -> Result<States>
{
Ok(self.states.lock()?.to_owned())
}
}