use lsp_server::RequestId;
use serde::Serialize;
use tracing::error;
use crate::lsp::result::LSPError;
use crate::server::client::{Notifier, Requester, Responder};
use crate::state::{MetaState, State, StateSnapshot};
type LocalMutFn<'s> = Box<dyn FnOnce(&mut State, Notifier, &mut Requester<'_>, Responder) + 's>;
type LocalFn<'s> = Box<dyn FnOnce(&State, MetaState, Notifier, &mut Requester<'_>, Responder) + 's>;
type BackgroundFn = Box<dyn FnOnce(Notifier, Responder) + Send + 'static>;
pub type BackgroundFnBuilder<'s> = Box<dyn FnOnce(&State, MetaState) -> BackgroundFn + 's>;
#[derive(Clone, Copy, Debug, Default)]
pub enum BackgroundSchedule {
LatencySensitive,
#[default]
Worker,
}
pub enum Task<'s> {
Fmt(BackgroundFnBuilder<'s>),
Background(BackgroundTaskBuilder<'s>),
Sync(SyncTask<'s>),
SyncMut(SyncMutTask<'s>),
}
pub struct BackgroundTaskBuilder<'s> {
pub schedule: BackgroundSchedule,
pub builder: BackgroundFnBuilder<'s>,
}
pub struct SyncMutTask<'s> {
pub func: LocalMutFn<'s>,
}
pub struct SyncTask<'s> {
pub func: LocalFn<'s>,
}
impl<'s> Task<'s> {
pub fn fmt(
func: impl FnOnce(&State, MetaState) -> Box<dyn FnOnce(Notifier, Responder) + Send + 'static>
+ 's,
) -> Self {
Self::Fmt(Box::new(func))
}
pub fn background(
schedule: BackgroundSchedule,
func: impl FnOnce(&State, MetaState) -> Box<dyn FnOnce(Notifier, Responder) + Send + 'static>
+ 's,
) -> Self {
Self::Background(BackgroundTaskBuilder { schedule, builder: Box::new(func) })
}
pub fn local_mut(
func: impl FnOnce(&mut State, Notifier, &mut Requester<'_>, Responder) + 's,
) -> Self {
Self::SyncMut(SyncMutTask { func: Box::new(func) })
}
pub fn local(
func: impl FnOnce(&State, MetaState, Notifier, &mut Requester<'_>, Responder) + 's,
) -> Self {
Self::Sync(SyncTask { func: Box::new(func) })
}
pub fn immediate<R>(id: RequestId, result: Result<R, LSPError>) -> Self
where
R: Serialize + Send + 'static,
{
Self::local(move |_, _, _, _, responder| {
if let Err(err) = responder.respond(id, result) {
error!("unable to send immediate response: {err:?}");
}
})
}
pub fn nothing() -> Self {
Self::local(move |_, _, _, _, _| {})
}
}
pub trait Handler: FnOnce(StateSnapshot, MetaState, Notifier, Responder) + Send + 'static {}
impl<T> Handler for T where T: FnOnce(StateSnapshot, MetaState, Notifier, Responder) + Send + 'static
{}
#[derive(Debug, Clone, Copy)]
pub enum RetryTaskInfo {
Fmt,
Background(BackgroundSchedule),
}
impl RetryTaskInfo {
pub fn task(self, request_handler: impl Handler) -> Task<'static> {
let builder: BackgroundFnBuilder = Box::new(|state: &State, meta_state| {
let state_snapshot = state.snapshot();
Box::new(|notifier, responder| {
request_handler(state_snapshot, meta_state, notifier, responder)
})
});
match self {
Self::Fmt => Task::Fmt(builder),
Self::Background(schedule) => {
Task::Background(BackgroundTaskBuilder { schedule, builder })
}
}
}
}