summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs')
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
new file mode 100644
index 000000000..c4018d3b3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -0,0 +1,107 @@
+//! Handle process life-time and message passing for proc-macro client
+
+use std::{
+ ffi::{OsStr, OsString},
+ io::{self, BufRead, BufReader, Write},
+ process::{Child, ChildStdin, ChildStdout, Command, Stdio},
+};
+
+use paths::{AbsPath, AbsPathBuf};
+use stdx::JodChild;
+
+use crate::{
+ msg::{Message, Request, Response},
+ ProcMacroKind, ServerError,
+};
+
+#[derive(Debug)]
+pub(crate) struct ProcMacroProcessSrv {
+ _process: Process,
+ stdin: ChildStdin,
+ stdout: BufReader<ChildStdout>,
+}
+
+impl ProcMacroProcessSrv {
+ pub(crate) fn run(
+ process_path: AbsPathBuf,
+ args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+ ) -> 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: process, stdin, stdout };
+
+ Ok(srv)
+ }
+
+ pub(crate) fn find_proc_macros(
+ &mut self,
+ dylib_path: &AbsPath,
+ ) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
+ let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() };
+
+ let response = self.send_task(request)?;
+
+ match response {
+ Response::ListMacros(it) => Ok(it),
+ Response::ExpandMacro { .. } => {
+ Err(ServerError { message: "unexpected response".to_string(), io: None })
+ }
+ }
+ }
+
+ pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> {
+ let mut buf = String::new();
+ send_request(&mut self.stdin, &mut self.stdout, req, &mut buf)
+ }
+}
+
+#[derive(Debug)]
+struct Process {
+ child: JodChild,
+}
+
+impl Process {
+ fn run(
+ path: AbsPathBuf,
+ args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+ ) -> io::Result<Process> {
+ let args: Vec<OsString> = args.into_iter().map(|s| s.as_ref().into()).collect();
+ let child = JodChild(mk_child(&path, &args)?);
+ Ok(Process { child })
+ }
+
+ 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);
+
+ Some((stdin, read))
+ }
+}
+
+fn mk_child(
+ path: &AbsPath,
+ args: impl IntoIterator<Item = impl AsRef<OsStr>>,
+) -> io::Result<Child> {
+ Command::new(path.as_os_str())
+ .args(args)
+ .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::inherit())
+ .spawn()
+}
+
+fn send_request(
+ mut writer: &mut impl Write,
+ mut reader: &mut impl BufRead,
+ req: Request,
+ buf: &mut String,
+) -> Result<Response, ServerError> {
+ req.write(&mut writer)
+ .map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?;
+ let res = Response::read(&mut reader, buf)
+ .map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?;
+ res.ok_or_else(|| ServerError { message: "server exited".into(), io: None })
+}