Fork-join multitasking for SPECS ECS

Instead of hand-rolling state machines to sequence the effects of various ECS systems, spawn tasks as entities and declare explicit temporal dependencies between them.

Code Examples

Making task graphs

```rust fn makestatictaskgraph(user: &TaskUser) { // Any component that implements TaskComponent can be spawned. let taskgraph: TaskGraph = seq!( @TaskFoo("hello"), fork!( @TaskBar { value: 1 }, @TaskBar { value: 2 }, @TaskBar { value: 3 } ), @TaskZing("goodbye") ); task_graph.assemble(user, OnCompletion::Delete); }

fn makedynamictaskgraph(user: &TaskUser) { let first = task!(@TaskFoo("hello")); let mut middle = emptygraph!(); for i in 0..10 { middle = fork!(middle, @TaskBar { value: i }); } let last = task!(@TaskZing("goodbye")); let taskgraph: TaskGraph = seq!(first, middle, last); taskgraph.assemble(user, OnCompletion::Delete); } ```

Building a dispatcher with a TaskRunnerSystem

```rust

[derive(Clone, Debug)]

struct PushValue { value: usize, }

impl Component for PushValue { type Storage = VecStorage; }

impl<'a> TaskComponent<'a> for PushValue { type Data = Write<'a, Vec>;

fn run(&mut self, data: &mut Self::Data) -> bool {
    data.push(self.value);

    true
}

}

fn makedispatcher() -> Dispatcher { DispatcherBuilder::new() .with( TaskRunnerSystem::::default(), "pushvalue", &[], ) .with( TaskManagerSystem, "task_manager", &[], ) .build() } ```