diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs index 5996f88298..643ba98f51 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -21,7 +21,7 @@ use crate::{ serialize_span_data_index_map, }, }, - process::ProcMacroServerProcess, + process::{ProcMacroWorker, SynIO}, transport::codec::postcard::PostcardProtocol, version, }; @@ -84,7 +84,7 @@ fn wrap_decode(err: io::Error) -> ServerError { } pub(crate) fn version_check( - srv: &ProcMacroServerProcess, + srv: &dyn ProcMacroWorker, callback: SubCallback<'_>, ) -> Result { let request = BidirectionalMessage::Request(Request::ApiVersionCheck {}); @@ -101,7 +101,7 @@ pub(crate) fn version_check( /// Enable support for rust-analyzer span mode if the server supports it. pub(crate) fn enable_rust_analyzer_spans( - srv: &ProcMacroServerProcess, + srv: &dyn ProcMacroWorker, callback: SubCallback<'_>, ) -> Result { let request = BidirectionalMessage::Request(Request::SetConfig(ServerConfig { @@ -120,7 +120,7 @@ pub(crate) fn enable_rust_analyzer_spans( /// Finds proc-macros in a given dynamic library. pub(crate) fn find_proc_macros( - srv: &ProcMacroServerProcess, + srv: &dyn ProcMacroWorker, dylib_path: &AbsPath, callback: SubCallback<'_>, ) -> Result, String>, ServerError> { @@ -175,7 +175,7 @@ pub(crate) fn expand( current_dir: Some(current_dir), }))); - let response_payload = run_request(&proc_macro.process, task, callback)?; + let response_payload = run_request(proc_macro.process.as_ref(), task, callback)?; match response_payload { BidirectionalMessage::Response(Response::ExpandMacro(it)) => Ok(it @@ -205,7 +205,7 @@ pub(crate) fn expand( } fn run_request( - srv: &ProcMacroServerProcess, + srv: &dyn ProcMacroWorker, msg: BidirectionalMessage, callback: SubCallback<'_>, ) -> Result { diff --git a/crates/proc-macro-api/src/legacy_protocol.rs b/crates/proc-macro-api/src/legacy_protocol.rs index aabe5a0118..56bf863a88 100644 --- a/crates/proc-macro-api/src/legacy_protocol.rs +++ b/crates/proc-macro-api/src/legacy_protocol.rs @@ -113,7 +113,7 @@ pub(crate) fn expand( current_dir: Some(current_dir), }; - let response = send_task(&proc_macro.process, Request::ExpandMacro(Box::new(task)))?; + let response = send_task(proc_macro.process.as_ref(), Request::ExpandMacro(Box::new(task)))?; match response { Response::ExpandMacro(it) => Ok(it @@ -143,7 +143,7 @@ pub(crate) fn expand( } /// Sends a request to the proc-macro server and waits for a response. -fn send_task(srv: &ProcMacroServerProcess, req: Request) -> Result { +fn send_task(srv: &dyn ProcMacroWorker, req: Request) -> Result { if let Some(server_error) = srv.exited() { return Err(server_error.clone()); } diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 01195c10fe..dd0c89103a 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -27,7 +27,10 @@ use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use std::{fmt, io, sync::Arc, time::SystemTime}; pub use crate::transport::codec::Codec; -use crate::{bidirectional_protocol::SubCallback, process::ProcMacroServerProcess}; +use crate::{ + bidirectional_protocol::SubCallback, + process::{ProcMacroServerProcess, ProcMacroWorker}, +}; /// The versions of the server protocol pub mod version { @@ -85,7 +88,7 @@ pub struct ProcMacroClient { /// /// That means that concurrent salsa requests may block each other when expanding proc macros, /// which is unfortunate, but simple and good enough for the time being. - process: Arc, + worker: Arc, path: AbsPathBuf, } @@ -107,7 +110,7 @@ impl MacroDylib { /// we share a single expander process for all macros within a workspace. #[derive(Debug, Clone)] pub struct ProcMacro { - process: Arc, + process: Arc, dylib_path: Arc, name: Box, kind: ProcMacroKind, @@ -171,7 +174,7 @@ impl ProcMacroClient { version: Option<&Version>, ) -> io::Result { let process = ProcMacroServerProcess::run(spawn, version, || "".to_owned())?; - Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() }) + Ok(ProcMacroClient { worker: Arc::new(process), path: process_path.to_owned() }) } /// Returns the absolute path to the proc-macro server. @@ -186,7 +189,7 @@ impl ProcMacroClient { callback: Option>, ) -> Result, ServerError> { let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered(); - let macros = self.process.find_proc_macros(&dylib.path, callback)?; + let macros = self.worker.find_proc_macros(&dylib.path, callback)?; let dylib_path = Arc::new(dylib.path); let dylib_last_modified = std::fs::metadata(dylib_path.as_path()) @@ -196,7 +199,7 @@ impl ProcMacroClient { Ok(macros) => Ok(macros .into_iter() .map(|(name, kind)| ProcMacro { - process: self.process.clone(), + process: self.worker.clone(), name: name.into(), kind, dylib_path: dylib_path.clone(), @@ -209,7 +212,7 @@ impl ProcMacroClient { /// Checks if the proc-macro server has exited. pub fn exited(&self) -> Option<&ServerError> { - self.process.exited() + self.worker.exited() } } diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index cd387dad0d..a206e9fc5d 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -1,8 +1,9 @@ //! Handle process life-time and message passing for proc-macro client use std::{ + fmt::Debug, io::{self, BufRead, BufReader, Read, Write}, - panic::AssertUnwindSafe, + panic::{AssertUnwindSafe, RefUnwindSafe}, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, sync::{Arc, Mutex, OnceLock}, }; @@ -74,12 +75,79 @@ impl ProcessExit for Process { } /// Maintains the state of the proc-macro server process. -struct ProcessSrvState { +pub(crate) struct ProcessSrvState { process: Box, stdin: Box, stdout: Box, } +impl ProcMacroWorker for ProcMacroServerProcess { + fn find_proc_macros( + &self, + dylib_path: &AbsPath, + callback: Option>, + ) -> Result, String>, ServerError> { + ProcMacroServerProcess::find_proc_macros(self, dylib_path, callback) + } + + fn expand( + &self, + proc_macro: &ProcMacro, + subtree: tt::SubtreeView<'_>, + attr: Option>, + env: Vec<(String, String)>, + def_site: Span, + call_site: Span, + mixed_site: Span, + current_dir: String, + callback: Option>, + ) -> Result, ServerError> { + ProcMacroServerProcess::expand( + self, + proc_macro, + subtree, + attr, + env, + def_site, + call_site, + mixed_site, + current_dir, + callback, + ) + } + + fn exited(&self) -> Option<&ServerError> { + ProcMacroServerProcess::exited(self) + } + + fn version(&self) -> u32 { + ProcMacroServerProcess::version(self) + } + + fn rust_analyzer_spans(&self) -> bool { + ProcMacroServerProcess::rust_analyzer_spans(self) + } + + fn enable_rust_analyzer_spans( + &self, + callback: Option>, + ) -> Result { + ProcMacroServerProcess::enable_rust_analyzer_spans(self, callback) + } + + fn use_postcard(&self) -> bool { + ProcMacroServerProcess::use_postcard(self) + } + + fn state(&self) -> &Mutex { + &self.state + } + + fn get_exited(&self) -> &OnceLock> { + &self.exited + } +} + impl ProcMacroServerProcess { /// Starts the proc-macro server and performs a version check pub(crate) fn spawn<'a>( @@ -291,9 +359,13 @@ impl ProcMacroServerProcess { ), } } +} +pub(crate) struct SynIO; + +impl SynIO { pub(crate) fn send_task( - &self, + proc_macro_worker: &dyn ProcMacroWorker, send: impl FnOnce( &mut dyn Write, &mut dyn BufRead, @@ -302,7 +374,7 @@ impl ProcMacroServerProcess { ) -> Result, ServerError>, req: Request, ) -> Result { - self.with_locked_io::(|writer, reader, buf| { + SynIO::with_locked_io::(proc_macro_worker, |writer, reader, buf| { send(writer, reader, req, buf).and_then(|res| { res.ok_or_else(|| { let message = "proc-macro server did not respond with data".to_owned(); @@ -319,10 +391,10 @@ impl ProcMacroServerProcess { } pub(crate) fn with_locked_io( - &self, + proc_macro_worker: &dyn ProcMacroWorker, f: impl FnOnce(&mut dyn Write, &mut dyn BufRead, &mut C::Buf) -> Result, ) -> Result { - let state = &mut *self.state.lock().unwrap(); + let state = &mut *proc_macro_worker.state().lock().unwrap(); let mut buf = C::Buf::default(); f(&mut state.stdin, &mut state.stdout, &mut buf).map_err(|e| { @@ -330,7 +402,11 @@ impl ProcMacroServerProcess { match state.process.exit_err() { None => e, Some(server_error) => { - self.exited.get_or_init(|| AssertUnwindSafe(server_error)).0.clone() + proc_macro_worker + .get_exited() + .get_or_init(|| AssertUnwindSafe(server_error)) + .0 + .clone() } } } else { @@ -340,11 +416,11 @@ impl ProcMacroServerProcess { } pub(crate) fn run_bidirectional( - &self, + proc_macro_worker: &dyn ProcMacroWorker, initial: BidirectionalMessage, callback: SubCallback<'_>, ) -> Result { - self.with_locked_io::(|writer, reader, buf| { + SynIO::with_locked_io::(proc_macro_worker, |writer, reader, buf| { bidirectional_protocol::run_conversation::(writer, reader, buf, initial, callback) }) }