perf(lsp): Only deserialize response from op_respond once (#23349)

Previously we were deserializing it twice - once to `serde_json::Value`,
and then again from the `serde_json::Value` to a concrete type
This commit is contained in:
Nathan Whitaker 2024-04-12 16:04:54 -07:00 committed by Bartek Iwańczuk
parent aa11858372
commit f819d4719c
No known key found for this signature in database
GPG Key ID: 0C6BCDDC3B3AD750
2 changed files with 16 additions and 23 deletions

View File

@ -105,7 +105,7 @@ const FILE_EXTENSION_KIND_MODIFIERS: &[&str] =
type Request = (
TscRequest,
Arc<StateSnapshot>,
oneshot::Sender<Result<Value, AnyError>>,
oneshot::Sender<Result<String, AnyError>>,
CancellationToken,
);
@ -1054,13 +1054,13 @@ impl TsServer {
}
let token = token.child_token();
let droppable_token = DroppableToken(token.clone());
let (tx, rx) = oneshot::channel::<Result<Value, AnyError>>();
let (tx, rx) = oneshot::channel::<Result<String, AnyError>>();
if self.sender.send((req, snapshot, tx, token)).is_err() {
return Err(anyhow!("failed to send request to tsc thread"));
}
let value = rx.await??;
drop(droppable_token);
Ok(serde_json::from_value::<R>(value)?)
Ok(serde_json::from_str(&value)?)
}
}
@ -3848,12 +3848,6 @@ impl SelectionRange {
}
}
#[derive(Debug, Clone, Deserialize)]
struct Response {
// id: usize,
data: Value,
}
#[derive(Debug, Default)]
pub struct TscSpecifierMap {
normalized_specifiers: DashMap<String, ModuleSpecifier>,
@ -3917,7 +3911,8 @@ impl TscSpecifierMap {
struct State {
last_id: usize,
performance: Arc<Performance>,
response: Option<Response>,
// the response from JS, as a JSON string
response: Option<String>,
state_snapshot: Arc<StateSnapshot>,
specifier_map: Arc<TscSpecifierMap>,
token: CancellationToken,
@ -4084,10 +4079,10 @@ fn op_resolve_inner(
Ok(specifiers)
}
#[op2]
fn op_respond(state: &mut OpState, #[serde] args: Response) {
#[op2(fast)]
fn op_respond(state: &mut OpState, #[string] response: String) {
let state = state.borrow_mut::<State>();
state.response = Some(args);
state.response = Some(response);
}
#[op2]
@ -4646,7 +4641,7 @@ fn request(
state_snapshot: Arc<StateSnapshot>,
request: TscRequest,
token: CancellationToken,
) -> Result<Value, AnyError> {
) -> Result<String, AnyError> {
if token.is_cancelled() {
return Err(anyhow!("Operation was cancelled."));
}
@ -4679,14 +4674,12 @@ fn request(
let state = op_state.borrow_mut::<State>();
performance.measure(mark);
if let Some(response) = state.response.take() {
Ok(response.data)
} else {
Err(custom_error(
state.response.take().ok_or_else(|| {
custom_error(
"RequestError",
"The response was not received for the request.",
))
}
)
})
}
#[cfg(test)]

View File

@ -1021,14 +1021,14 @@ delete Object.prototype.__proto__;
}
/**
* @param {number} id
* @param {number} _id
* @param {any} data
*/
// TODO(bartlomieju): this feels needlessly generic, both type chcking
// and language server use it with inefficient serialization. Id is not used
// anyway...
function respond(id, data = null) {
ops.op_respond({ id, data });
function respond(_id, data = null) {
ops.op_respond(JSON.stringify(data));
}
function serverRequest(id, method, args) {