use crossbeam_channel::Sender;
type Job = Box<dyn FnOnce() + Send + 'static>;
pub(crate) struct TaskPool<T> {
job_tx: Sender<Job>,
result_tx: Sender<T>,
_workers: Vec<std::thread::JoinHandle<()>>,
}
impl<T: Send + 'static> TaskPool<T> {
pub(crate) fn new(result_tx: Sender<T>, n: usize) -> Self {
let n = n.max(1);
let (job_tx, job_rx) = crossbeam_channel::unbounded::<Job>();
let workers = (0..n)
.map(|_| {
let job_rx = job_rx.clone();
std::thread::Builder::new()
.name("panache-lsp-worker".to_owned())
.spawn(move || {
for job in job_rx {
if let Err(panic) =
std::panic::catch_unwind(std::panic::AssertUnwindSafe(job))
{
let msg = panic
.downcast_ref::<&'static str>()
.copied()
.or_else(|| panic.downcast_ref::<String>().map(String::as_str))
.unwrap_or("<non-string panic payload>");
log::error!("LSP task pool worker caught panic: {msg}");
}
}
})
.expect("failed to spawn LSP worker thread")
})
.collect();
Self {
job_tx,
result_tx,
_workers: workers,
}
}
pub(crate) fn spawn(&self, f: impl FnOnce() + Send + 'static) {
let _ = self.job_tx.send(Box::new(f));
}
pub(crate) fn result_sender(&self) -> Sender<T> {
self.result_tx.clone()
}
}
pub(crate) fn default_pool_size() -> usize {
num_cpus::get_physical().max(1)
}