1 //! Defines messages for cross-process message passing based on `ndjson` wire protocol
5 io::{self, BufRead, Write},
9 use serde::{de::DeserializeOwned, Deserialize, Serialize};
11 use crate::ProcMacroKind;
13 pub use crate::msg::flat::FlatTree;
15 #[derive(Debug, Serialize, Deserialize)]
17 ListMacros { dylib_path: PathBuf },
18 ExpandMacro(ExpandMacro),
21 #[derive(Debug, Serialize, Deserialize)]
23 ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),
24 ExpandMacro(Result<FlatTree, PanicMessage>),
27 #[derive(Debug, Serialize, Deserialize)]
28 pub struct PanicMessage(pub String);
30 #[derive(Debug, Serialize, Deserialize)]
31 pub struct ExpandMacro {
32 /// Argument of macro call.
34 /// In custom derive this will be a struct or enum; in attribute-like macro - underlying
35 /// item; in function-like macro - the macro body.
36 pub macro_body: FlatTree,
38 /// Name of macro to expand.
40 /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.).
41 /// In attribute-like and function-like macros - single name of macro itself (`show_streams`).
42 pub macro_name: String,
44 /// Possible attributes for the attribute-like macros.
45 pub attributes: Option<FlatTree>,
49 /// Environment variables to set during macro expansion.
50 pub env: Vec<(String, String)>,
52 pub current_dir: Option<String>,
55 pub trait Message: Serialize + DeserializeOwned {
56 fn read(inp: &mut impl BufRead, buf: &mut String) -> io::Result<Option<Self>> {
57 Ok(match read_json(inp, buf)? {
60 let mut deserializer = serde_json::Deserializer::from_str(text);
61 // Note that some proc-macro generate very deep syntax tree
62 // We have to disable the current limit of serde here
63 deserializer.disable_recursion_limit();
64 Some(Self::deserialize(&mut deserializer)?)
68 fn write(self, out: &mut impl Write) -> io::Result<()> {
69 let text = serde_json::to_string(&self)?;
70 write_json(out, &text)
74 impl Message for Request {}
75 impl Message for Response {}
77 fn read_json<'a>(inp: &mut impl BufRead, buf: &'a mut String) -> io::Result<Option<&'a String>> {
82 buf.pop(); // Remove trailing '\n'
88 // Some ill behaved macro try to use stdout for debugging
90 if !buf.starts_with('{') {
91 tracing::error!("proc-macro tried to print : {}", buf);
99 fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
100 tracing::debug!("> {}", msg);
101 out.write_all(msg.as_bytes())?;
102 out.write_all(b"\n")?;
112 fn fixture_token_tree() -> Subtree {
113 let mut subtree = Subtree::default();
116 .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
119 .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
120 subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
122 id: TokenId::unspecified(),
124 subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
126 id: TokenId::unspecified(),
127 spacing: Spacing::Joint,
129 subtree.token_trees.push(TokenTree::Subtree(Subtree {
130 delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
137 fn test_proc_macro_rpc_works() {
138 let tt = fixture_token_tree();
139 let task = ExpandMacro {
140 macro_body: FlatTree::new(&tt),
141 macro_name: Default::default(),
143 lib: std::env::current_dir().unwrap(),
144 env: Default::default(),
145 current_dir: Default::default(),
148 let json = serde_json::to_string(&task).unwrap();
149 // println!("{}", json);
150 let back: ExpandMacro = serde_json::from_str(&json).unwrap();
152 assert_eq!(tt, back.macro_body.to_subtree());