diff options
Diffstat (limited to 'crates/proc_macro_api/src/rpc.rs')
-rw-r--r-- | crates/proc_macro_api/src/rpc.rs | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/crates/proc_macro_api/src/rpc.rs b/crates/proc_macro_api/src/rpc.rs new file mode 100644 index 000000000..47624163e --- /dev/null +++ b/crates/proc_macro_api/src/rpc.rs | |||
@@ -0,0 +1,267 @@ | |||
1 | //! Data structure serialization related stuff for RPC | ||
2 | //! | ||
3 | //! Defines all necessary rpc serialization data structures, | ||
4 | //! which includes `tt` related data and some task messages. | ||
5 | //! Although adding `Serialize` and `Deserialize` traits to `tt` directly seems | ||
6 | //! to be much easier, we deliberately duplicate `tt` structs with `#[serde(with = "XXDef")]` | ||
7 | //! for separation of code responsibility. | ||
8 | |||
9 | use std::path::PathBuf; | ||
10 | |||
11 | use serde::{Deserialize, Serialize}; | ||
12 | use tt::{ | ||
13 | Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId, | ||
14 | TokenTree, | ||
15 | }; | ||
16 | |||
17 | #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] | ||
18 | pub struct ListMacrosTask { | ||
19 | pub lib: PathBuf, | ||
20 | } | ||
21 | |||
22 | #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] | ||
23 | pub enum ProcMacroKind { | ||
24 | CustomDerive, | ||
25 | FuncLike, | ||
26 | Attr, | ||
27 | } | ||
28 | |||
29 | #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] | ||
30 | pub struct ListMacrosResult { | ||
31 | pub macros: Vec<(String, ProcMacroKind)>, | ||
32 | } | ||
33 | |||
34 | #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] | ||
35 | pub struct ExpansionTask { | ||
36 | /// Argument of macro call. | ||
37 | /// | ||
38 | /// In custom derive this will be a struct or enum; in attribute-like macro - underlying | ||
39 | /// item; in function-like macro - the macro body. | ||
40 | #[serde(with = "SubtreeDef")] | ||
41 | pub macro_body: Subtree, | ||
42 | |||
43 | /// Name of macro to expand. | ||
44 | /// | ||
45 | /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.). | ||
46 | /// In attribute-like and function-like macros - single name of macro itself (`show_streams`). | ||
47 | pub macro_name: String, | ||
48 | |||
49 | /// Possible attributes for the attribute-like macros. | ||
50 | #[serde(with = "opt_subtree_def")] | ||
51 | pub attributes: Option<Subtree>, | ||
52 | |||
53 | pub lib: PathBuf, | ||
54 | } | ||
55 | |||
56 | #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] | ||
57 | pub struct ExpansionResult { | ||
58 | #[serde(with = "SubtreeDef")] | ||
59 | pub expansion: Subtree, | ||
60 | } | ||
61 | |||
62 | #[derive(Serialize, Deserialize)] | ||
63 | #[serde(remote = "DelimiterKind")] | ||
64 | enum DelimiterKindDef { | ||
65 | Parenthesis, | ||
66 | Brace, | ||
67 | Bracket, | ||
68 | } | ||
69 | |||
70 | #[derive(Serialize, Deserialize)] | ||
71 | #[serde(remote = "TokenId")] | ||
72 | struct TokenIdDef(u32); | ||
73 | |||
74 | #[derive(Serialize, Deserialize)] | ||
75 | #[serde(remote = "Delimiter")] | ||
76 | struct DelimiterDef { | ||
77 | #[serde(with = "TokenIdDef")] | ||
78 | pub id: TokenId, | ||
79 | #[serde(with = "DelimiterKindDef")] | ||
80 | pub kind: DelimiterKind, | ||
81 | } | ||
82 | |||
83 | #[derive(Serialize, Deserialize)] | ||
84 | #[serde(remote = "Subtree")] | ||
85 | struct SubtreeDef { | ||
86 | #[serde(default, with = "opt_delimiter_def")] | ||
87 | pub delimiter: Option<Delimiter>, | ||
88 | #[serde(with = "vec_token_tree")] | ||
89 | pub token_trees: Vec<TokenTree>, | ||
90 | } | ||
91 | |||
92 | #[derive(Serialize, Deserialize)] | ||
93 | #[serde(remote = "TokenTree")] | ||
94 | enum TokenTreeDef { | ||
95 | #[serde(with = "LeafDef")] | ||
96 | Leaf(Leaf), | ||
97 | #[serde(with = "SubtreeDef")] | ||
98 | Subtree(Subtree), | ||
99 | } | ||
100 | |||
101 | #[derive(Serialize, Deserialize)] | ||
102 | #[serde(remote = "Leaf")] | ||
103 | enum LeafDef { | ||
104 | #[serde(with = "LiteralDef")] | ||
105 | Literal(Literal), | ||
106 | #[serde(with = "PunctDef")] | ||
107 | Punct(Punct), | ||
108 | #[serde(with = "IdentDef")] | ||
109 | Ident(Ident), | ||
110 | } | ||
111 | |||
112 | #[derive(Serialize, Deserialize)] | ||
113 | #[serde(remote = "Literal")] | ||
114 | struct LiteralDef { | ||
115 | pub text: SmolStr, | ||
116 | #[serde(with = "TokenIdDef")] | ||
117 | pub id: TokenId, | ||
118 | } | ||
119 | |||
120 | #[derive(Serialize, Deserialize)] | ||
121 | #[serde(remote = "Punct")] | ||
122 | struct PunctDef { | ||
123 | pub char: char, | ||
124 | #[serde(with = "SpacingDef")] | ||
125 | pub spacing: Spacing, | ||
126 | #[serde(with = "TokenIdDef")] | ||
127 | pub id: TokenId, | ||
128 | } | ||
129 | |||
130 | #[derive(Serialize, Deserialize)] | ||
131 | #[serde(remote = "Spacing")] | ||
132 | enum SpacingDef { | ||
133 | Alone, | ||
134 | Joint, | ||
135 | } | ||
136 | |||
137 | #[derive(Serialize, Deserialize)] | ||
138 | #[serde(remote = "Ident")] | ||
139 | struct IdentDef { | ||
140 | pub text: SmolStr, | ||
141 | #[serde(with = "TokenIdDef")] | ||
142 | pub id: TokenId, | ||
143 | } | ||
144 | |||
145 | mod opt_delimiter_def { | ||
146 | use super::{Delimiter, DelimiterDef}; | ||
147 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||
148 | |||
149 | pub fn serialize<S>(value: &Option<Delimiter>, serializer: S) -> Result<S::Ok, S::Error> | ||
150 | where | ||
151 | S: Serializer, | ||
152 | { | ||
153 | #[derive(Serialize)] | ||
154 | struct Helper<'a>(#[serde(with = "DelimiterDef")] &'a Delimiter); | ||
155 | value.as_ref().map(Helper).serialize(serializer) | ||
156 | } | ||
157 | |||
158 | pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Delimiter>, D::Error> | ||
159 | where | ||
160 | D: Deserializer<'de>, | ||
161 | { | ||
162 | #[derive(Deserialize)] | ||
163 | struct Helper(#[serde(with = "DelimiterDef")] Delimiter); | ||
164 | let helper = Option::deserialize(deserializer)?; | ||
165 | Ok(helper.map(|Helper(external)| external)) | ||
166 | } | ||
167 | } | ||
168 | |||
169 | mod opt_subtree_def { | ||
170 | use super::{Subtree, SubtreeDef}; | ||
171 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||
172 | |||
173 | pub fn serialize<S>(value: &Option<Subtree>, serializer: S) -> Result<S::Ok, S::Error> | ||
174 | where | ||
175 | S: Serializer, | ||
176 | { | ||
177 | #[derive(Serialize)] | ||
178 | struct Helper<'a>(#[serde(with = "SubtreeDef")] &'a Subtree); | ||
179 | value.as_ref().map(Helper).serialize(serializer) | ||
180 | } | ||
181 | |||
182 | pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Subtree>, D::Error> | ||
183 | where | ||
184 | D: Deserializer<'de>, | ||
185 | { | ||
186 | #[derive(Deserialize)] | ||
187 | struct Helper(#[serde(with = "SubtreeDef")] Subtree); | ||
188 | let helper = Option::deserialize(deserializer)?; | ||
189 | Ok(helper.map(|Helper(external)| external)) | ||
190 | } | ||
191 | } | ||
192 | |||
193 | mod vec_token_tree { | ||
194 | use super::{TokenTree, TokenTreeDef}; | ||
195 | use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; | ||
196 | |||
197 | pub fn serialize<S>(value: &Vec<TokenTree>, serializer: S) -> Result<S::Ok, S::Error> | ||
198 | where | ||
199 | S: Serializer, | ||
200 | { | ||
201 | #[derive(Serialize)] | ||
202 | struct Helper<'a>(#[serde(with = "TokenTreeDef")] &'a TokenTree); | ||
203 | |||
204 | let items: Vec<_> = value.iter().map(Helper).collect(); | ||
205 | let mut seq = serializer.serialize_seq(Some(items.len()))?; | ||
206 | for element in items { | ||
207 | seq.serialize_element(&element)?; | ||
208 | } | ||
209 | seq.end() | ||
210 | } | ||
211 | |||
212 | pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<TokenTree>, D::Error> | ||
213 | where | ||
214 | D: Deserializer<'de>, | ||
215 | { | ||
216 | #[derive(Deserialize)] | ||
217 | struct Helper(#[serde(with = "TokenTreeDef")] TokenTree); | ||
218 | |||
219 | let helper = Vec::deserialize(deserializer)?; | ||
220 | Ok(helper.into_iter().map(|Helper(external)| external).collect()) | ||
221 | } | ||
222 | } | ||
223 | |||
224 | #[cfg(test)] | ||
225 | mod tests { | ||
226 | use super::*; | ||
227 | |||
228 | fn fixture_token_tree() -> Subtree { | ||
229 | let mut subtree = Subtree::default(); | ||
230 | subtree | ||
231 | .token_trees | ||
232 | .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into())); | ||
233 | subtree | ||
234 | .token_trees | ||
235 | .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into())); | ||
236 | subtree.token_trees.push(TokenTree::Subtree( | ||
237 | Subtree { | ||
238 | delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }), | ||
239 | token_trees: vec![], | ||
240 | } | ||
241 | .into(), | ||
242 | )); | ||
243 | subtree | ||
244 | } | ||
245 | |||
246 | #[test] | ||
247 | fn test_proc_macro_rpc_works() { | ||
248 | let tt = fixture_token_tree(); | ||
249 | let task = ExpansionTask { | ||
250 | macro_body: tt.clone(), | ||
251 | macro_name: Default::default(), | ||
252 | attributes: None, | ||
253 | lib: Default::default(), | ||
254 | }; | ||
255 | |||
256 | let json = serde_json::to_string(&task).unwrap(); | ||
257 | let back: ExpansionTask = serde_json::from_str(&json).unwrap(); | ||
258 | |||
259 | assert_eq!(task.macro_body, back.macro_body); | ||
260 | |||
261 | let result = ExpansionResult { expansion: tt.clone() }; | ||
262 | let json = serde_json::to_string(&result).unwrap(); | ||
263 | let back: ExpansionResult = serde_json::from_str(&json).unwrap(); | ||
264 | |||
265 | assert_eq!(result, back); | ||
266 | } | ||
267 | } | ||