leudz / shipyard

Entity Component System focused on usability and flexibility.
Other
738 stars 44 forks source link

How to implement some trait to all System trait? #198

Closed PudgeKim closed 2 months ago

PudgeKim commented 2 months ago
pub trait WorkloadExclusion {
    fn is_excluded(&self) -> bool {
        false
    }
}

I want to impl the trait above to all System trait.

impl<'s, Borrow, T> WorkloadExclusion for T
    where
        T: System<'s, Nothing, Borrow, Nothing>
{
       fn is_excluded(&self) -> bool {
        false
    }
}

In my case, I don't need Data and Return but I don't know how to treat Borrow. My goal is some systems which implement WorkloadExclusion's is_excluded to true should be excluded when the code below runs.

impl sys2 for WorkloadExclusion {
  fn is_excluded(&self) -> bool {
     true
   }
}

let workload = (sys1, sys2, sys3).into_workload(); // sys2 should be excluded

There are some macros in shipyard code so I don't know where to fix it exactly.

--- edited ---

It seems WorkloadExclusion trait also should be implemented to WorkloadSystem struct. My final goal is like


#[exclude(some_test)] // I'll write this macro which implements WorkloadExclusion trait to true in test_environment
fn sys2(c1: View<Component1>, c2: UniqueView<Component2>, ...) { .. }

let workload = (sys1, sys2, sys3).into_workload(); // sys2 should be excluded

---- edited2 ----

I found SystemModificator/WorkloadModificator trait. and there's run_if method. Can I use this to reach my goal? (It seems I can't use IntoRunIf trait ..? even it's pub trait. what should I import to use it?)

leudz commented 2 months ago

As you noticed, you have to hook into something shipyard understands, which is going to be either run_if or skip_if. I'm pretty sure you can't impl sys2, you could in theory make it generic but then you wouldn't be able to specify is_excluded for each system so it would be useless. If you plan on having a macro then one of the easiest way is to wrap the system with skip_if.

fn some_test() { ... }

#[exclude(some_test)]
fn sys2(c1: View<Component1>, c2: UniqueView<Component2>, ...) { .. }

would expend to:

fn some_test() { ... }

fn sys2() -> WorkloadSystem {
    fn sys2(c1: View<Component1>, c2: UniqueView<Component2>, ...) { .. }

    sys2.skip_if(some_test)
}

I just pushed a commit to make fn sys2() -> WorkloadSystem work like a "system generator". Before the commit you'd have to use sys2() to add it to a workload, now you can use sys2.

PudgeKim commented 2 months ago

hmm.. I don't understand sys2.skip_if(some_test). skip_if method needs IntoRunIf trait as a parameter.

#[track_caller]
fn skip_if<RunB, Run: IntoRunIf<RunB>>(self, run_if: Run) -> WorkloadSystem {
 let mut run_if = run_if.into_workload_run_if().unwrap();

  run_if.system_fn = Box::new(move |world| (run_if.system_fn)(world).map(Not::not));

  SystemModificator::<($($type,)+), R>::run_if(self, run_if)
}
leudz commented 2 months ago

skip_if accepts any system that returns bool.


Wait a second.

I'll write this macro which implements WorkloadExclusion trait to true in test_environment

If you want to run a system only during tests then why not:

fn workload() -> Workload {
    (
        sys1,
        #[cfg(test)]
        sys2,
        sys3,
    )
}

// OR

#[cfg(test)]
fn sys2(c1: View<Component1>, c2: UniqueView<Component2>, ...) { .. }
#[cfg(not(test))]
fn sys2() {}
PudgeKim commented 2 months ago

oh IntoRunIf implements for 'static + Send + Sync + Fn() -> bool.

Actually, using #[cfg] and #[cfg(not(..)] was my first plan. (I think I'll do my first plan) I wondered there's some shipyard way. anyway thank you!