From de2122fb671b5bde0549fa04c0b6e3e82924264d Mon Sep 17 00:00:00 2001 From: Piotr Figiela <77412592+Draggu@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:58:16 +0200 Subject: [PATCH] Add Proc macro server commit-id:2ceebe3f --- Cargo.lock | 2 + scarb/Cargo.toml | 2 + scarb/src/ops/proc_macro_server/connection.rs | 101 ++++++++++++++++++ scarb/src/ops/proc_macro_server/mod.rs | 11 +- 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 scarb/src/ops/proc_macro_server/connection.rs diff --git a/Cargo.lock b/Cargo.lock index f8cbb2a5e..1dc12a3f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4812,6 +4812,7 @@ dependencies = [ "clap", "convert_case", "create-output-dir", + "crossbeam-channel", "data-encoding", "deno_task_shell", "derive_builder", @@ -4838,6 +4839,7 @@ dependencies = [ "pathdiff", "petgraph", "predicates", + "scarb-proc-macro-server-types", "ra_ap_toolchain", "redb", "reqwest", diff --git a/scarb/Cargo.toml b/scarb/Cargo.toml index 5f887e927..8693d8725 100644 --- a/scarb/Cargo.toml +++ b/scarb/Cargo.toml @@ -37,6 +37,7 @@ camino.workspace = true clap.workspace = true convert_case.workspace = true create-output-dir = { path = "../utils/create-output-dir" } +crossbeam-channel = "0.5.13" data-encoding.workspace = true deno_task_shell.workspace = true derive_builder.workspace = true @@ -56,6 +57,7 @@ libloading.workspace = true once_cell.workspace = true pathdiff.workspace = true petgraph.workspace = true +scarb-proc-macro-server-types = { path = "../utils/scarb-proc-macro-server-types" } ra_ap_toolchain.workspace = true redb.workspace = true reqwest.workspace = true diff --git a/scarb/src/ops/proc_macro_server/connection.rs b/scarb/src/ops/proc_macro_server/connection.rs new file mode 100644 index 000000000..b24451fe3 --- /dev/null +++ b/scarb/src/ops/proc_macro_server/connection.rs @@ -0,0 +1,101 @@ +use std::io::{BufRead, Write}; +use std::thread::JoinHandle; + +use crossbeam_channel::{Receiver, Sender}; +use scarb_proc_macro_server_types::jsonrpc::{RpcRequest, RpcResponse}; +use tracing::error; + +pub struct Connection { + pub sender: Sender, + pub receiver: Receiver, + io_threads: IoThreads, +} + +impl Connection { + pub fn new() -> Self { + let (reader_sender, reader_receiver) = crossbeam_channel::bounded(0); + let (writer_sender, writer_receiver) = crossbeam_channel::bounded(0); + + let reader = std::thread::spawn(move || { + let stdin = std::io::stdin(); + let mut stdin = stdin.lock(); + let mut line = String::new(); + + loop { + line.clear(); + + match stdin.read_line(&mut line) { + // End of stream. + Ok(0) => break, + Ok(_) => {} + Err(_) => { + // Report unexpected error. + error!("Reading from stdin failed"); + break; + } + }; + + if line.is_empty() { + continue; + } + + let Ok(request) = serde_json::from_str(&line) else { + error!("Deserializing request failed, used input:\n{line}"); + break; + }; + + if reader_sender.send(request).is_err() { + break; + } + } + }); + + let writer = std::thread::spawn(move || { + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + for response in writer_receiver { + // This should not fail. + let mut res = serde_json::to_vec(&response).unwrap(); + + res.push(b'\n'); + + if stdout.write_all(&res).is_err() { + error!("Writing to stdout failed"); + break; + } + + if stdout.flush().is_err() { + error!("Flushing stdout failed"); + break; + } + } + }); + + let io_threads = IoThreads { reader, writer }; + + Self { + sender: writer_sender, + receiver: reader_receiver, + io_threads, + } + } + + pub fn join(self) { + // There are clones of these used by worker threads. Drop only our refs. + drop(self.sender); + drop(self.receiver); + + if let Err(err) = self.io_threads.reader.join() { + std::panic::panic_any(err); + } + if let Err(err) = self.io_threads.writer.join() { + std::panic::panic_any(err); + } + } +} + +struct IoThreads { + reader: JoinHandle<()>, + writer: JoinHandle<()>, +} diff --git a/scarb/src/ops/proc_macro_server/mod.rs b/scarb/src/ops/proc_macro_server/mod.rs index 9f1fb9d5e..3cc30ea1e 100644 --- a/scarb/src/ops/proc_macro_server/mod.rs +++ b/scarb/src/ops/proc_macro_server/mod.rs @@ -1,6 +1,15 @@ use crate::compiler::plugin::proc_macro::ProcMacroHost; use anyhow::Result; +use connection::Connection; + +mod connection; pub fn start_proc_macro_server(proc_macros: ProcMacroHost) -> Result<()> { - unimplemented!() + let connection = Connection::new(); + + //TODO + + connection.join(); + + Ok(()) }