diff options
author | Benjamin Coenen <[email protected]> | 2020-04-21 13:32:02 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-04-21 13:32:02 +0100 |
commit | 7f143b154e7c47b1f5bdc558bb0b5d1f2bf74f8d (patch) | |
tree | 571b7d5bdfc84bdaeaa8235221fd96a87453fe05 /crates/ra_proc_macro | |
parent | 1c3a1385a587f0713908c0ae888ffad31f13de11 (diff) | |
parent | a88887df0726cc3d390db4bfbbc1274195d87f91 (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.rs | 17 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/msg.rs | 37 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/process.rs | 118 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/rpc.rs | 18 |
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 | ||
8 | mod rpc; | 8 | mod rpc; |
@@ -13,6 +13,7 @@ use process::{ProcMacroProcessSrv, ProcMacroProcessThread}; | |||
13 | use ra_tt::{SmolStr, Subtree}; | 13 | use ra_tt::{SmolStr, Subtree}; |
14 | use std::{ | 14 | use 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 | ||
59 | impl ProcMacroClient { | 60 | impl 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 | ||
3 | use std::{ | 3 | use 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 | ||
56 | pub trait Message: Sized + Serialize + DeserializeOwned { | 56 | pub 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 | ||
74 | fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> { | 72 | fn 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 | ||
87 | fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { | 82 | fn 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 | |||
9 | use io::{BufRead, BufReader}; | 9 | use io::{BufRead, BufReader}; |
10 | use std::{ | 10 | use 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 | ||
31 | struct Task { | ||
32 | req: Request, | ||
33 | result_tx: Sender<Option<Response>>, | ||
34 | } | ||
35 | |||
36 | struct Process { | ||
37 | path: PathBuf, | ||
38 | child: Child, | ||
39 | } | ||
40 | |||
41 | impl Drop for Process { | ||
42 | fn drop(&mut self) { | ||
43 | let _ = self.child.kill(); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | impl 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 | |||
82 | impl ProcMacroProcessSrv { | 31 | impl 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 | ||
145 | struct Task { | ||
146 | req: Request, | ||
147 | result_tx: Sender<Option<Response>>, | ||
148 | } | ||
149 | |||
150 | struct Process { | ||
151 | path: PathBuf, | ||
152 | args: Vec<OsString>, | ||
153 | child: Child, | ||
154 | } | ||
155 | |||
156 | impl Drop for Process { | ||
157 | fn drop(&mut self) { | ||
158 | let _ = self.child.kill(); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | impl 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 | |||
187 | fn 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 | |||
200 | fn send_request( | 196 | fn 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 | ||
9 | use ra_tt::{ | 9 | use ra_tt::{ |
@@ -34,15 +34,15 @@ pub struct ListMacrosResult { | |||
34 | pub struct ExpansionTask { | 34 | pub 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. |