use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use console::style;
use indicatif::{MultiProgress, ProgressDrawTarget};
use threadpool::ThreadPool;
use crate::{Line, LineStatus, Task};
use crate::graph::DependencyGraph;
#[derive(Clone)]
pub enum Status {
Idle,
Busy(Option<Vec<String>>),
}
#[derive(Clone)]
pub struct Pool<S> {
threads: usize,
status: Status,
graph: Arc<RwLock<DependencyGraph<S>>>,
progress: Arc<MultiProgress>,
}
impl<S> Pool<S> where S: Clone + 'static {
pub fn new(threads: usize) -> Self {
Self {
threads,
status: Status::Idle,
graph: Arc::new(RwLock::new(DependencyGraph::new())),
progress: Arc::new(MultiProgress::with_draw_target(
ProgressDrawTarget::stderr_with_hz(60),
)),
}
}
pub fn add_task(&mut self, name: &str, task: Task<S>, deps: Vec<&str>) {
let mut graph_lock = self.graph.write().unwrap();
graph_lock.add_task(name, task);
for dep in deps {
graph_lock.add_dependency(name, dep);
}
}
pub fn start_single(&mut self, name: &str) {
self.start_multi(vec![name])
}
pub fn start_multi(&mut self, names: Vec<&str>) {
self.status = Status::Busy(Some(names.iter().map(|s| s.to_string()).collect()));
self.exec();
todo!();
}
pub fn start(&mut self) {
self.status = Status::Busy(None);
self.exec()
}
fn exec(&self) {
let pool = ThreadPool::new(self.threads);
for _ in 0..self.threads {
let graph = self.graph.clone();
let line = Line::new(self.progress.clone());
pool.execute(move || {
while let Some((name, task)) = line.suspend(|| {
let mut graph_lock = graph.write().unwrap();
graph_lock.pop_next()
}) {
line.update_prefix(format!("[{}]", name));
line.update_message(LineStatus::Idle, "waiting...".to_string());
match task(name.clone(), HashMap::new(), line.clone()) {
Ok(_s) => {
}
Err(e) => {
let prefix = style(format!("[{}]", name)).bold();
let symbol = style("✘").red();
let message = style(e).white();
line.println(format!("{} {} {}", prefix, symbol, message));
}
};
}
});
}
pool.join();
}
}