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 pub const NO_VERSION_CHECK_VERSION
: u32 = 0;
16 pub const CURRENT_API_VERSION
: u32 = 1;
18 #[derive(Debug, Serialize, Deserialize)]
20 ListMacros { dylib_path: PathBuf }
,
21 ExpandMacro(ExpandMacro
),
25 #[derive(Debug, Serialize, Deserialize)]
27 ListMacros(Result
<Vec
<(String
, ProcMacroKind
)>, String
>),
28 ExpandMacro(Result
<FlatTree
, PanicMessage
>),
32 #[derive(Debug, Serialize, Deserialize)]
33 pub struct PanicMessage(pub String
);
35 #[derive(Debug, Serialize, Deserialize)]
36 pub struct ExpandMacro
{
37 /// Argument of macro call.
39 /// In custom derive this will be a struct or enum; in attribute-like macro - underlying
40 /// item; in function-like macro - the macro body.
41 pub macro_body
: FlatTree
,
43 /// Name of macro to expand.
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
,
49 /// Possible attributes for the attribute-like macros.
50 pub attributes
: Option
<FlatTree
>,
54 /// Environment variables to set during macro expansion.
55 pub env
: Vec
<(String
, String
)>,
57 pub current_dir
: Option
<String
>,
60 pub trait Message
: Serialize
+ DeserializeOwned
{
61 fn read(inp
: &mut impl BufRead
, buf
: &mut String
) -> io
::Result
<Option
<Self>> {
62 Ok(match read_json(inp
, buf
)?
{
65 let mut deserializer
= serde_json
::Deserializer
::from_str(text
);
66 // Note that some proc-macro generate very deep syntax tree
67 // We have to disable the current limit of serde here
68 deserializer
.disable_recursion_limit();
69 Some(Self::deserialize(&mut deserializer
)?
)
73 fn write(self, out
: &mut impl Write
) -> io
::Result
<()> {
74 let text
= serde_json
::to_string(&self)?
;
75 write_json(out
, &text
)
79 impl Message
for Request {}
80 impl Message
for Response {}
82 fn read_json
<'a
>(inp
: &mut impl BufRead
, buf
: &'a
mut String
) -> io
::Result
<Option
<&'a String
>> {
87 buf
.pop(); // Remove trailing '\n'
93 // Some ill behaved macro try to use stdout for debugging
95 if !buf
.starts_with('
{'
) {
96 tracing
::error
!("proc-macro tried to print : {}", buf
);
100 return Ok(Some(buf
));
104 fn write_json(out
: &mut impl Write
, msg
: &str) -> io
::Result
<()> {
105 tracing
::debug
!("> {}", msg
);
106 out
.write_all(msg
.as_bytes())?
;
107 out
.write_all(b
"\n")?
;
117 fn fixture_token_tree() -> Subtree
{
118 let mut subtree
= Subtree { delimiter: Delimiter::unspecified(), token_trees: Vec::new() }
;
121 .push(TokenTree
::Leaf(Ident { text: "struct".into(), span: TokenId(0) }
.into()));
124 .push(TokenTree
::Leaf(Ident { text: "Foo".into(), span: TokenId(1) }
.into()));
125 subtree
.token_trees
.push(TokenTree
::Leaf(Leaf
::Literal(Literal
{
127 span
: TokenId
::unspecified(),
129 subtree
.token_trees
.push(TokenTree
::Leaf(Leaf
::Punct(Punct
{
131 span
: TokenId
::unspecified(),
132 spacing
: Spacing
::Joint
,
134 subtree
.token_trees
.push(TokenTree
::Subtree(Subtree
{
135 delimiter
: Delimiter
{
137 close
: TokenId
::UNSPECIFIED
,
138 kind
: DelimiterKind
::Brace
,
146 fn test_proc_macro_rpc_works() {
147 let tt
= fixture_token_tree();
148 let task
= ExpandMacro
{
149 macro_body
: FlatTree
::new(&tt
),
150 macro_name
: Default
::default(),
152 lib
: std
::env
::current_dir().unwrap(),
153 env
: Default
::default(),
154 current_dir
: Default
::default(),
157 let json
= serde_json
::to_string(&task
).unwrap();
158 // println!("{}", json);
159 let back
: ExpandMacro
= serde_json
::from_str(&json
).unwrap();
161 assert_eq
!(tt
, back
.macro_body
.to_subtree());