├── .gitignore ├── Cargo.toml ├── README.md ├── LICENSE ├── src ├── transport.rs └── lib.rs ├── examples └── process.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lsp-client" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | description = "A client for the Language Server Protocol" 7 | repository = "https://github.com/unknown/lsp-client" 8 | readme = "README.md" 9 | license = "MIT" 10 | 11 | [dependencies] 12 | async-trait = "0.1.85" 13 | jsonrpsee = { version = "0.24.8", features = ["async-client", "client-core"] } 14 | lsp-types = "0.97.0" 15 | serde = "1.0.217" 16 | serde_json = "1.0.138" 17 | thiserror = "2.0.11" 18 | tokio = { version = "1.43.0", features = ["io-util"] } 19 | 20 | [dev-dependencies] 21 | anyhow = "1.0.95" 22 | tokio = { version = "1.43.0", features = ["full"] } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lsp-client 2 | 3 | [![crates.io](https://img.shields.io/crates/v/lsp-client.svg)](https://crates.io/crates/lsp-client) 4 | [![Documentation](https://docs.rs/lsp-client/badge.svg)](https://docs.rs/lsp-client) 5 | [![MIT licensed](https://img.shields.io/crates/l/lsp-client.svg)](./LICENSE) 6 | 7 | A client for the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/). 8 | 9 | ## Usage 10 | 11 | Start a language server and create a client to communicate with it. 12 | 13 | ```rust 14 | let mut child = Command::new("rust-analyzer") 15 | .stdin(Stdio::piped()) 16 | .stdout(Stdio::piped()) 17 | .spawn() 18 | .unwrap(); 19 | 20 | let stdin = child.stdin.take().unwrap(); 21 | let stdout = child.stdout.take()..unwrap(); 22 | let (tx, rx) = io_transport(stdin, stdout); 23 | let client = LspClient::new(tx, rx); 24 | ``` 25 | 26 | See the [examples](examples) directory for more usage examples. 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 David Mo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/transport.rs: -------------------------------------------------------------------------------- 1 | use jsonrpsee::core::client::{ReceivedMessage, TransportReceiverT, TransportSenderT}; 2 | use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader}; 3 | 4 | /// Error that can occur when reading or sending messages on a transport. 5 | #[derive(thiserror::Error, Debug)] 6 | pub enum TransportError { 7 | /// Error in I/O operation. 8 | #[error("io error: {0}")] 9 | Io(#[from] std::io::Error), 10 | /// Error in parsing message. 11 | #[error("parse error: {0}")] 12 | Parse(String), 13 | } 14 | 15 | /// Sending end of I/O transport. 16 | pub struct Sender(T) 17 | where 18 | T: AsyncWrite + Send + Unpin + 'static; 19 | 20 | #[async_trait::async_trait] 21 | impl TransportSenderT for Sender 22 | where 23 | T: AsyncWrite + Send + Unpin + 'static, 24 | { 25 | type Error = TransportError; 26 | 27 | async fn send(&mut self, msg: String) -> Result<(), Self::Error> { 28 | let msg_with_header = format!("Content-Length: {}\r\n\r\n{}", msg.len(), msg); 29 | self.0.write_all(msg_with_header.as_bytes()).await?; 30 | Ok(()) 31 | } 32 | } 33 | 34 | /// Receiving end of I/O transport. 35 | pub struct Receiver(BufReader) 36 | where 37 | T: AsyncRead + Send + Unpin + 'static; 38 | 39 | #[async_trait::async_trait] 40 | impl TransportReceiverT for Receiver 41 | where 42 | T: AsyncRead + Send + Unpin + 'static, 43 | { 44 | type Error = TransportError; 45 | 46 | async fn receive(&mut self) -> Result { 47 | let mut content_length: Option = None; 48 | 49 | // Parse header part. 50 | // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#baseProtocol 51 | let mut line = String::new(); 52 | loop { 53 | self.0.read_line(&mut line).await?; 54 | match line.as_str() { 55 | // End of header. 56 | "\r\n" => break, 57 | // Content-Length: the length of the content part in bytes. 58 | line if line.starts_with("Content-Length: ") => { 59 | // "Content-Length: " is 16 chars long and the last 2 chars are \r\n. 60 | let len = &line[16..line.len() - 2]; 61 | let len = len 62 | .parse::() 63 | .map_err(|e| TransportError::Parse(e.to_string()))?; 64 | content_length = Some(len); 65 | } 66 | _ => {} 67 | } 68 | line.clear(); 69 | } 70 | 71 | let content_length = content_length.ok_or(TransportError::Parse( 72 | "Content-Length header not found".to_string(), 73 | ))?; 74 | let mut buf = vec![0; content_length]; 75 | self.0.read_exact(&mut buf).await?; 76 | Ok(ReceivedMessage::Bytes(buf)) 77 | } 78 | } 79 | 80 | /// Create a I/O transport `Sender` and `Receiver` pair. 81 | pub fn io_transport(input: I, output: O) -> (Sender, Receiver) 82 | where 83 | I: AsyncWrite + Send + Unpin + 'static, 84 | O: AsyncRead + Send + Unpin + 'static, 85 | { 86 | let sender = Sender(input); 87 | let receiver = Receiver(BufReader::new(output)); 88 | (sender, receiver) 89 | } 90 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod transport; 2 | 3 | use jsonrpsee::{ 4 | async_client::{Client, ClientBuilder}, 5 | core::{ 6 | client::{ 7 | ClientT, Subscription, SubscriptionClientT, TransportReceiverT, TransportSenderT, 8 | }, 9 | traits::ToRpcParams, 10 | }, 11 | }; 12 | use lsp_types::{notification::*, request::*, *}; 13 | use serde::Serialize; 14 | use serde_json::value::RawValue; 15 | 16 | struct SerdeParam(T) 17 | where 18 | T: Serialize; 19 | 20 | impl ToRpcParams for SerdeParam 21 | where 22 | T: Serialize, 23 | { 24 | fn to_rpc_params(self) -> Result>, serde_json::Error> { 25 | let json = serde_json::to_string(&self.0)?; 26 | RawValue::from_string(json).map(Some) 27 | } 28 | } 29 | 30 | #[derive(thiserror::Error, Debug)] 31 | pub enum LspError { 32 | #[error("jsonrpsee error: {0}")] 33 | Jsonrpsee(#[from] jsonrpsee::core::client::Error), 34 | } 35 | 36 | /// A client for the Language Server Protocol. 37 | #[derive(Debug)] 38 | pub struct LspClient { 39 | client: Client, 40 | } 41 | 42 | impl LspClient { 43 | pub fn new(sender: S, receiver: R) -> Self 44 | where 45 | S: TransportSenderT + Send, 46 | R: TransportReceiverT + Send, 47 | { 48 | let client = ClientBuilder::default().build_with_tokio(sender, receiver); 49 | Self { client } 50 | } 51 | 52 | /// Request the server to initialize the client. 53 | /// 54 | /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize 55 | pub async fn initialize(&self, params: InitializeParams) -> Result { 56 | self.send_request::(params).await 57 | } 58 | 59 | /// Notify the server that the client received the result of the `initialize` request. 60 | /// 61 | /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialized 62 | pub async fn initialized(&self) -> Result<(), LspError> { 63 | let params = InitializedParams {}; 64 | self.send_notification::(params).await 65 | } 66 | 67 | /// Request the server to shutdown the client. 68 | /// 69 | /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#shutdown 70 | pub async fn shutdown(&self) -> Result<(), LspError> { 71 | self.send_request::(()).await 72 | } 73 | 74 | /// Notify the server to exit the process. 75 | /// 76 | /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#exit 77 | pub async fn exit(&self) -> Result<(), LspError> { 78 | self.send_notification::(()).await 79 | } 80 | 81 | /// Send an LSP request to the server. 82 | pub async fn send_request(&self, params: R::Params) -> Result 83 | where 84 | R: Request, 85 | { 86 | let result = self.client.request(R::METHOD, SerdeParam(params)).await?; 87 | Ok(result) 88 | } 89 | 90 | /// Send an LSP notification to the server. 91 | pub async fn send_notification(&self, params: N::Params) -> Result<(), LspError> 92 | where 93 | N: Notification, 94 | { 95 | self.client 96 | .notification(N::METHOD, SerdeParam(params)) 97 | .await?; 98 | Ok(()) 99 | } 100 | 101 | /// Create a subscription to an LSP notification. 102 | pub async fn subscribe_to_method(&self) -> Result, LspError> 103 | where 104 | N: Notification, 105 | { 106 | let subscription = self.client.subscribe_to_method(N::METHOD).await?; 107 | Ok(subscription) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /examples/process.rs: -------------------------------------------------------------------------------- 1 | use std::{path::PathBuf, process::Stdio, str::FromStr}; 2 | 3 | use anyhow::{Context, Result}; 4 | use lsp_client::{transport::io_transport, LspClient}; 5 | use lsp_types::{notification::*, request::*, *}; 6 | use tokio::{process::Command, sync::oneshot}; 7 | 8 | #[tokio::main] 9 | async fn main() -> Result<()> { 10 | let mut child = Command::new("rust-analyzer") 11 | .stdin(Stdio::piped()) 12 | .stdout(Stdio::piped()) 13 | .spawn() 14 | .context("failed to spawn rust-analyzer")?; 15 | 16 | let stdin = child.stdin.take().context("missing stdin")?; 17 | let stdout = child.stdout.take().context("missing stdout")?; 18 | let (tx, rx) = io_transport(stdin, stdout); 19 | let client = LspClient::new(tx, rx); 20 | 21 | // Channel to wait for rust-analyzer to finish indexing the workspace. 22 | let (indexed_tx, indexed_rx) = oneshot::channel(); 23 | let mut subscription = client.subscribe_to_method::().await?; 24 | tokio::spawn(async move { 25 | while let Some(msg) = subscription.next().await { 26 | let params = msg.unwrap(); 27 | if matches!(params.token, NumberOrString::String(s) if s == "rustAnalyzer/Indexing") 28 | && matches!( 29 | params.value, 30 | ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)) 31 | ) 32 | { 33 | indexed_tx.send(()).unwrap(); 34 | break; 35 | } 36 | } 37 | subscription.unsubscribe().await.unwrap(); 38 | }); 39 | 40 | // Initialize rust-analyzer with the current file. 41 | let source_path = PathBuf::from(file!()) 42 | .canonicalize() 43 | .context("failed to get current file path")?; 44 | let source_uri = Uri::from_str(format!("file://{}", source_path.display()).as_str())?; 45 | 46 | let initialize_params = InitializeParams { 47 | capabilities: ClientCapabilities { 48 | workspace: Some(WorkspaceClientCapabilities { 49 | workspace_folders: Some(true), 50 | ..Default::default() 51 | }), 52 | window: Some(WindowClientCapabilities { 53 | work_done_progress: Some(true), 54 | ..Default::default() 55 | }), 56 | ..Default::default() 57 | }, 58 | workspace_folders: Some(vec![WorkspaceFolder { 59 | name: "root".to_string(), 60 | uri: source_uri.clone(), 61 | }]), 62 | ..Default::default() 63 | }; 64 | client.initialize(initialize_params).await?; 65 | client.initialized().await?; 66 | 67 | println!("Initialized rust-analyzer"); 68 | 69 | // Wait to finish indexing the workspace. 70 | indexed_rx 71 | .await 72 | .context("failed to receive indexing notification")?; 73 | 74 | println!("Finished indexing"); 75 | 76 | let goto_definition_params = GotoDefinitionParams { 77 | text_document_position_params: TextDocumentPositionParams { 78 | text_document: TextDocumentIdentifier { uri: source_uri }, 79 | // Position of the `LspClient` import. 80 | position: lsp_types::Position { 81 | line: 3, 82 | character: 32, 83 | }, 84 | }, 85 | work_done_progress_params: Default::default(), 86 | partial_result_params: Default::default(), 87 | }; 88 | let response = client 89 | .send_request::(goto_definition_params) 90 | .await? 91 | .context("failed to get goto definition response")?; 92 | 93 | println!("Goto definition response: {response:?}"); 94 | 95 | client.shutdown().await?; 96 | client.exit().await?; 97 | child.wait().await?; 98 | Ok(()) 99 | } 100 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "anyhow" 22 | version = "1.0.95" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" 25 | 26 | [[package]] 27 | name = "async-trait" 28 | version = "0.1.86" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" 31 | dependencies = [ 32 | "proc-macro2", 33 | "quote", 34 | "syn", 35 | ] 36 | 37 | [[package]] 38 | name = "autocfg" 39 | version = "1.4.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 42 | 43 | [[package]] 44 | name = "backtrace" 45 | version = "0.3.74" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 48 | dependencies = [ 49 | "addr2line", 50 | "cfg-if", 51 | "libc", 52 | "miniz_oxide", 53 | "object", 54 | "rustc-demangle", 55 | "windows-targets", 56 | ] 57 | 58 | [[package]] 59 | name = "bitflags" 60 | version = "1.3.2" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 63 | 64 | [[package]] 65 | name = "bitflags" 66 | version = "2.8.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 69 | 70 | [[package]] 71 | name = "bytes" 72 | version = "1.10.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" 75 | 76 | [[package]] 77 | name = "cfg-if" 78 | version = "1.0.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 81 | 82 | [[package]] 83 | name = "fluent-uri" 84 | version = "0.1.4" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" 87 | dependencies = [ 88 | "bitflags 1.3.2", 89 | ] 90 | 91 | [[package]] 92 | name = "fnv" 93 | version = "1.0.7" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 96 | 97 | [[package]] 98 | name = "futures-core" 99 | version = "0.3.31" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 102 | 103 | [[package]] 104 | name = "futures-sink" 105 | version = "0.3.31" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 108 | 109 | [[package]] 110 | name = "futures-task" 111 | version = "0.3.31" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 114 | 115 | [[package]] 116 | name = "futures-timer" 117 | version = "3.0.3" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" 120 | 121 | [[package]] 122 | name = "futures-util" 123 | version = "0.3.31" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 126 | dependencies = [ 127 | "futures-core", 128 | "futures-sink", 129 | "futures-task", 130 | "pin-project-lite", 131 | "pin-utils", 132 | ] 133 | 134 | [[package]] 135 | name = "gimli" 136 | version = "0.31.1" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 139 | 140 | [[package]] 141 | name = "http" 142 | version = "1.2.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 145 | dependencies = [ 146 | "bytes", 147 | "fnv", 148 | "itoa", 149 | ] 150 | 151 | [[package]] 152 | name = "itoa" 153 | version = "1.0.14" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 156 | 157 | [[package]] 158 | name = "jsonrpsee" 159 | version = "0.24.8" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "834af00800e962dee8f7bfc0f60601de215e73e78e5497d733a2919da837d3c8" 162 | dependencies = [ 163 | "jsonrpsee-core", 164 | ] 165 | 166 | [[package]] 167 | name = "jsonrpsee-core" 168 | version = "0.24.8" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "76637f6294b04e747d68e69336ef839a3493ca62b35bf488ead525f7da75c5bb" 171 | dependencies = [ 172 | "async-trait", 173 | "futures-timer", 174 | "futures-util", 175 | "jsonrpsee-types", 176 | "pin-project", 177 | "rustc-hash", 178 | "serde", 179 | "serde_json", 180 | "thiserror 1.0.69", 181 | "tokio", 182 | "tokio-stream", 183 | "tracing", 184 | ] 185 | 186 | [[package]] 187 | name = "jsonrpsee-types" 188 | version = "0.24.8" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6" 191 | dependencies = [ 192 | "http", 193 | "serde", 194 | "serde_json", 195 | "thiserror 1.0.69", 196 | ] 197 | 198 | [[package]] 199 | name = "libc" 200 | version = "0.2.169" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 203 | 204 | [[package]] 205 | name = "lock_api" 206 | version = "0.4.12" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 209 | dependencies = [ 210 | "autocfg", 211 | "scopeguard", 212 | ] 213 | 214 | [[package]] 215 | name = "lsp-client" 216 | version = "0.1.0" 217 | dependencies = [ 218 | "anyhow", 219 | "async-trait", 220 | "jsonrpsee", 221 | "lsp-types", 222 | "serde", 223 | "serde_json", 224 | "thiserror 2.0.11", 225 | "tokio", 226 | ] 227 | 228 | [[package]] 229 | name = "lsp-types" 230 | version = "0.97.0" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "53353550a17c04ac46c585feb189c2db82154fc84b79c7a66c96c2c644f66071" 233 | dependencies = [ 234 | "bitflags 1.3.2", 235 | "fluent-uri", 236 | "serde", 237 | "serde_json", 238 | "serde_repr", 239 | ] 240 | 241 | [[package]] 242 | name = "memchr" 243 | version = "2.7.4" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 246 | 247 | [[package]] 248 | name = "miniz_oxide" 249 | version = "0.8.4" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" 252 | dependencies = [ 253 | "adler2", 254 | ] 255 | 256 | [[package]] 257 | name = "mio" 258 | version = "1.0.3" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 261 | dependencies = [ 262 | "libc", 263 | "wasi", 264 | "windows-sys", 265 | ] 266 | 267 | [[package]] 268 | name = "object" 269 | version = "0.36.7" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 272 | dependencies = [ 273 | "memchr", 274 | ] 275 | 276 | [[package]] 277 | name = "once_cell" 278 | version = "1.20.3" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" 281 | 282 | [[package]] 283 | name = "parking_lot" 284 | version = "0.12.3" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 287 | dependencies = [ 288 | "lock_api", 289 | "parking_lot_core", 290 | ] 291 | 292 | [[package]] 293 | name = "parking_lot_core" 294 | version = "0.9.10" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 297 | dependencies = [ 298 | "cfg-if", 299 | "libc", 300 | "redox_syscall", 301 | "smallvec", 302 | "windows-targets", 303 | ] 304 | 305 | [[package]] 306 | name = "pin-project" 307 | version = "1.1.9" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" 310 | dependencies = [ 311 | "pin-project-internal", 312 | ] 313 | 314 | [[package]] 315 | name = "pin-project-internal" 316 | version = "1.1.9" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" 319 | dependencies = [ 320 | "proc-macro2", 321 | "quote", 322 | "syn", 323 | ] 324 | 325 | [[package]] 326 | name = "pin-project-lite" 327 | version = "0.2.16" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 330 | 331 | [[package]] 332 | name = "pin-utils" 333 | version = "0.1.0" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 336 | 337 | [[package]] 338 | name = "proc-macro2" 339 | version = "1.0.93" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 342 | dependencies = [ 343 | "unicode-ident", 344 | ] 345 | 346 | [[package]] 347 | name = "quote" 348 | version = "1.0.38" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 351 | dependencies = [ 352 | "proc-macro2", 353 | ] 354 | 355 | [[package]] 356 | name = "redox_syscall" 357 | version = "0.5.8" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 360 | dependencies = [ 361 | "bitflags 2.8.0", 362 | ] 363 | 364 | [[package]] 365 | name = "rustc-demangle" 366 | version = "0.1.24" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 369 | 370 | [[package]] 371 | name = "rustc-hash" 372 | version = "2.1.1" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 375 | 376 | [[package]] 377 | name = "ryu" 378 | version = "1.0.19" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" 381 | 382 | [[package]] 383 | name = "scopeguard" 384 | version = "1.2.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 387 | 388 | [[package]] 389 | name = "serde" 390 | version = "1.0.217" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 393 | dependencies = [ 394 | "serde_derive", 395 | ] 396 | 397 | [[package]] 398 | name = "serde_derive" 399 | version = "1.0.217" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 402 | dependencies = [ 403 | "proc-macro2", 404 | "quote", 405 | "syn", 406 | ] 407 | 408 | [[package]] 409 | name = "serde_json" 410 | version = "1.0.138" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" 413 | dependencies = [ 414 | "itoa", 415 | "memchr", 416 | "ryu", 417 | "serde", 418 | ] 419 | 420 | [[package]] 421 | name = "serde_repr" 422 | version = "0.1.19" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" 425 | dependencies = [ 426 | "proc-macro2", 427 | "quote", 428 | "syn", 429 | ] 430 | 431 | [[package]] 432 | name = "signal-hook-registry" 433 | version = "1.4.2" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 436 | dependencies = [ 437 | "libc", 438 | ] 439 | 440 | [[package]] 441 | name = "smallvec" 442 | version = "1.13.2" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 445 | 446 | [[package]] 447 | name = "socket2" 448 | version = "0.5.8" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 451 | dependencies = [ 452 | "libc", 453 | "windows-sys", 454 | ] 455 | 456 | [[package]] 457 | name = "syn" 458 | version = "2.0.98" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" 461 | dependencies = [ 462 | "proc-macro2", 463 | "quote", 464 | "unicode-ident", 465 | ] 466 | 467 | [[package]] 468 | name = "thiserror" 469 | version = "1.0.69" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 472 | dependencies = [ 473 | "thiserror-impl 1.0.69", 474 | ] 475 | 476 | [[package]] 477 | name = "thiserror" 478 | version = "2.0.11" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" 481 | dependencies = [ 482 | "thiserror-impl 2.0.11", 483 | ] 484 | 485 | [[package]] 486 | name = "thiserror-impl" 487 | version = "1.0.69" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 490 | dependencies = [ 491 | "proc-macro2", 492 | "quote", 493 | "syn", 494 | ] 495 | 496 | [[package]] 497 | name = "thiserror-impl" 498 | version = "2.0.11" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" 501 | dependencies = [ 502 | "proc-macro2", 503 | "quote", 504 | "syn", 505 | ] 506 | 507 | [[package]] 508 | name = "tokio" 509 | version = "1.43.0" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" 512 | dependencies = [ 513 | "backtrace", 514 | "bytes", 515 | "libc", 516 | "mio", 517 | "parking_lot", 518 | "pin-project-lite", 519 | "signal-hook-registry", 520 | "socket2", 521 | "tokio-macros", 522 | "windows-sys", 523 | ] 524 | 525 | [[package]] 526 | name = "tokio-macros" 527 | version = "2.5.0" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 530 | dependencies = [ 531 | "proc-macro2", 532 | "quote", 533 | "syn", 534 | ] 535 | 536 | [[package]] 537 | name = "tokio-stream" 538 | version = "0.1.17" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" 541 | dependencies = [ 542 | "futures-core", 543 | "pin-project-lite", 544 | "tokio", 545 | ] 546 | 547 | [[package]] 548 | name = "tracing" 549 | version = "0.1.41" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 552 | dependencies = [ 553 | "pin-project-lite", 554 | "tracing-attributes", 555 | "tracing-core", 556 | ] 557 | 558 | [[package]] 559 | name = "tracing-attributes" 560 | version = "0.1.28" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 563 | dependencies = [ 564 | "proc-macro2", 565 | "quote", 566 | "syn", 567 | ] 568 | 569 | [[package]] 570 | name = "tracing-core" 571 | version = "0.1.33" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 574 | dependencies = [ 575 | "once_cell", 576 | ] 577 | 578 | [[package]] 579 | name = "unicode-ident" 580 | version = "1.0.16" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" 583 | 584 | [[package]] 585 | name = "wasi" 586 | version = "0.11.0+wasi-snapshot-preview1" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 589 | 590 | [[package]] 591 | name = "windows-sys" 592 | version = "0.52.0" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 595 | dependencies = [ 596 | "windows-targets", 597 | ] 598 | 599 | [[package]] 600 | name = "windows-targets" 601 | version = "0.52.6" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 604 | dependencies = [ 605 | "windows_aarch64_gnullvm", 606 | "windows_aarch64_msvc", 607 | "windows_i686_gnu", 608 | "windows_i686_gnullvm", 609 | "windows_i686_msvc", 610 | "windows_x86_64_gnu", 611 | "windows_x86_64_gnullvm", 612 | "windows_x86_64_msvc", 613 | ] 614 | 615 | [[package]] 616 | name = "windows_aarch64_gnullvm" 617 | version = "0.52.6" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 620 | 621 | [[package]] 622 | name = "windows_aarch64_msvc" 623 | version = "0.52.6" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 626 | 627 | [[package]] 628 | name = "windows_i686_gnu" 629 | version = "0.52.6" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 632 | 633 | [[package]] 634 | name = "windows_i686_gnullvm" 635 | version = "0.52.6" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 638 | 639 | [[package]] 640 | name = "windows_i686_msvc" 641 | version = "0.52.6" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 644 | 645 | [[package]] 646 | name = "windows_x86_64_gnu" 647 | version = "0.52.6" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 650 | 651 | [[package]] 652 | name = "windows_x86_64_gnullvm" 653 | version = "0.52.6" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 656 | 657 | [[package]] 658 | name = "windows_x86_64_msvc" 659 | version = "0.52.6" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 662 | --------------------------------------------------------------------------------