lsp: Skip serializing of params if unit type (#46027)

Michael Barth created

Closes #45994 

Per the JSON-RPC specification, `params` "MUST be provided as a
Structured value" or the member "MAY be omitted." See specification
here: https://www.jsonrpc.org/specification#request_object

The code was passing in unit `()` for params which serde_json was
serializing to `null` which is not valid.

This pulls request adds an `is_unit` function and annotates the `params`
fields in the `Request` and `Notification` structs with the following:
 ```rs
#[serde(default, skip_serializing_if = "is_unit")]
```

so that the field will be omitted if the type is unit. This does also introduce a `'static` bound to these structs.

> [!WARNING]
> While this seems to me like a simple change, I am not super familiar with Rust, please look at this PR with extra scrutiny. The last thing I want to do is break everyone's LSP integration.


Release Notes:
- LSP integrations: send language server shutdown requests with correct parameters

Change summary

crates/lsp/src/lsp.rs | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

Detailed changes

crates/lsp/src/lsp.rs 🔗

@@ -25,6 +25,7 @@ use smol::{
 };
 
 use std::{
+    any::TypeId,
     collections::BTreeSet,
     ffi::{OsStr, OsString},
     fmt,
@@ -200,14 +201,22 @@ pub enum RequestId {
     Str(String),
 }
 
+fn is_unit<T: 'static>(_: &T) -> bool {
+    TypeId::of::<T>() == TypeId::of::<()>()
+}
+
 /// Language server protocol RPC request message.
 ///
 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
 #[derive(Serialize, Deserialize)]
-pub struct Request<'a, T> {
+pub struct Request<'a, T>
+where
+    T: 'static,
+{
     jsonrpc: &'static str,
     id: RequestId,
     method: &'a str,
+    #[serde(default, skip_serializing_if = "is_unit")]
     params: T,
 }
 
@@ -245,10 +254,14 @@ enum LspResult<T> {
 ///
 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
 #[derive(Serialize, Deserialize)]
-struct Notification<'a, T> {
+struct Notification<'a, T>
+where
+    T: 'static,
+{
     jsonrpc: &'static str,
     #[serde(borrow)]
     method: &'a str,
+    #[serde(default, skip_serializing_if = "is_unit")]
     params: T,
 }