From 8d2870b94af238a30dc12e14d8fd19c06a202f9d Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 6 Jun 2025 10:16:35 -0400 Subject: [PATCH] Reuse content buffer in JSONRPC recv for LSP and DAP Previously `recv` for new messages from the language server or debug adapter allocated a fresh Vec for each message. Instead we can reuse the buffer. This resolves TODO comments. Co-authored-by: Rolo --- helix-dap/src/transport.rs | 22 +++++++++++++++------- helix-lsp/src/transport.rs | 21 +++++++++++++-------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/helix-dap/src/transport.rs b/helix-dap/src/transport.rs index c1e15b3fc..6911e4e72 100644 --- a/helix-dap/src/transport.rs +++ b/helix-dap/src/transport.rs @@ -85,10 +85,11 @@ impl Transport { async fn recv_server_message( reader: &mut Box, buffer: &mut String, + content: &mut Vec, ) -> Result { let mut content_length = None; loop { - buffer.truncate(0); + buffer.clear(); if reader.read_line(buffer).await? == 0 { return Err(Error::StreamClosed); }; @@ -117,17 +118,17 @@ impl Transport { } let content_length = content_length.context("missing content length")?; - - //TODO: reuse vector - let mut content = vec![0; content_length]; - reader.read_exact(&mut content).await?; - let msg = std::str::from_utf8(&content).context("invalid utf8 from server")?; + content.resize(content_length, 0); + reader.read_exact(content).await?; + let msg = std::str::from_utf8(content).context("invalid utf8 from server")?; info!("<- DAP {}", msg); // try parsing as output (server response) or call (server request) let output: serde_json::Result = serde_json::from_str(msg); + content.clear(); + Ok(output?) } @@ -242,8 +243,15 @@ impl Transport { client_tx: UnboundedSender, ) { let mut recv_buffer = String::new(); + let mut content_buffer = Vec::new(); loop { - match Self::recv_server_message(&mut server_stdout, &mut recv_buffer).await { + match Self::recv_server_message( + &mut server_stdout, + &mut recv_buffer, + &mut content_buffer, + ) + .await + { Ok(msg) => match transport.process_server_message(&client_tx, msg).await { Ok(_) => (), Err(err) => { diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index a7399955c..465130faa 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -90,11 +90,12 @@ impl Transport { async fn recv_server_message( reader: &mut (impl AsyncBufRead + Unpin + Send), buffer: &mut String, + content: &mut Vec, language_server_name: &str, ) -> Result { let mut content_length = None; loop { - buffer.truncate(0); + buffer.clear(); if reader.read_line(buffer).await? == 0 { return Err(Error::StreamClosed); }; @@ -126,11 +127,9 @@ impl Transport { } let content_length = content_length.context("missing content length")?; - - //TODO: reuse vector - let mut content = vec![0; content_length]; - reader.read_exact(&mut content).await?; - let msg = std::str::from_utf8(&content).context("invalid utf8 from server")?; + content.resize(content_length, 0); + reader.read_exact(content).await?; + let msg = std::str::from_utf8(content).context("invalid utf8 from server")?; info!("{language_server_name} <- {msg}"); @@ -255,9 +254,15 @@ impl Transport { client_tx: UnboundedSender<(LanguageServerId, jsonrpc::Call)>, ) { let mut recv_buffer = String::new(); + let mut content_buffer = Vec::new(); loop { - match Self::recv_server_message(&mut server_stdout, &mut recv_buffer, &transport.name) - .await + match Self::recv_server_message( + &mut server_stdout, + &mut recv_buffer, + &mut content_buffer, + &transport.name, + ) + .await { Ok(msg) => { match transport