1pub(crate) mod flat;
3pub use self::flat::*;
4
5use std::io::{self, BufRead, Write};
6
7use paths::Utf8PathBuf;
8use serde::de::DeserializeOwned;
9use serde_derive::{Deserialize, Serialize};
10
11use crate::ProcMacroKind;
12
13#[derive(Debug, Serialize, Deserialize)]
15pub enum Request {
16 ListMacros { dylib_path: Utf8PathBuf },
19
20 ExpandMacro(Box<ExpandMacro>),
23
24 ApiVersionCheck {},
27
28 SetConfig(ServerConfig),
31}
32
33#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)]
35pub enum SpanMode {
36 #[default]
38 Id,
39
40 RustAnalyzer,
42}
43
44#[derive(Debug, Serialize, Deserialize)]
46pub enum Response {
47 ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),
50
51 ExpandMacro(Result<FlatTree, PanicMessage>),
54
55 ApiVersionCheck(u32),
58
59 SetConfig(ServerConfig),
62
63 ExpandMacroExtended(Result<ExpandMacroExtended, PanicMessage>),
66}
67
68#[derive(Debug, Serialize, Deserialize, Default)]
70#[serde(default)]
71pub struct ServerConfig {
72 pub span_mode: SpanMode,
74}
75
76#[derive(Debug, Serialize, Deserialize)]
78pub struct ExpandMacroExtended {
79 pub tree: FlatTree,
81 pub span_data_table: Vec<u32>,
83}
84
85#[derive(Debug, Serialize, Deserialize)]
87pub struct PanicMessage(pub String);
88
89#[derive(Debug, Serialize, Deserialize)]
91pub struct ExpandMacro {
92 pub lib: Utf8PathBuf,
94 pub env: Vec<(String, String)>,
96 pub current_dir: Option<String>,
98 #[serde(flatten)]
100 pub data: ExpandMacroData,
101}
102
103#[derive(Debug, Serialize, Deserialize)]
105pub struct ExpandMacroData {
106 pub macro_body: FlatTree,
111
112 pub macro_name: String,
117
118 pub attributes: Option<FlatTree>,
120 #[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")]
122 #[serde(default)]
123 pub has_global_spans: ExpnGlobals,
124 #[serde(skip_serializing_if = "Vec::is_empty")]
126 #[serde(default)]
127 pub span_data_table: Vec<u32>,
128}
129
130#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
132pub struct ExpnGlobals {
133 #[serde(skip_serializing)]
135 #[serde(default)]
136 pub serialize: bool,
137 pub def_site: usize,
139 pub call_site: usize,
141 pub mixed_site: usize,
143}
144
145impl ExpnGlobals {
146 fn skip_serializing_if(&self) -> bool {
147 !self.serialize
148 }
149}
150
151pub trait Message: serde::Serialize + DeserializeOwned {
152 fn read<R: BufRead>(
153 from_proto: ProtocolRead<R>,
154 inp: &mut R,
155 buf: &mut String,
156 ) -> io::Result<Option<Self>> {
157 Ok(match from_proto(inp, buf)? {
158 None => None,
159 Some(text) => {
160 let mut deserializer = serde_json::Deserializer::from_str(text);
161 deserializer.disable_recursion_limit();
164 Some(Self::deserialize(&mut deserializer)?)
165 }
166 })
167 }
168 fn write<W: Write>(self, to_proto: ProtocolWrite<W>, out: &mut W) -> io::Result<()> {
169 let text = serde_json::to_string(&self)?;
170 to_proto(out, &text)
171 }
172}
173
174impl Message for Request {}
175impl Message for Response {}
176
177#[allow(type_alias_bounds)]
179type ProtocolRead<R: BufRead> =
180 for<'i, 'buf> fn(inp: &'i mut R, buf: &'buf mut String) -> io::Result<Option<&'buf String>>;
181#[allow(type_alias_bounds)]
183type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) -> io::Result<()>;
184
185#[cfg(test)]
186mod tests {
187 use intern::{Symbol, sym};
188 use span::{
189 Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize,
190 };
191 use tt::{
192 Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree,
193 TopSubtreeBuilder,
194 };
195
196 use crate::version;
197
198 use super::*;
199
200 fn fixture_token_tree() -> TopSubtree<Span> {
201 let anchor = SpanAnchor {
202 file_id: span::EditionedFileId::new(
203 span::FileId::from_raw(0xe4e4e),
204 span::Edition::CURRENT,
205 ),
206 ast_id: ROOT_ERASED_FILE_AST_ID,
207 };
208
209 let mut builder = TopSubtreeBuilder::new(Delimiter {
210 open: Span {
211 range: TextRange::empty(TextSize::new(0)),
212 anchor,
213 ctx: SyntaxContext::root(Edition::CURRENT),
214 },
215 close: Span {
216 range: TextRange::empty(TextSize::new(19)),
217 anchor,
218 ctx: SyntaxContext::root(Edition::CURRENT),
219 },
220 kind: DelimiterKind::Invisible,
221 });
222
223 builder.push(
224 Ident {
225 sym: Symbol::intern("struct"),
226 span: Span {
227 range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
228 anchor,
229 ctx: SyntaxContext::root(Edition::CURRENT),
230 },
231 is_raw: tt::IdentIsRaw::No,
232 }
233 .into(),
234 );
235 builder.push(
236 Ident {
237 sym: Symbol::intern("Foo"),
238 span: Span {
239 range: TextRange::at(TextSize::new(5), TextSize::of("r#Foo")),
240 anchor,
241 ctx: SyntaxContext::root(Edition::CURRENT),
242 },
243 is_raw: tt::IdentIsRaw::Yes,
244 }
245 .into(),
246 );
247 builder.push(Leaf::Literal(Literal {
248 symbol: Symbol::intern("Foo"),
249 span: Span {
250 range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")),
251 anchor,
252 ctx: SyntaxContext::root(Edition::CURRENT),
253 },
254 kind: tt::LitKind::Str,
255 suffix: None,
256 }));
257 builder.push(Leaf::Punct(Punct {
258 char: '@',
259 span: Span {
260 range: TextRange::at(TextSize::new(13), TextSize::of('@')),
261 anchor,
262 ctx: SyntaxContext::root(Edition::CURRENT),
263 },
264 spacing: Spacing::Joint,
265 }));
266 builder.open(
267 DelimiterKind::Brace,
268 Span {
269 range: TextRange::at(TextSize::new(14), TextSize::of('{')),
270 anchor,
271 ctx: SyntaxContext::root(Edition::CURRENT),
272 },
273 );
274 builder.push(Leaf::Literal(Literal {
275 symbol: sym::INTEGER_0,
276 span: Span {
277 range: TextRange::at(TextSize::new(15), TextSize::of("0u32")),
278 anchor,
279 ctx: SyntaxContext::root(Edition::CURRENT),
280 },
281 kind: tt::LitKind::Integer,
282 suffix: Some(sym::u32),
283 }));
284 builder.close(Span {
285 range: TextRange::at(TextSize::new(19), TextSize::of('}')),
286 anchor,
287 ctx: SyntaxContext::root(Edition::CURRENT),
288 });
289
290 builder.build()
291 }
292
293 #[test]
294 fn test_proc_macro_rpc_works() {
295 let tt = fixture_token_tree();
296 for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
297 let mut span_data_table = Default::default();
298 let task = ExpandMacro {
299 data: ExpandMacroData {
300 macro_body: FlatTree::new(tt.view(), v, &mut span_data_table),
301 macro_name: Default::default(),
302 attributes: None,
303 has_global_spans: ExpnGlobals {
304 serialize: true,
305 def_site: 0,
306 call_site: 0,
307 mixed_site: 0,
308 },
309 span_data_table: Vec::new(),
310 },
311 lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(),
312 env: Default::default(),
313 current_dir: Default::default(),
314 };
315
316 let json = serde_json::to_string(&task).unwrap();
317 let back: ExpandMacro = serde_json::from_str(&json).unwrap();
319
320 assert!(
321 tt == back.data.macro_body.to_subtree_resolved(v, &span_data_table),
322 "version: {v}"
323 );
324 }
325 }
326}