1 //! Handle process life-time and message passing for proc-macro client
3 use crossbeam_channel::{bounded, Receiver, Sender};
6 use crate::msg::{ErrorCode, Message, Request, Response, ResponseError};
7 use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
9 use io::{BufRead, BufReader};
11 convert::{TryFrom, TryInto},
12 ffi::{OsStr, OsString},
14 path::{Path, PathBuf},
15 process::{Child, Command, Stdio},
19 #[derive(Debug, Default)]
20 pub(crate) struct ProcMacroProcessSrv {
21 inner: Option<Weak<Sender<Task>>>,
25 pub(crate) struct ProcMacroProcessThread {
26 // XXX: drop order is significant
27 sender: Arc<Sender<Task>>,
28 handle: jod_thread::JoinHandle<()>,
31 impl ProcMacroProcessSrv {
33 process_path: PathBuf,
34 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
35 ) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
36 let process = Process::run(process_path, args)?;
38 let (task_tx, task_rx) = bounded(0);
39 let handle = jod_thread::spawn(move || {
40 client_loop(task_rx, process);
43 let task_tx = Arc::new(task_tx);
44 let srv = ProcMacroProcessSrv { inner: Some(Arc::downgrade(&task_tx)) };
45 let thread = ProcMacroProcessThread { handle, sender: task_tx };
50 pub fn find_proc_macros(
53 ) -> Result<Vec<(String, ProcMacroKind)>, ra_tt::ExpansionError> {
54 let task = ListMacrosTask { lib: dylib_path.to_path_buf() };
56 let result: ListMacrosResult = self.send_task(Request::ListMacro(task))?;
65 ) -> Result<Subtree, ra_tt::ExpansionError> {
66 let task = ExpansionTask {
67 macro_body: subtree.clone(),
68 macro_name: derive_name.to_string(),
70 lib: dylib_path.to_path_buf(),
73 let result: ExpansionResult = self.send_task(Request::ExpansionMacro(task))?;
77 pub fn send_task<R>(&self, req: Request) -> Result<R, ra_tt::ExpansionError>
79 R: TryFrom<Response, Error = &'static str>,
81 let sender = match &self.inner {
82 None => return Err(ra_tt::ExpansionError::Unknown("No sender is found.".to_string())),
86 let (result_tx, result_rx) = bounded(0);
87 let sender = match sender.upgrade() {
89 return Err(ra_tt::ExpansionError::Unknown("Proc macro process is closed.".into()))
93 sender.send(Task { req: req.into(), result_tx }).unwrap();
96 .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;
99 Some(Response::Error(err)) => {
100 return Err(ra_tt::ExpansionError::ExpansionError(err.message));
102 Some(res) => Ok(res.try_into().map_err(|err| {
103 ra_tt::ExpansionError::Unknown(format!(
104 "Fail to get response, reason : {:#?} ",
108 None => Err(ra_tt::ExpansionError::Unknown("Empty result".into())),
113 fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
114 let (mut stdin, mut stdout) = match process.stdio() {
119 for task in task_rx {
120 let Task { req, result_tx } = task;
122 match send_request(&mut stdin, &mut stdout, req) {
123 Ok(res) => result_tx.send(res).unwrap(),
125 let res = Response::Error(ResponseError {
126 code: ErrorCode::ServerErrorEnd,
127 message: "Server closed".into(),
129 result_tx.send(res.into()).unwrap();
130 // Restart the process
131 if process.restart().is_err() {
134 let stdio = match process.stdio() {
147 result_tx: Sender<Option<Response>>,
156 impl Drop for Process {
158 let _ = self.child.kill();
165 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
166 ) -> io::Result<Process> {
167 let args = args.into_iter().map(|s| s.as_ref().into()).collect();
168 let child = mk_child(&path, &args)?;
169 Ok(Process { path, args, child })
172 fn restart(&mut self) -> io::Result<()> {
173 let _ = self.child.kill();
174 self.child = mk_child(&self.path, &self.args)?;
178 fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
179 let stdin = self.child.stdin.take()?;
180 let stdout = self.child.stdout.take()?;
181 let read = BufReader::new(stdout);
187 fn mk_child(path: &Path, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> io::Result<Child> {
190 .stdin(Stdio::piped())
191 .stdout(Stdio::piped())
192 .stderr(Stdio::inherit())
197 mut writer: &mut impl Write,
198 mut reader: &mut impl BufRead,
200 ) -> io::Result<Option<Response>> {
201 req.write(&mut writer)?;
202 Ok(Response::read(&mut reader)?)