aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_proc_macro
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-04-21 13:32:02 +0100
committerBenjamin Coenen <[email protected]>2020-04-21 13:32:02 +0100
commit7f143b154e7c47b1f5bdc558bb0b5d1f2bf74f8d (patch)
tree571b7d5bdfc84bdaeaa8235221fd96a87453fe05 /crates/ra_proc_macro
parent1c3a1385a587f0713908c0ae888ffad31f13de11 (diff)
parenta88887df0726cc3d390db4bfbbc1274195d87f91 (diff)
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer
Diffstat (limited to 'crates/ra_proc_macro')
-rw-r--r--crates/ra_proc_macro/src/lib.rs17
-rw-r--r--crates/ra_proc_macro/src/msg.rs37
-rw-r--r--crates/ra_proc_macro/src/process.rs118
-rw-r--r--crates/ra_proc_macro/src/rpc.rs18
4 files changed, 89 insertions, 101 deletions
diff --git a/crates/ra_proc_macro/src/lib.rs b/crates/ra_proc_macro/src/lib.rs
index b200fd126..004943b9e 100644
--- a/crates/ra_proc_macro/src/lib.rs
+++ b/crates/ra_proc_macro/src/lib.rs
@@ -2,7 +2,7 @@
2//! 2//!
3//! We separate proc-macro expanding logic to an extern program to allow 3//! We separate proc-macro expanding logic to an extern program to allow
4//! different implementations (e.g. wasm or dylib loading). And this crate 4//! different implementations (e.g. wasm or dylib loading). And this crate
5//! is used to provide basic infrastructure for communication between two 5//! is used to provide basic infrastructure for communication between two
6//! processes: Client (RA itself), Server (the external program) 6//! processes: Client (RA itself), Server (the external program)
7 7
8mod rpc; 8mod rpc;
@@ -13,6 +13,7 @@ use process::{ProcMacroProcessSrv, ProcMacroProcessThread};
13use ra_tt::{SmolStr, Subtree}; 13use ra_tt::{SmolStr, Subtree};
14use std::{ 14use std::{
15 ffi::OsStr, 15 ffi::OsStr,
16 io,
16 path::{Path, PathBuf}, 17 path::{Path, PathBuf},
17 sync::Arc, 18 sync::Arc,
18}; 19};
@@ -57,14 +58,10 @@ pub struct ProcMacroClient {
57} 58}
58 59
59impl ProcMacroClient { 60impl ProcMacroClient {
60 pub fn extern_process<I, S>( 61 pub fn extern_process(
61 process_path: &Path, 62 process_path: PathBuf,
62 args: I, 63 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
63 ) -> Result<ProcMacroClient, std::io::Error> 64 ) -> io::Result<ProcMacroClient> {
64 where
65 I: IntoIterator<Item = S>,
66 S: AsRef<OsStr>,
67 {
68 let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?; 65 let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
69 Ok(ProcMacroClient { 66 Ok(ProcMacroClient {
70 kind: ProcMacroClientKind::Process { process: Arc::new(process), thread }, 67 kind: ProcMacroClientKind::Process { process: Arc::new(process), thread },
@@ -84,7 +81,7 @@ impl ProcMacroClient {
84 ProcMacroClientKind::Process { process, .. } => { 81 ProcMacroClientKind::Process { process, .. } => {
85 let macros = match process.find_proc_macros(dylib_path) { 82 let macros = match process.find_proc_macros(dylib_path) {
86 Err(err) => { 83 Err(err) => {
87 eprintln!("Fail to find proc macro. Error: {:#?}", err); 84 eprintln!("Failed to find proc macros. Error: {:#?}", err);
88 return vec![]; 85 return vec![];
89 } 86 }
90 Ok(macros) => macros, 87 Ok(macros) => macros,
diff --git a/crates/ra_proc_macro/src/msg.rs b/crates/ra_proc_macro/src/msg.rs
index aa95bcc8f..95d9b8804 100644
--- a/crates/ra_proc_macro/src/msg.rs
+++ b/crates/ra_proc_macro/src/msg.rs
@@ -1,4 +1,4 @@
1//! Defines messages for cross-process message based on `ndjson` wire protocol 1//! Defines messages for cross-process message passing based on `ndjson` wire protocol
2 2
3use std::{ 3use std::{
4 convert::TryFrom, 4 convert::TryFrom,
@@ -31,7 +31,7 @@ macro_rules! impl_try_from_response {
31 fn try_from(value: Response) -> Result<Self, Self::Error> { 31 fn try_from(value: Response) -> Result<Self, Self::Error> {
32 match value { 32 match value {
33 Response::$tag(res) => Ok(res), 33 Response::$tag(res) => Ok(res),
34 _ => Err("Fail to convert from response"), 34 _ => Err(concat!("Failed to convert response to ", stringify!($tag))),
35 } 35 }
36 } 36 }
37 } 37 }
@@ -53,18 +53,16 @@ pub enum ErrorCode {
53 ExpansionError, 53 ExpansionError,
54} 54}
55 55
56pub trait Message: Sized + Serialize + DeserializeOwned { 56pub trait Message: Serialize + DeserializeOwned {
57 fn read(r: &mut impl BufRead) -> io::Result<Option<Self>> { 57 fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> {
58 let text = match read_json(r)? { 58 Ok(match read_json(inp)? {
59 None => return Ok(None), 59 None => None,
60 Some(text) => text, 60 Some(text) => Some(serde_json::from_str(&text)?),
61 }; 61 })
62 let msg = serde_json::from_str(&text)?;
63 Ok(Some(msg))
64 } 62 }
65 fn write(self, w: &mut impl Write) -> io::Result<()> { 63 fn write(self, out: &mut impl Write) -> io::Result<()> {
66 let text = serde_json::to_string(&self)?; 64 let text = serde_json::to_string(&self)?;
67 write_json(w, &text) 65 write_json(out, &text)
68 } 66 }
69} 67}
70 68
@@ -73,15 +71,12 @@ impl Message for Response {}
73 71
74fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> { 72fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> {
75 let mut buf = String::new(); 73 let mut buf = String::new();
76 if inp.read_line(&mut buf)? == 0 { 74 inp.read_line(&mut buf)?;
77 return Ok(None); 75 buf.pop(); // Remove traling '\n'
78 } 76 Ok(match buf.len() {
79 // Remove ending '\n' 77 0 => None,
80 let buf = &buf[..buf.len() - 1]; 78 _ => Some(buf),
81 if buf.is_empty() { 79 })
82 return Ok(None);
83 }
84 Ok(Some(buf.to_string()))
85} 80}
86 81
87fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { 82fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs
index f851570bc..673f80a7a 100644
--- a/crates/ra_proc_macro/src/process.rs
+++ b/crates/ra_proc_macro/src/process.rs
@@ -9,7 +9,7 @@ use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTas
9use io::{BufRead, BufReader}; 9use io::{BufRead, BufReader};
10use std::{ 10use std::{
11 convert::{TryFrom, TryInto}, 11 convert::{TryFrom, TryInto},
12 ffi::OsStr, 12 ffi::{OsStr, OsString},
13 io::{self, Write}, 13 io::{self, Write},
14 path::{Path, PathBuf}, 14 path::{Path, PathBuf},
15 process::{Child, Command, Stdio}, 15 process::{Child, Command, Stdio},
@@ -28,66 +28,11 @@ pub(crate) struct ProcMacroProcessThread {
28 handle: jod_thread::JoinHandle<()>, 28 handle: jod_thread::JoinHandle<()>,
29} 29}
30 30
31struct Task {
32 req: Request,
33 result_tx: Sender<Option<Response>>,
34}
35
36struct Process {
37 path: PathBuf,
38 child: Child,
39}
40
41impl Drop for Process {
42 fn drop(&mut self) {
43 let _ = self.child.kill();
44 }
45}
46
47impl Process {
48 fn run<I, S>(process_path: &Path, args: I) -> Result<Process, io::Error>
49 where
50 I: IntoIterator<Item = S>,
51 S: AsRef<OsStr>,
52 {
53 let child = Command::new(process_path.clone())
54 .args(args)
55 .stdin(Stdio::piped())
56 .stdout(Stdio::piped())
57 .stderr(Stdio::null())
58 .spawn()?;
59
60 Ok(Process { path: process_path.into(), child })
61 }
62
63 fn restart(&mut self) -> Result<(), io::Error> {
64 let _ = self.child.kill();
65 self.child = Command::new(self.path.clone())
66 .stdin(Stdio::piped())
67 .stdout(Stdio::piped())
68 .stderr(Stdio::null())
69 .spawn()?;
70 Ok(())
71 }
72
73 fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
74 let stdin = self.child.stdin.take()?;
75 let stdout = self.child.stdout.take()?;
76 let read = BufReader::new(stdout);
77
78 Some((stdin, read))
79 }
80}
81
82impl ProcMacroProcessSrv { 31impl ProcMacroProcessSrv {
83 pub fn run<I, S>( 32 pub fn run(
84 process_path: &Path, 33 process_path: PathBuf,
85 args: I, 34 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
86 ) -> Result<(ProcMacroProcessThread, ProcMacroProcessSrv), io::Error> 35 ) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
87 where
88 I: IntoIterator<Item = S>,
89 S: AsRef<OsStr>,
90 {
91 let process = Process::run(process_path, args)?; 36 let process = Process::run(process_path, args)?;
92 37
93 let (task_tx, task_rx) = bounded(0); 38 let (task_tx, task_rx) = bounded(0);
@@ -197,11 +142,62 @@ fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
197 } 142 }
198} 143}
199 144
145struct Task {
146 req: Request,
147 result_tx: Sender<Option<Response>>,
148}
149
150struct Process {
151 path: PathBuf,
152 args: Vec<OsString>,
153 child: Child,
154}
155
156impl Drop for Process {
157 fn drop(&mut self) {
158 let _ = self.child.kill();
159 }
160}
161
162impl Process {
163 fn run(
164 path: PathBuf,
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 })
170 }
171
172 fn restart(&mut self) -> io::Result<()> {
173 let _ = self.child.kill();
174 self.child = mk_child(&self.path, &self.args)?;
175 Ok(())
176 }
177
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);
182
183 Some((stdin, read))
184 }
185}
186
187fn mk_child(path: &Path, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> io::Result<Child> {
188 Command::new(&path)
189 .args(args)
190 .stdin(Stdio::piped())
191 .stdout(Stdio::piped())
192 .stderr(Stdio::null())
193 .spawn()
194}
195
200fn send_request( 196fn send_request(
201 mut writer: &mut impl Write, 197 mut writer: &mut impl Write,
202 mut reader: &mut impl BufRead, 198 mut reader: &mut impl BufRead,
203 req: Request, 199 req: Request,
204) -> Result<Option<Response>, io::Error> { 200) -> io::Result<Option<Response>> {
205 req.write(&mut writer)?; 201 req.write(&mut writer)?;
206 Ok(Response::read(&mut reader)?) 202 Ok(Response::read(&mut reader)?)
207} 203}
diff --git a/crates/ra_proc_macro/src/rpc.rs b/crates/ra_proc_macro/src/rpc.rs
index 66b3f55db..4ce485926 100644
--- a/crates/ra_proc_macro/src/rpc.rs
+++ b/crates/ra_proc_macro/src/rpc.rs
@@ -1,9 +1,9 @@
1//! Data struture serialization related stuffs for RPC 1//! Data struture serialization related stuff for RPC
2//! 2//!
3//! Define all necessary rpc serialization data structure, 3//! Defines all necessary rpc serialization data structures,
4//! which include ra_tt related data and some task messages. 4//! which includes `ra_tt` related data and some task messages.
5//! Although adding Serialize and Deserialize trait to ra_tt directly seem to be much easier, 5//! Although adding `Serialize` and `Deserialize` traits to `ra_tt` directly seems
6//! we deliberately duplicate the ra_tt struct with #[serde(with = "XXDef")] 6//! to be much easier, we deliberately duplicate `ra_tt` structs with `#[serde(with = "XXDef")]`
7//! for separation of code responsibility. 7//! for separation of code responsibility.
8 8
9use ra_tt::{ 9use ra_tt::{
@@ -34,15 +34,15 @@ pub struct ListMacrosResult {
34pub struct ExpansionTask { 34pub struct ExpansionTask {
35 /// Argument of macro call. 35 /// Argument of macro call.
36 /// 36 ///
37 /// In custom derive that would be a struct or enum; in attribute-like macro - underlying 37 /// In custom derive this will be a struct or enum; in attribute-like macro - underlying
38 /// item; in function-like macro - the macro body. 38 /// item; in function-like macro - the macro body.
39 #[serde(with = "SubtreeDef")] 39 #[serde(with = "SubtreeDef")]
40 pub macro_body: Subtree, 40 pub macro_body: Subtree,
41 41
42 /// Names of macros to expand. 42 /// Name of macro to expand.
43 /// 43 ///
44 /// In custom derive those are names of derived traits (`Serialize`, `Getters`, etc.). In 44 /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.).
45 /// attribute-like and functiona-like macros - single name of macro itself (`show_streams`). 45 /// In attribute-like and function-like macros - single name of macro itself (`show_streams`).
46 pub macro_name: String, 46 pub macro_name: String,
47 47
48 /// Possible attributes for the attribute-like macros. 48 /// Possible attributes for the attribute-like macros.