use tt::{SmolStr, Subtree};
-use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
+use crate::process::ProcMacroProcessSrv;
pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
pub use version::{read_dylib_info, RustCInfo};
#[derive(Debug)]
pub struct ProcMacroClient {
process: Arc<ProcMacroProcessSrv>,
- thread: ProcMacroProcessThread,
}
impl ProcMacroClient {
+ /// Spawns an external process as the proc macro server and returns a client connected to it.
pub fn extern_process(
process_path: PathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
) -> io::Result<ProcMacroClient> {
- let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
- Ok(ProcMacroClient { process: Arc::new(process), thread })
+ let process = ProcMacroProcessSrv::run(process_path, args)?;
+ Ok(ProcMacroClient { process: Arc::new(process) })
}
pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> {
use std::{
convert::{TryFrom, TryInto},
ffi::{OsStr, OsString},
+ fmt,
io::{self, BufRead, BufReader, Write},
path::{Path, PathBuf},
- process::{Child, Command, Stdio},
- sync::{Arc, Weak},
+ process::{Child, ChildStdin, ChildStdout, Command, Stdio},
+ sync::Mutex,
};
-use crossbeam_channel::{bounded, Receiver, Sender};
use stdx::JodChild;
use crate::{
rpc::{ListMacrosResult, ListMacrosTask, ProcMacroKind},
};
-#[derive(Debug, Default)]
pub(crate) struct ProcMacroProcessSrv {
- inner: Weak<Sender<Task>>,
+ process: Mutex<Process>,
+ stdio: Mutex<(ChildStdin, BufReader<ChildStdout>)>,
}
-#[derive(Debug)]
-pub(crate) struct ProcMacroProcessThread {
- // XXX: drop order is significant
- sender: Arc<Sender<Task>>,
- handle: jod_thread::JoinHandle<()>,
+impl fmt::Debug for ProcMacroProcessSrv {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ProcMacroProcessSrv").field("process", &self.process).finish()
+ }
}
impl ProcMacroProcessSrv {
pub(crate) fn run(
process_path: PathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
- ) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
- let process = Process::run(process_path, args)?;
-
- let (task_tx, task_rx) = bounded(0);
- let handle = jod_thread::Builder::new()
- .name("ProcMacroClient".to_owned())
- .spawn(move || {
- client_loop(task_rx, process);
- })
- .expect("failed to spawn thread");
-
- let task_tx = Arc::new(task_tx);
- let srv = ProcMacroProcessSrv { inner: Arc::downgrade(&task_tx) };
- let thread = ProcMacroProcessThread { handle, sender: task_tx };
-
- Ok((thread, srv))
+ ) -> io::Result<ProcMacroProcessSrv> {
+ let mut process = Process::run(process_path, args)?;
+ let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
+
+ let srv = ProcMacroProcessSrv {
+ process: Mutex::new(process),
+ stdio: Mutex::new((stdin, stdout)),
+ };
+
+ Ok(srv)
}
pub(crate) fn find_proc_macros(
where
R: TryFrom<Response, Error = &'static str>,
{
- let (result_tx, result_rx) = bounded(0);
- let sender = match self.inner.upgrade() {
- None => return Err(tt::ExpansionError::Unknown("proc macro process is closed".into())),
- Some(it) => it,
- };
- sender
- .send(Task { req, result_tx })
- .map_err(|_| tt::ExpansionError::Unknown("proc macro server crashed".into()))?;
+ let mut guard = self.stdio.lock().unwrap_or_else(|e| e.into_inner());
+ let stdio = &mut *guard;
+ let (stdin, stdout) = (&mut stdio.0, &mut stdio.1);
- let res = result_rx
- .recv()
- .map_err(|_| tt::ExpansionError::Unknown("proc macro server crashed".into()))?;
-
- match res {
- Some(Response::Error(err)) => Err(tt::ExpansionError::ExpansionError(err.message)),
- Some(res) => Ok(res.try_into().map_err(|err| {
- tt::ExpansionError::Unknown(format!("Fail to get response, reason : {:#?} ", err))
- })?),
- None => Err(tt::ExpansionError::Unknown("Empty result".into())),
- }
- }
-}
-
-fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
- let (mut stdin, mut stdout) = process.stdio().expect("couldn't access child stdio");
-
- let mut buf = String::new();
-
- for Task { req, result_tx } in task_rx {
- match send_request(&mut stdin, &mut stdout, req, &mut buf) {
- Ok(res) => result_tx.send(res).unwrap(),
+ let mut buf = String::new();
+ let res = match send_request(stdin, stdout, req, &mut buf) {
+ Ok(res) => res,
Err(err) => {
+ let mut process = self.process.lock().unwrap_or_else(|e| e.into_inner());
log::error!(
"proc macro server crashed, server process state: {:?}, server request error: {:?}",
process.child.try_wait(),
code: ErrorCode::ServerErrorEnd,
message: "proc macro server crashed".into(),
});
- result_tx.send(res.into()).unwrap();
- // Exit the thread.
- break;
+ Some(res)
}
+ };
+
+ match res {
+ Some(Response::Error(err)) => Err(tt::ExpansionError::ExpansionError(err.message)),
+ Some(res) => Ok(res.try_into().map_err(|err| {
+ tt::ExpansionError::Unknown(format!("Fail to get response, reason : {:#?} ", err))
+ })?),
+ None => Err(tt::ExpansionError::Unknown("Empty result".into())),
}
}
}
-struct Task {
- req: Request,
- result_tx: Sender<Option<Response>>,
-}
-
+#[derive(Debug)]
struct Process {
child: JodChild,
}
Ok(Process { child })
}
- fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
+ fn stdio(&mut self) -> Option<(ChildStdin, BufReader<ChildStdout>)> {
let stdin = self.child.stdin.take()?;
let stdout = self.child.stdout.take()?;
let read = BufReader::new(stdout);