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}