legion_task/
components.rs1use legion::prelude::*;
2use std::sync::atomic::{AtomicBool, Ordering};
3
4pub trait TaskComponent<'a>: Send + Sync {
7    type Data;
8
9    fn run(&mut self, data: &mut Self::Data) -> bool;
11}
12
13#[doc(hidden)]
14#[derive(Default)]
15pub struct TaskProgress {
16    pub(crate) is_complete: AtomicBool,
17    pub(crate) is_unblocked: bool,
18}
19
20impl TaskProgress {
21    pub(crate) fn is_complete(&self) -> bool {
22        self.is_complete.load(Ordering::Relaxed)
23    }
24
25    pub(crate) fn complete(&self) {
26        self.is_complete.store(true, Ordering::Relaxed);
27    }
28
29    pub(crate) fn unblock(&mut self) {
30        self.is_unblocked = true;
31    }
32}
33
34#[doc(hidden)]
35#[derive(Clone)]
36pub struct SingleEdge {
37    pub(crate) child: Entity,
38}
39
40#[doc(hidden)]
41#[derive(Clone, Default)]
42pub struct MultiEdge {
43    pub(crate) children: Vec<Entity>,
44}
45
46impl MultiEdge {
47    fn add_child(&mut self, entity: Entity) {
48        self.children.push(entity);
49    }
50}
51
52#[doc(hidden)]
53#[derive(Clone, Copy, Default)]
54pub struct FinalTag {
55    pub(crate) on_completion: OnCompletion,
56}
57
58#[derive(Copy, Clone, Debug, Eq, PartialEq)]
60pub enum OnCompletion {
61    None,
62    Delete,
63}
64
65impl Default for OnCompletion {
66    fn default() -> Self {
67        OnCompletion::None
68    }
69}
70
71pub fn with_task_components(builder: SystemBuilder) -> SystemBuilder {
73    builder
74        .read_component::<TaskProgress>()
75        .read_component::<SingleEdge>()
76        .read_component::<MultiEdge>()
77}
78
79pub fn make_task<'a, T: 'static + TaskComponent<'a>>(
81    cmd: &mut CommandBuffer,
82    task_component: T,
83) -> Entity {
84    let entity = cmd
85        .start_entity()
86        .with_component(TaskProgress::default())
87        .with_component(task_component)
88        .build();
89    log::debug!("Created task {:?}", entity);
90
91    entity
92}
93
94pub fn finalize(cmd: &CommandBuffer, entity: Entity, on_completion: OnCompletion) {
96    cmd.add_component(entity, FinalTag { on_completion });
97    log::debug!("Finalized task {:?}", entity);
98}
99
100pub fn make_fork(cmd: &mut CommandBuffer) -> Entity {
102    let entity = cmd
103        .start_entity()
104        .with_component(MultiEdge::default())
105        .with_component(())
107        .build();
108    log::debug!("Created fork {:?}", entity);
109
110    entity
111}
112
113pub fn add_prong(cmd: &CommandBuffer, fork_entity: Entity, prong: Entity) {
115    cmd.exec_mut(move |world| {
116        let mut multi_edge = world
117            .get_component_mut::<MultiEdge>(fork_entity)
118            .unwrap_or_else(|| {
119                panic!(
120                    "Tried to add prong {} to non-fork entity {}",
121                    prong, fork_entity
122                )
123            });
124        multi_edge.add_child(prong);
125    });
126    log::debug!(
127        "Submitted command to add prong {} to fork {}",
128        prong,
129        fork_entity
130    );
131}
132
133pub fn join(cmd: &CommandBuffer, parent: Entity, child: Entity) {
135    cmd.exec_mut(move |world| {
136        if let Some(edge) = world
137            .get_component::<SingleEdge>(parent)
138            .map(|e| (*e).clone())
139        {
140            panic!(
141                "Attempted to make task {} child of {}, but task {} already has child {}",
142                child, parent, parent, edge.child
143            );
144        } else {
145            world.add_component(parent, SingleEdge { child }).unwrap();
147        }
148    });
149    log::debug!("Submitted command to make {} parent of {}", parent, child);
150}