1use core::fmt;
4use std::any::Any;
5use std::collections::HashMap;
6use std::path::{Path, PathBuf};
7use std::time::Instant;
8
9use serde::Serialize;
10use serde_json::{from_value, Value as JsonValue};
11
12#[cfg(feature = "dap")]
13mod dap_srv;
14
15#[cfg(feature = "lsp")]
16mod lsp_srv;
17#[cfg(feature = "lsp")]
18use lsp::{Notification, Request};
19
20use crate::msg::*;
21use crate::*;
22
23type Event = Box<dyn Any + Send>;
24type ImmutPath = Arc<Path>;
25
26type AsyncHandler<S, T, R> = fn(srv: &mut S, args: T) -> SchedulableResponse<R>;
27type RawHandler<S, T> = fn(srv: &mut S, req_id: RequestId, args: T) -> ScheduledResult;
28type BoxPureHandler<S, T> = Box<dyn Fn(&mut S, T) -> LspResult<()>>;
29type BoxHandler<S, T> = Box<dyn Fn(&mut S, &LspClient, RequestId, T) -> ScheduledResult>;
30type ExecuteCmdMap<S> = HashMap<&'static str, BoxHandler<S, Vec<JsonValue>>>;
31type RegularCmdMap<S> = HashMap<&'static str, BoxHandler<S, JsonValue>>;
32type NotifyCmdMap<S> = HashMap<&'static str, BoxPureHandler<S, JsonValue>>;
33type ResourceMap<S> = HashMap<ImmutPath, BoxHandler<S, Vec<JsonValue>>>;
34type MayInitBoxHandler<A, S, T> =
35 Box<dyn for<'a> Fn(ServiceState<'a, A, S>, &LspClient, T) -> anyhow::Result<()>>;
36type EventMap<A, S> = HashMap<core::any::TypeId, MayInitBoxHandler<A, S, Event>>;
37
38pub trait Initializer {
40 type I: for<'de> serde::Deserialize<'de>;
42 type S;
44
45 fn initialize(self, req: Self::I) -> (Self::S, AnySchedulableResponse);
49}
50
51pub struct LsBuilder<M, Args: Initializer> {
53 pub args: Args,
55 pub client: LspClient,
57 pub events: EventMap<Args, Args::S>,
59 pub command_handlers: ExecuteCmdMap<Args::S>,
61 pub notif_handlers: NotifyCmdMap<Args::S>,
63 pub req_handlers: RegularCmdMap<Args::S>,
65 pub resource_handlers: ResourceMap<Args::S>,
67 _marker: std::marker::PhantomData<M>,
68}
69
70#[cfg(feature = "lsp")]
72pub type LspBuilder<Args> = LsBuilder<LspMessage, Args>;
73#[cfg(feature = "dap")]
75pub type DapBuilder<Args> = LsBuilder<DapMessage, Args>;
76
77impl<M, Args: Initializer> LsBuilder<M, Args>
78where
79 Args::S: 'static,
80{
81 pub fn new(args: Args, client: LspClient) -> Self {
83 Self {
84 args,
85 client,
86 events: EventMap::new(),
87 command_handlers: ExecuteCmdMap::new(),
88 notif_handlers: NotifyCmdMap::new(),
89 req_handlers: RegularCmdMap::new(),
90 resource_handlers: ResourceMap::new(),
91 _marker: std::marker::PhantomData,
92 }
93 }
94
95 pub fn with_event<T: std::any::Any>(
97 mut self,
98 ins: &T,
99 handler: impl for<'a> Fn(ServiceState<'a, Args, Args::S>, T) -> anyhow::Result<()> + 'static,
100 ) -> Self {
101 self.events.insert(
102 ins.type_id(),
103 Box::new(move |s, _client, req| handler(s, *req.downcast().unwrap())),
104 );
105 self
106 }
107
108 pub fn with_resource_(
110 mut self,
111 path: ImmutPath,
112 handler: RawHandler<Args::S, Vec<JsonValue>>,
113 ) -> Self {
114 self.resource_handlers.insert(path, raw_to_boxed(handler));
115 self
116 }
117
118 pub fn with_resource(
120 mut self,
121 path: &'static str,
122 handler: fn(&mut Args::S, Vec<JsonValue>) -> AnySchedulableResponse,
123 ) -> Self {
124 self.resource_handlers.insert(
125 Path::new(path).into(),
126 Box::new(move |s, client, req_id, req| client.schedule(req_id, handler(s, req))),
127 );
128 self
129 }
130
131 pub fn build(self) -> LsDriver<M, Args> {
133 LsDriver {
134 state: State::Uninitialized(Some(Box::new(self.args))),
135 events: self.events,
136 client: self.client,
137 commands: self.command_handlers,
138 notifications: self.notif_handlers,
139 requests: self.req_handlers,
140 resources: self.resource_handlers,
141 _marker: std::marker::PhantomData,
142 }
143 }
144}
145
146pub enum ServiceState<'a, A, S> {
148 Uninitialized(Option<&'a mut A>),
150 Ready(&'a mut S),
152}
153
154impl<A, S> ServiceState<'_, A, S> {
155 pub fn ready(&mut self) -> Option<&mut S> {
157 match self {
158 ServiceState::Ready(s) => Some(s),
159 _ => None,
160 }
161 }
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
165#[allow(dead_code)]
166enum State<Args, S> {
167 Uninitialized(Option<Box<Args>>),
168 Initializing(S),
169 Ready(S),
170 ShuttingDown,
171}
172
173impl<Args, S> State<Args, S> {
174 fn opt(&self) -> Option<&S> {
175 match &self {
176 State::Ready(s) => Some(s),
177 _ => None,
178 }
179 }
180
181 fn opt_mut(&mut self) -> Option<&mut S> {
182 match self {
183 State::Ready(s) => Some(s),
184 _ => None,
185 }
186 }
187}
188
189pub struct LsDriver<M, Args: Initializer> {
191 state: State<Args, Args::S>,
193 pub client: LspClient,
195
196 pub events: EventMap<Args, Args::S>,
199 pub commands: ExecuteCmdMap<Args::S>,
201 pub notifications: NotifyCmdMap<Args::S>,
203 pub requests: RegularCmdMap<Args::S>,
205 pub resources: ResourceMap<Args::S>,
207 _marker: std::marker::PhantomData<M>,
208}
209
210impl<M, Args: Initializer> LsDriver<M, Args> {
211 pub fn state(&self) -> Option<&Args::S> {
213 self.state.opt()
214 }
215
216 pub fn state_mut(&mut self) -> Option<&mut Args::S> {
218 self.state.opt_mut()
219 }
220
221 pub fn ready(&mut self, params: Args::I) -> AnySchedulableResponse {
223 let args = match &mut self.state {
224 State::Uninitialized(args) => args,
225 _ => return just_result(Err(invalid_request("server is already initialized"))),
226 };
227
228 let args = args.take().expect("already initialized");
229 let (s, res) = args.initialize(params);
230 self.state = State::Ready(s);
231
232 res
233 }
234
235 pub fn get_resources(&mut self, req_id: RequestId, args: Vec<JsonValue>) -> ScheduledResult {
238 let s = self.state.opt_mut().ok_or_else(not_initialized)?;
239
240 let path =
241 from_value::<PathBuf>(args[0].clone()).map_err(|e| invalid_params(e.to_string()))?;
242
243 let Some(handler) = self.resources.get(path.as_path()) else {
244 log::error!("asked for unknown resource: {path:?}");
245 return Err(method_not_found());
246 };
247
248 handler(s, &self.client, req_id, args)
250 }
251}
252
253fn from_json<T: serde::de::DeserializeOwned>(json: JsonValue) -> LspResult<T> {
254 serde_json::from_value(json).map_err(invalid_request)
255}
256
257fn raw_to_boxed<S: 'static, T: 'static>(handler: RawHandler<S, T>) -> BoxHandler<S, T> {
258 Box::new(move |s, _client, req_id, req| handler(s, req_id, req))
259}
260
261fn resp_err(code: ErrorCode, msg: impl fmt::Display) -> ResponseError {
262 ResponseError {
263 code: code as i32,
264 message: msg.to_string(),
265 data: None,
266 }
267}
268
269pub fn invalid_params(msg: impl fmt::Display) -> ResponseError {
271 resp_err(ErrorCode::InvalidParams, msg)
272}
273
274pub fn internal_error(msg: impl fmt::Display) -> ResponseError {
276 resp_err(ErrorCode::InternalError, msg)
277}
278
279pub fn not_initialized() -> ResponseError {
281 resp_err(ErrorCode::ServerNotInitialized, "not initialized yet")
282}
283
284pub fn method_not_found() -> ResponseError {
286 resp_err(ErrorCode::MethodNotFound, "method not found")
287}
288
289pub fn invalid_request(msg: impl fmt::Display) -> ResponseError {
291 resp_err(ErrorCode::InvalidRequest, msg)
292}