use crate::{TaskComponent, TaskProgress};
use log::debug;
use specs::{prelude::*, storage::StorageEntry};
use std::{error, fmt};
pub fn insert<T: Component>(storage: &mut WriteStorage<T>, entity: Entity, data: T) {
storage.insert(entity, data).unwrap();
}
pub fn delete(entities: &Entities, entity: Entity) {
entities.delete(entity).unwrap();
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum UnexpectedEntity {
ExpectedTaskEntity(Entity),
ExpectedForkEntity(Entity),
}
impl fmt::Display for UnexpectedEntity {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::ExpectedTaskEntity(e) => write!(f, "Expected {:?} to be a task", e),
Self::ExpectedForkEntity(e) => write!(f, "Expected {:?} to be a fork", e),
}
}
}
impl error::Error for UnexpectedEntity {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AlreadyJoined {
pub parent: Entity,
pub already_child: Entity,
pub new_child: Entity,
}
impl fmt::Display for AlreadyJoined {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Tried to join {:?} --> {:?}, but the SingleEdge {:?} --> {:?} already exists",
self.parent, self.already_child, self.parent, self.new_child,
)
}
}
impl error::Error for AlreadyJoined {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
#[derive(Clone)]
pub struct SingleEdge {
child: Entity,
}
impl Component for SingleEdge {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Default)]
pub struct MultiEdge {
children: Vec<Entity>,
}
impl MultiEdge {
fn add_child(&mut self, entity: Entity) {
self.children.push(entity);
}
}
impl Component for MultiEdge {
type Storage = VecStorage<Self>;
}
#[derive(Clone, Copy, Default)]
pub struct FinalTag {
delete_on_completion: bool,
}
impl Component for FinalTag {
type Storage = VecStorage<Self>;
}
#[derive(SystemData)]
pub struct TaskManager<'a> {
progress: WriteStorage<'a, TaskProgress>,
single_edges: WriteStorage<'a, SingleEdge>,
multi_edges: WriteStorage<'a, MultiEdge>,
finalized: WriteStorage<'a, FinalTag>,
}
impl TaskManager<'_> {
pub fn make_task<'a, T: TaskComponent<'a>>(
&mut self,
task: T,
entities: &Entities,
tasks: &mut WriteStorage<T>,
) -> Entity {
let entity = entities.create();
insert(&mut self.progress, entity, TaskProgress::default());
insert(tasks, entity, task);
debug!("Created task {:?}", entity);
entity
}
pub fn make_fork(&mut self, entities: &Entities) -> Entity {
let entity = entities.create();
insert(&mut self.multi_edges, entity, MultiEdge::default());
debug!("Created fork {:?}", entity);
entity
}
pub fn add_prong(
&mut self,
fork_entity: Entity,
prong: Entity,
) -> Result<(), UnexpectedEntity> {
let multi_edge = self
.multi_edges
.get_mut(fork_entity)
.ok_or(UnexpectedEntity::ExpectedForkEntity(fork_entity))?;
multi_edge.add_child(prong);
Ok(())
}
pub fn join(&mut self, parent: Entity, child: Entity) -> Result<(), AlreadyJoined> {
let entry = self.single_edges.entry(parent).unwrap();
match entry {
StorageEntry::Occupied(e) => Err(AlreadyJoined {
parent,
already_child: e.get().child,
new_child: child,
}),
StorageEntry::Vacant(e) => {
e.insert(SingleEdge { child });
Ok(())
}
}
}
pub fn finalize(&mut self, entity: Entity, delete_on_completion: bool) {
insert(
&mut self.finalized,
entity,
FinalTag {
delete_on_completion,
},
);
}
pub fn task_is_complete(&self, entity: Entity) -> bool {
!self.progress.contains(entity)
}
fn fork_is_complete(&self, entity: Entity, multi_children: &[Entity]) -> bool {
if let Some(SingleEdge { child }) = self.single_edges.get(entity) {
if !self.entity_is_complete(*child) {
return false;
}
}
for child in multi_children.iter() {
if !self.entity_is_complete(*child) {
return false;
}
}
true
}
pub fn entity_is_complete(&self, entity: Entity) -> bool {
if let Some(MultiEdge { children }) = self.multi_edges.get(entity) {
self.fork_is_complete(entity, &children)
} else {
self.task_is_complete(entity)
}
}
pub fn delete_descendents(&self, entity: Entity, entities: &Entities) {
if let Some(MultiEdge { children }) = self.multi_edges.get(entity) {
for child in children.iter() {
self.delete_entity_and_descendents(*child, entities);
}
}
if let Some(SingleEdge { child }) = self.single_edges.get(entity) {
self.delete_entity_and_descendents(*child, entities);
}
}
pub fn delete_entity_and_descendents(&self, entity: Entity, entities: &Entities) {
self.delete_descendents(entity, entities);
debug!("Deleting {:?}", entity);
delete(entities, entity);
}
fn maintain_task_and_descendents(&mut self, entity: Entity) -> bool {
let (is_unblocked, is_complete) = if let Some(progress) = self.progress.get(entity) {
(progress.is_unblocked, progress.is_complete())
} else {
return true;
};
if is_complete {
debug!(
"Noticed task {:?} is complete, removing TaskProgress",
entity
);
self.progress.remove(entity);
return true;
}
if is_unblocked {
return false;
}
let mut child_complete = true;
if let Some(SingleEdge { child }) = self.single_edges.get(entity).cloned() {
child_complete = self.maintain_entity_and_descendents(child);
}
if child_complete {
debug!("Unblocking task {:?}", entity);
let progress = self
.progress
.get_mut(entity)
.expect("Blocked task must have progress");
progress.unblock();
}
false
}
fn maintain_fork_and_descendents(
&mut self,
entity: Entity,
multi_edge_children: &[Entity],
) -> bool {
let mut single_child_complete = true;
if let Some(SingleEdge { child }) = self.single_edges.get(entity).cloned() {
single_child_complete = self.maintain_entity_and_descendents(child);
}
let mut multi_children_complete = true;
if single_child_complete {
for child in multi_edge_children.iter() {
multi_children_complete &= self.maintain_entity_and_descendents(*child);
}
}
single_child_complete && multi_children_complete
}
fn maintain_entity_and_descendents(&mut self, entity: Entity) -> bool {
if let Some(MultiEdge { children }) = self.multi_edges.get(entity).cloned() {
self.maintain_fork_and_descendents(entity, &children)
} else {
self.maintain_task_and_descendents(entity)
}
}
}
pub struct TaskManagerSystem;
impl<'a> System<'a> for TaskManagerSystem {
type SystemData = (Entities<'a>, TaskManager<'a>);
fn run(&mut self, (entities, mut task_man): Self::SystemData) {
let final_ents: Vec<(Entity, FinalTag)> = (&entities, &task_man.finalized)
.join()
.map(|(e, f)| (e, *f))
.collect();
for (
entity,
FinalTag {
delete_on_completion,
},
) in final_ents.into_iter()
{
let final_complete = task_man.maintain_entity_and_descendents(entity);
if final_complete {
if delete_on_completion {
task_man.delete_entity_and_descendents(entity, &entities);
} else {
debug!("Removing FinalTag from {:?}", entity);
task_man.finalized.remove(entity);
}
}
}
}
}