use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use serde_derive::{Deserialize, Serialize};
use crate::error::Error;
use crate::task::{Task, TaskStatus};
pub const PUEUE_DEFAULT_GROUP: &str = "default";
pub type SharedState = Arc<Mutex<State>>;
#[derive(PartialEq, Eq, Clone, Debug, Copy, Deserialize, Serialize)]
pub enum GroupStatus {
Running,
Paused,
}
#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct Group {
pub status: GroupStatus,
pub parallel_tasks: usize,
}
#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct State {
pub tasks: BTreeMap<usize, Task>,
pub groups: BTreeMap<String, Group>,
}
impl Default for State {
fn default() -> Self {
Self::new()
}
}
impl State {
pub fn new() -> State {
let mut state = State {
tasks: BTreeMap::new(),
groups: BTreeMap::new(),
};
state.create_group(PUEUE_DEFAULT_GROUP);
state
}
pub fn add_task(&mut self, mut task: Task) -> usize {
let next_id = match self.tasks.keys().max() {
None => 0,
Some(id) => id + 1,
};
task.id = next_id;
self.tasks.insert(next_id, task);
next_id
}
pub fn change_status(&mut self, id: usize, new_status: TaskStatus) {
if let Some(ref mut task) = self.tasks.get_mut(&id) {
task.status = new_status;
};
}
pub fn create_group(&mut self, name: &str) -> &mut Group {
self.groups.entry(name.into()).or_insert(Group {
status: GroupStatus::Running,
parallel_tasks: 1,
})
}
pub fn remove_group(&mut self, group: &str) -> Result<(), Error> {
if group.eq(PUEUE_DEFAULT_GROUP) {
return Err(Error::Generic(
"You cannot remove the default group.".into(),
));
}
self.groups.remove(group);
for (_, task) in self.tasks.iter_mut() {
if task.group.eq(group) {
task.set_default_group();
}
}
Ok(())
}
pub fn set_status_for_all_groups(&mut self, status: GroupStatus) {
for (_, group) in self.groups.iter_mut() {
group.status = status;
}
}
pub fn task_ids_in_group(&self, group: &str) -> Vec<usize> {
self.tasks
.iter()
.filter(|(_, task)| task.group.eq(group))
.map(|(id, _)| *id)
.collect()
}
pub fn filter_tasks<F>(
&self,
filter: F,
task_ids: Option<Vec<usize>>,
) -> (Vec<usize>, Vec<usize>)
where
F: Fn(&Task) -> bool,
{
let task_ids = match task_ids {
Some(ids) => ids,
None => self.tasks.keys().cloned().collect(),
};
self.filter_task_ids(task_ids, filter)
}
pub fn filter_tasks_of_group<F>(&self, filter: F, group: &str) -> (Vec<usize>, Vec<usize>)
where
F: Fn(&Task) -> bool,
{
if !self.groups.contains_key(group) {
return (Vec::new(), Vec::new());
}
let task_ids = self
.tasks
.iter()
.filter(|(_, task)| task.group == group)
.map(|(id, _)| *id)
.collect();
self.filter_task_ids(task_ids, filter)
}
fn filter_task_ids<F>(&self, task_ids: Vec<usize>, filter: F) -> (Vec<usize>, Vec<usize>)
where
F: Fn(&Task) -> bool,
{
let mut matching = Vec::new();
let mut mismatching = Vec::new();
for task_id in task_ids.iter() {
match self.tasks.get(task_id) {
None => {
mismatching.push(*task_id);
continue;
}
Some(task) => {
if filter(task) {
matching.push(*task_id);
} else {
mismatching.push(*task_id);
}
}
};
}
(matching, mismatching)
}
}