#[allow(unused_imports)] use crate::action_state::ActionState;
use bevy::utils::hashbrown::hash_set::Iter;
use std::iter::Once;
use bevy::{
ecs::{component::Component, entity::Entity},
utils::HashSet,
};
use crate::Actionlike;
#[derive(Debug, Component, Clone, PartialEq, Eq)]
pub struct ActionStateDriver<A: Actionlike> {
pub action: A,
pub targets: ActionStateDriverTarget,
}
#[derive(Debug, Component, Clone, PartialEq, Eq)]
pub enum ActionStateDriverTarget {
None,
Single(Entity),
Multi(HashSet<Entity>),
}
impl ActionStateDriverTarget {
#[inline(always)]
pub fn iter(&self) -> impl Iterator<Item = &Entity> {
match self {
Self::None => ActionStateDriverTargetIterator::None,
Self::Single(entity) => {
ActionStateDriverTargetIterator::Single(std::iter::once(entity))
}
Self::Multi(entities) => ActionStateDriverTargetIterator::Multi(entities.iter()),
}
}
#[inline(always)]
pub fn insert(&mut self, entity: Entity) {
*self = std::mem::replace(self, Self::None).with(entity);
}
#[inline(always)]
pub fn remove(&mut self, entity: Entity) {
*self = std::mem::replace(self, Self::None).without(entity);
}
#[inline(always)]
pub fn add(&mut self, entities: impl Iterator<Item = Entity>) {
for entity in entities {
self.insert(entity)
}
}
#[inline(always)]
pub fn len(&self) -> usize {
match self {
Self::None => 0,
Self::Single(_) => 1,
Self::Multi(targets) => targets.len(),
}
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn with(mut self, entity: Entity) -> Self {
match self {
Self::None => Self::Single(entity),
Self::Single(og) => Self::Multi(HashSet::from([og, entity])),
Self::Multi(ref mut targets) => {
targets.insert(entity);
self
}
}
}
pub fn without(self, entity: Entity) -> Self {
match self {
Self::None => Self::None,
Self::Single(_) => Self::None,
Self::Multi(mut targets) => {
targets.remove(&entity);
Self::from_iter(targets)
}
}
}
}
impl From<Entity> for ActionStateDriverTarget {
fn from(value: Entity) -> Self {
Self::Single(value)
}
}
impl From<()> for ActionStateDriverTarget {
fn from(_value: ()) -> Self {
Self::None
}
}
impl FromIterator<Entity> for ActionStateDriverTarget {
fn from_iter<T: IntoIterator<Item = Entity>>(iter: T) -> Self {
let entities = HashSet::from_iter(iter);
match entities.len() {
0 => Self::None,
1 => Self::Single(entities.into_iter().next().unwrap()),
_ => Self::Multi(entities),
}
}
}
impl<'a> FromIterator<&'a Entity> for ActionStateDriverTarget {
fn from_iter<T: IntoIterator<Item = &'a Entity>>(iter: T) -> Self {
let entities = HashSet::from_iter(iter.into_iter().cloned());
match entities.len() {
0 => Self::None,
1 => Self::Single(entities.into_iter().next().unwrap()),
_ => Self::Multi(entities),
}
}
}
enum ActionStateDriverTargetIterator<'a> {
None,
Single(Once<&'a Entity>),
Multi(Iter<'a, Entity>),
}
impl<'a> Iterator for ActionStateDriverTargetIterator<'a> {
type Item = &'a Entity;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::None => None,
Self::Single(iter) => iter.next(),
Self::Multi(iter) => iter.next(),
}
}
}
#[cfg(test)]
mod tests {
use super::ActionStateDriverTarget;
use bevy::prelude::Entity;
#[test]
fn action_state_driver_targets() {
let mut target = ActionStateDriverTarget::from(());
assert_eq!(0, target.len());
target.insert(Entity::from_raw(0));
assert_eq!(1, target.len());
target.insert(Entity::from_raw(1));
assert_eq!(2, target.len());
target.remove(Entity::from_raw(0));
assert_eq!(1, target.len());
target.remove(Entity::from_raw(1));
assert_eq!(0, target.len());
target = target.with(Entity::from_raw(0));
assert_eq!(1, target.len());
target = target.without(Entity::from_raw(0));
assert_eq!(0, target.len());
target.add(
[
Entity::from_raw(0),
Entity::from_raw(1),
Entity::from_raw(2),
]
.iter()
.cloned(),
);
assert_eq!(3, target.len());
let mut sum = 0;
for entity in target.iter() {
sum += entity.index();
}
assert_eq!(3, sum);
}
}