use anyhow::Result;
use self::task::BackgroundTaskBuilder;
use self::thread::{JoinHandle, ThreadPriority};
use crate::server::client::{Client, Notifier, Requester, Responder};
use crate::server::connection::ClientSender;
use crate::state::State;
mod task;
pub mod thread;
pub(super) use self::task::BackgroundSchedule;
pub use self::task::{SyncTask, Task};
pub fn event_loop_thread(
func: impl FnOnce() -> Result<()> + Send + 'static,
) -> Result<JoinHandle<Result<()>>> {
const MAIN_THREAD_STACK_SIZE: usize = 2 * 1024 * 1024;
const MAIN_THREAD_NAME: &str = "cairols:main";
Ok(thread::Builder::new(ThreadPriority::LatencySensitive)
.name(MAIN_THREAD_NAME.into())
.stack_size(MAIN_THREAD_STACK_SIZE)
.spawn(func)?)
}
type SyncTaskHook = Box<dyn Fn(&mut State, Notifier)>;
pub struct Scheduler<'s> {
state: &'s mut State,
client: Client<'s>,
background_pool: thread::Pool,
sync_task_hooks: Vec<SyncTaskHook>,
}
impl<'s> Scheduler<'s> {
pub fn new(state: &'s mut State, sender: ClientSender) -> Self {
Self {
state,
client: Client::new(sender),
background_pool: thread::Pool::new(),
sync_task_hooks: Default::default(),
}
}
pub fn response(&mut self, response: lsp_server::Response) -> Task<'s> {
self.client.requester.pop_response_task(response)
}
pub fn dispatch(&mut self, task: Task<'s>) {
match task {
Task::Sync(SyncTask { func }) => {
let notifier = self.client.notifier();
let responder = self.client.responder();
func(self.state, notifier.clone(), &mut self.client.requester, responder);
for hook in &self.sync_task_hooks {
hook(self.state, notifier.clone());
}
}
Task::Background(BackgroundTaskBuilder { schedule, builder: func }) => {
let static_func = func(self.state);
let notifier = self.client.notifier();
let responder = self.client.responder();
let task = move || static_func(notifier, responder);
match schedule {
BackgroundSchedule::Worker => {
self.background_pool.spawn(ThreadPriority::Worker, task);
}
BackgroundSchedule::LatencySensitive => {
self.background_pool.spawn(ThreadPriority::LatencySensitive, task)
}
}
}
}
}
pub fn local(
&mut self,
func: impl FnOnce(&mut State, Notifier, &mut Requester<'_>, Responder) + 's,
) {
self.dispatch(Task::local(func));
}
pub fn on_sync_task(&mut self, hook: impl Fn(&mut State, Notifier) + 'static) {
self.sync_task_hooks.push(Box::new(hook));
}
}