diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-31 15:30:24 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-31 15:30:24 +0100 |
commit | 7a546490ecb93b9da1cd888086f00a69ebd8d0aa (patch) | |
tree | 18c25777f7f0fad8f60f58bf7187db45fe3307fd /crates/ra_proc_macro/src/msg.rs | |
parent | fa3c7742af9fbfe5146f4158a6119fa727dcc87a (diff) | |
parent | 207903a1c33961c2014010f5678b1c6807e7f6d6 (diff) |
Merge #3738
3738: Implement ra_proc_macro client logic r=matklad a=edwin0cheng
This PR add the actual client logic for `ra_proc_macro` crate:
1. Define all necessary rpc serialization data structure, which include `ra_tt` related data and some task messages. Although adding `Serialize` and `Deserialize` trait to ra_tt directly seem to be much easier, we deliberately duplicate the `ra_tt` struct with `#[serde(with = "XXDef")]` for separation of code responsibility.
2. Define a simplified version of lsp base protocol for rpc, which basically copy from lsp-server code base.
3. Implement the actual `IO` for the client side progress spawning and message passing.
Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates/ra_proc_macro/src/msg.rs')
-rw-r--r-- | crates/ra_proc_macro/src/msg.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/crates/ra_proc_macro/src/msg.rs b/crates/ra_proc_macro/src/msg.rs new file mode 100644 index 000000000..aa95bcc8f --- /dev/null +++ b/crates/ra_proc_macro/src/msg.rs | |||
@@ -0,0 +1,93 @@ | |||
1 | //! Defines messages for cross-process message based on `ndjson` wire protocol | ||
2 | |||
3 | use std::{ | ||
4 | convert::TryFrom, | ||
5 | io::{self, BufRead, Write}, | ||
6 | }; | ||
7 | |||
8 | use crate::{ | ||
9 | rpc::{ListMacrosResult, ListMacrosTask}, | ||
10 | ExpansionResult, ExpansionTask, | ||
11 | }; | ||
12 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; | ||
13 | |||
14 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
15 | pub enum Request { | ||
16 | ListMacro(ListMacrosTask), | ||
17 | ExpansionMacro(ExpansionTask), | ||
18 | } | ||
19 | |||
20 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
21 | pub enum Response { | ||
22 | Error(ResponseError), | ||
23 | ListMacro(ListMacrosResult), | ||
24 | ExpansionMacro(ExpansionResult), | ||
25 | } | ||
26 | |||
27 | macro_rules! impl_try_from_response { | ||
28 | ($ty:ty, $tag:ident) => { | ||
29 | impl TryFrom<Response> for $ty { | ||
30 | type Error = &'static str; | ||
31 | fn try_from(value: Response) -> Result<Self, Self::Error> { | ||
32 | match value { | ||
33 | Response::$tag(res) => Ok(res), | ||
34 | _ => Err("Fail to convert from response"), | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | }; | ||
39 | } | ||
40 | |||
41 | impl_try_from_response!(ListMacrosResult, ListMacro); | ||
42 | impl_try_from_response!(ExpansionResult, ExpansionMacro); | ||
43 | |||
44 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
45 | pub struct ResponseError { | ||
46 | pub code: ErrorCode, | ||
47 | pub message: String, | ||
48 | } | ||
49 | |||
50 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
51 | pub enum ErrorCode { | ||
52 | ServerErrorEnd, | ||
53 | ExpansionError, | ||
54 | } | ||
55 | |||
56 | pub trait Message: Sized + Serialize + DeserializeOwned { | ||
57 | fn read(r: &mut impl BufRead) -> io::Result<Option<Self>> { | ||
58 | let text = match read_json(r)? { | ||
59 | None => return Ok(None), | ||
60 | Some(text) => text, | ||
61 | }; | ||
62 | let msg = serde_json::from_str(&text)?; | ||
63 | Ok(Some(msg)) | ||
64 | } | ||
65 | fn write(self, w: &mut impl Write) -> io::Result<()> { | ||
66 | let text = serde_json::to_string(&self)?; | ||
67 | write_json(w, &text) | ||
68 | } | ||
69 | } | ||
70 | |||
71 | impl Message for Request {} | ||
72 | impl Message for Response {} | ||
73 | |||
74 | fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> { | ||
75 | let mut buf = String::new(); | ||
76 | if inp.read_line(&mut buf)? == 0 { | ||
77 | return Ok(None); | ||
78 | } | ||
79 | // Remove ending '\n' | ||
80 | let buf = &buf[..buf.len() - 1]; | ||
81 | if buf.is_empty() { | ||
82 | return Ok(None); | ||
83 | } | ||
84 | Ok(Some(buf.to_string())) | ||
85 | } | ||
86 | |||
87 | fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { | ||
88 | log::debug!("> {}", msg); | ||
89 | out.write_all(msg.as_bytes())?; | ||
90 | out.write_all(b"\n")?; | ||
91 | out.flush()?; | ||
92 | Ok(()) | ||
93 | } | ||