use crate::Cx;
use bevy::prelude::*;
#[allow(unused)]
pub trait EntityEffect: Sync + Send {
type State: Send + Sync;
fn apply(&self, cx: &mut Cx, target: Entity) -> Self::State;
fn reapply(&self, cx: &mut Cx, target: Entity, state: &mut Self::State) {}
}
#[doc(hidden)]
pub trait AppendEffect<T> {
type Result: EffectTuple;
fn append(self, tail: T) -> Self::Result;
}
#[allow(unused)]
impl<T: EntityEffect> AppendEffect<T> for () {
type Result = (T,);
#[inline(always)]
fn append(self, tail: T) -> Self::Result {
(tail,)
}
}
macro_rules! impl_append_effect {
( $($view: ident, $idx: tt);+ ) => {
impl<$(
$view: EntityEffect,
)+ T: EntityEffect> AppendEffect<T> for ( $( $view, )+ ) {
type Result = ($( $view, )+ T);
#[inline(always)]
fn append(self, tail: T) -> Self::Result {
( $( self.$idx, )+ tail)
}
}
};
}
impl_append_effect!(E0, 0);
impl_append_effect!(E0, 0; E1, 1);
impl_append_effect!(E0, 0; E1, 1; E2, 2);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13; E14, 14);
impl_append_effect!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13; E14, 14; E15, 15);
#[doc(hidden)]
pub trait EffectTuple: Send + Sync {
type State: Send + Sync;
fn apply(&self, cx: &mut Cx, target: Entity) -> Self::State;
fn reapply(&self, cx: &mut Cx, target: Entity, state: &mut Self::State);
fn append_effect<E: EntityEffect>(self, effect: E) -> <Self as AppendEffect<E>>::Result
where
Self: Sized + AppendEffect<E>,
{
self.append(effect)
}
}
impl<E: EntityEffect> EffectTuple for E {
type State = E::State;
#[inline(always)]
fn apply(&self, cx: &mut Cx, target: Entity) -> Self::State {
self.apply(cx, target)
}
#[inline(always)]
fn reapply(&self, cx: &mut Cx, target: Entity, state: &mut Self::State) {
self.reapply(cx, target, state)
}
}
#[allow(unused)]
impl EffectTuple for () {
type State = ();
#[inline(always)]
fn apply(&self, cx: &mut Cx, target: Entity) -> Self::State {}
#[inline(always)]
fn reapply(&self, cx: &mut Cx, target: Entity, state: &mut Self::State) {}
}
macro_rules! impl_effect_tuple {
( $($effect: ident, $idx: tt);+ ) => {
impl<$(
$effect: EntityEffect,
)+> EffectTuple for ( $( $effect, )+ ) {
type State = ( $( $effect::State ),*, );
fn apply(&self, cx: &mut Cx, target: Entity) -> Self::State {
($( self.$idx.apply(cx, target) ),*,)
}
fn reapply(&self, cx: &mut Cx, target: Entity, state: &mut Self::State) {
$( self.$idx.reapply(cx, target, &mut state.$idx); )*
}
}
};
}
impl_effect_tuple!(E0, 0);
impl_effect_tuple!(E0, 0; E1, 1);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13; E14, 14);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13; E14, 14; E15, 15);
impl_effect_tuple!(E0, 0; E1, 1; E2, 2; E3, 3; E4, 4; E5, 5; E6, 6; E7, 7; E8, 8; E9, 9; E10, 10; E11, 11; E12, 12; E13, 13; E14, 14; E15, 15; E16, 16);
pub struct CallbackEffect<F: Fn(&mut Cx, Entity, D), D: PartialEq + Clone> {
pub effect_fn: F,
pub deps: D,
}
impl<F: Fn(&mut Cx, Entity, D) + Send + Sync, D: PartialEq + Clone + Send + Sync> EntityEffect
for CallbackEffect<F, D>
{
type State = D;
fn apply(&self, cx: &mut Cx, target: Entity) -> Self::State {
(self.effect_fn)(cx, target, self.deps.clone());
self.deps.clone()
}
fn reapply(&self, cx: &mut Cx, target: Entity, state: &mut Self::State) {
if *state != self.deps {
*state = self.deps.clone();
(self.effect_fn)(cx, target, self.deps.clone());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestEffect;
impl EntityEffect for TestEffect {
type State = ();
fn apply(&self, _cx: &mut Cx, _target: Entity) -> Self::State {}
}
struct TestEffect2;
impl EntityEffect for TestEffect2 {
type State = ();
fn apply(&self, _cx: &mut Cx, _target: Entity) -> Self::State {}
}
struct EffectList<T: EffectTuple>(T);
impl<T: EffectTuple> EffectList<T> {
#[allow(unused)]
fn append<E: EntityEffect>(self, effect: E) -> EffectList<<T as AppendEffect<E>>::Result>
where
T: AppendEffect<E>,
{
let effects = self.0.append_effect(effect);
EffectList(effects)
}
}
#[test]
fn test_append() {
let effects = EffectList((TestEffect,));
let _effects2 = EffectList(effects.0.append(TestEffect2));
}
}