rust_analyzer/
task_pool.rs

1//! A thin wrapper around [`stdx::thread::Pool`] which threads a sender through spawned jobs.
2//! It is used in [`crate::global_state::GlobalState`] throughout the main loop.
3
4use std::panic::UnwindSafe;
5
6use crossbeam_channel::Sender;
7use stdx::thread::{Pool, ThreadIntent};
8
9use crate::main_loop::QueuedTask;
10
11pub(crate) struct TaskPool<T> {
12    sender: Sender<T>,
13    pool: Pool,
14}
15
16impl<T> TaskPool<T> {
17    pub(crate) fn new_with_threads(sender: Sender<T>, threads: usize) -> TaskPool<T> {
18        TaskPool { sender, pool: Pool::new(threads) }
19    }
20
21    pub(crate) fn spawn<F>(&mut self, intent: ThreadIntent, task: F)
22    where
23        F: FnOnce() -> T + Send + UnwindSafe + 'static,
24        T: Send + 'static,
25    {
26        self.pool.spawn(intent, {
27            let sender = self.sender.clone();
28            move || sender.send(task()).unwrap()
29        })
30    }
31
32    pub(crate) fn spawn_with_sender<F>(&mut self, intent: ThreadIntent, task: F)
33    where
34        F: FnOnce(Sender<T>) + Send + UnwindSafe + 'static,
35        T: Send + 'static,
36    {
37        self.pool.spawn(intent, {
38            let sender = self.sender.clone();
39            move || task(sender)
40        })
41    }
42
43    pub(crate) fn len(&self) -> usize {
44        self.pool.len()
45    }
46}
47
48/// `TaskQueue`, like its name suggests, queues tasks.
49///
50/// This should only be used if a task must run after [`GlobalState::process_changes`]
51/// has been called.
52pub(crate) struct TaskQueue {
53    pub(crate) sender: crossbeam_channel::Sender<QueuedTask>,
54    pub(crate) receiver: crossbeam_channel::Receiver<QueuedTask>,
55}