Skip to content

Commit 55e9476

Browse files
committed
internal: more production-ready proc-macro RPC deserialization
* avoid arbitrary nested JSON tree (danger of stack overflow) * use more compact representation.
1 parent 9ea3c4d commit 55e9476

File tree

6 files changed

+365
-214
lines changed

6 files changed

+365
-214
lines changed

crates/proc_macro_api/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use tt::{SmolStr, Subtree};
2121

2222
use crate::process::ProcMacroProcessSrv;
2323

24-
pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
24+
pub use rpc::{
25+
ExpansionResult, ExpansionTask, flat::FlatTree, ListMacrosResult, ListMacrosTask, ProcMacroKind,
26+
};
2527
pub use version::{read_dylib_info, RustCInfo};
2628

2729
#[derive(Debug, Clone)]
@@ -58,9 +60,9 @@ impl ProcMacroProcessExpander {
5860
env: Vec<(String, String)>,
5961
) -> Result<Subtree, tt::ExpansionError> {
6062
let task = ExpansionTask {
61-
macro_body: subtree.clone(),
63+
macro_body: FlatTree::new(subtree),
6264
macro_name: self.name.to_string(),
63-
attributes: attr.cloned(),
65+
attributes: attr.map(FlatTree::new),
6466
lib: self.dylib_path.to_path_buf(),
6567
env,
6668
};
@@ -70,7 +72,7 @@ impl ProcMacroProcessExpander {
7072
.lock()
7173
.unwrap_or_else(|e| e.into_inner())
7274
.send_task(msg::Request::ExpansionMacro(task))?;
73-
Ok(result.expansion)
75+
Ok(result.expansion.to_subtree())
7476
}
7577
}
7678

crates/proc_macro_api/src/msg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ use crate::{
1212
ExpansionResult, ExpansionTask,
1313
};
1414

15-
#[derive(Debug, Serialize, Deserialize, Clone)]
15+
#[derive(Debug, Serialize, Deserialize)]
1616
pub enum Request {
1717
ListMacro(ListMacrosTask),
1818
ExpansionMacro(ExpansionTask),
1919
}
2020

21-
#[derive(Debug, Serialize, Deserialize, Clone)]
21+
#[derive(Debug, Serialize, Deserialize)]
2222
pub enum Response {
2323
Error(ResponseError),
2424
ListMacro(ListMacrosResult),

crates/proc_macro_api/src/rpc.rs

Lines changed: 21 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
//! Although adding `Serialize` and `Deserialize` traits to `tt` directly seems
66
//! to be much easier, we deliberately duplicate `tt` structs with `#[serde(with = "XXDef")]`
77
//! for separation of code responsibility.
8+
pub(crate) mod flat;
89

910
use paths::AbsPathBuf;
1011
use serde::{Deserialize, Serialize};
11-
use tt::{
12-
Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId,
13-
TokenTree,
14-
};
12+
13+
use crate::rpc::flat::FlatTree;
1514

1615
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
1716
pub struct ListMacrosTask {
@@ -30,14 +29,13 @@ pub struct ListMacrosResult {
3029
pub macros: Vec<(String, ProcMacroKind)>,
3130
}
3231

33-
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
32+
#[derive(Debug, Serialize, Deserialize)]
3433
pub struct ExpansionTask {
3534
/// Argument of macro call.
3635
///
3736
/// In custom derive this will be a struct or enum; in attribute-like macro - underlying
3837
/// item; in function-like macro - the macro body.
39-
#[serde(with = "SubtreeDef")]
40-
pub macro_body: Subtree,
38+
pub macro_body: FlatTree,
4139

4240
/// Name of macro to expand.
4341
///
@@ -46,208 +44,23 @@ pub struct ExpansionTask {
4644
pub macro_name: String,
4745

4846
/// Possible attributes for the attribute-like macros.
49-
#[serde(with = "opt_subtree_def")]
50-
pub attributes: Option<Subtree>,
47+
pub attributes: Option<FlatTree>,
5148

5249
pub lib: AbsPathBuf,
5350

5451
/// Environment variables to set during macro expansion.
5552
pub env: Vec<(String, String)>,
5653
}
5754

58-
#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
55+
#[derive(Debug, Serialize, Deserialize)]
5956
pub struct ExpansionResult {
60-
#[serde(with = "SubtreeDef")]
61-
pub expansion: Subtree,
62-
}
63-
64-
#[derive(Serialize, Deserialize)]
65-
#[serde(remote = "DelimiterKind")]
66-
enum DelimiterKindDef {
67-
Parenthesis,
68-
Brace,
69-
Bracket,
70-
}
71-
72-
#[derive(Serialize, Deserialize)]
73-
#[serde(remote = "TokenId")]
74-
struct TokenIdDef(u32);
75-
76-
#[derive(Serialize, Deserialize)]
77-
#[serde(remote = "Delimiter")]
78-
struct DelimiterDef {
79-
#[serde(
80-
with = "TokenIdDef",
81-
default = "tt::TokenId::unspecified",
82-
skip_serializing_if = "token_id_def::skip_if"
83-
)]
84-
id: TokenId,
85-
#[serde(with = "DelimiterKindDef")]
86-
kind: DelimiterKind,
87-
}
88-
89-
#[derive(Serialize, Deserialize)]
90-
#[serde(remote = "Subtree")]
91-
struct SubtreeDef {
92-
#[serde(default, with = "opt_delimiter_def")]
93-
delimiter: Option<Delimiter>,
94-
#[serde(with = "vec_token_tree")]
95-
token_trees: Vec<TokenTree>,
96-
}
97-
98-
#[derive(Serialize, Deserialize)]
99-
#[serde(remote = "TokenTree")]
100-
enum TokenTreeDef {
101-
#[serde(with = "LeafDef")]
102-
Leaf(Leaf),
103-
#[serde(with = "SubtreeDef")]
104-
Subtree(Subtree),
105-
}
106-
107-
#[derive(Serialize, Deserialize)]
108-
#[serde(remote = "Leaf")]
109-
enum LeafDef {
110-
#[serde(with = "LiteralDef")]
111-
Literal(Literal),
112-
#[serde(with = "PunctDef")]
113-
Punct(Punct),
114-
#[serde(with = "IdentDef")]
115-
Ident(Ident),
116-
}
117-
118-
#[derive(Serialize, Deserialize)]
119-
#[serde(remote = "Literal")]
120-
struct LiteralDef {
121-
text: SmolStr,
122-
#[serde(
123-
with = "TokenIdDef",
124-
default = "tt::TokenId::unspecified",
125-
skip_serializing_if = "token_id_def::skip_if"
126-
)]
127-
id: TokenId,
128-
}
129-
130-
#[derive(Serialize, Deserialize)]
131-
#[serde(remote = "Punct")]
132-
struct PunctDef {
133-
char: char,
134-
#[serde(with = "SpacingDef")]
135-
spacing: Spacing,
136-
#[serde(
137-
with = "TokenIdDef",
138-
default = "tt::TokenId::unspecified",
139-
skip_serializing_if = "token_id_def::skip_if"
140-
)]
141-
id: TokenId,
142-
}
143-
144-
#[derive(Serialize, Deserialize)]
145-
#[serde(remote = "Spacing")]
146-
enum SpacingDef {
147-
Alone,
148-
Joint,
149-
}
150-
151-
#[derive(Serialize, Deserialize)]
152-
#[serde(remote = "Ident")]
153-
struct IdentDef {
154-
text: SmolStr,
155-
#[serde(
156-
with = "TokenIdDef",
157-
default = "tt::TokenId::unspecified",
158-
skip_serializing_if = "token_id_def::skip_if"
159-
)]
160-
id: TokenId,
161-
}
162-
163-
mod token_id_def {
164-
pub(super) fn skip_if(value: &tt::TokenId) -> bool {
165-
*value == tt::TokenId::unspecified()
166-
}
167-
}
168-
169-
mod opt_delimiter_def {
170-
use super::{Delimiter, DelimiterDef};
171-
use serde::{Deserialize, Deserializer, Serialize, Serializer};
172-
173-
pub(super) fn serialize<S>(value: &Option<Delimiter>, serializer: S) -> Result<S::Ok, S::Error>
174-
where
175-
S: Serializer,
176-
{
177-
#[derive(Serialize)]
178-
struct Helper<'a>(#[serde(with = "DelimiterDef")] &'a Delimiter);
179-
value.as_ref().map(Helper).serialize(serializer)
180-
}
181-
182-
pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Option<Delimiter>, D::Error>
183-
where
184-
D: Deserializer<'de>,
185-
{
186-
#[derive(Deserialize)]
187-
struct Helper(#[serde(with = "DelimiterDef")] Delimiter);
188-
let helper = Option::deserialize(deserializer)?;
189-
Ok(helper.map(|Helper(external)| external))
190-
}
191-
}
192-
193-
mod opt_subtree_def {
194-
use super::{Subtree, SubtreeDef};
195-
use serde::{Deserialize, Deserializer, Serialize, Serializer};
196-
197-
pub(super) fn serialize<S>(value: &Option<Subtree>, serializer: S) -> Result<S::Ok, S::Error>
198-
where
199-
S: Serializer,
200-
{
201-
#[derive(Serialize)]
202-
struct Helper<'a>(#[serde(with = "SubtreeDef")] &'a Subtree);
203-
value.as_ref().map(Helper).serialize(serializer)
204-
}
205-
206-
pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Option<Subtree>, D::Error>
207-
where
208-
D: Deserializer<'de>,
209-
{
210-
#[derive(Deserialize)]
211-
struct Helper(#[serde(with = "SubtreeDef")] Subtree);
212-
let helper = Option::deserialize(deserializer)?;
213-
Ok(helper.map(|Helper(external)| external))
214-
}
215-
}
216-
217-
mod vec_token_tree {
218-
use super::{TokenTree, TokenTreeDef};
219-
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
220-
221-
pub(super) fn serialize<S>(value: &[TokenTree], serializer: S) -> Result<S::Ok, S::Error>
222-
where
223-
S: Serializer,
224-
{
225-
#[derive(Serialize)]
226-
struct Helper<'a>(#[serde(with = "TokenTreeDef")] &'a TokenTree);
227-
228-
let items: Vec<_> = value.iter().map(Helper).collect();
229-
let mut seq = serializer.serialize_seq(Some(items.len()))?;
230-
for element in items {
231-
seq.serialize_element(&element)?;
232-
}
233-
seq.end()
234-
}
235-
236-
pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Vec<TokenTree>, D::Error>
237-
where
238-
D: Deserializer<'de>,
239-
{
240-
#[derive(Deserialize)]
241-
struct Helper(#[serde(with = "TokenTreeDef")] TokenTree);
242-
243-
let helper = Vec::deserialize(deserializer)?;
244-
Ok(helper.into_iter().map(|Helper(external)| external).collect())
245-
}
57+
pub expansion: FlatTree,
24658
}
24759

24860
#[cfg(test)]
24961
mod tests {
25062
use super::*;
63+
use tt::*;
25164

25265
fn fixture_token_tree() -> Subtree {
25366
let mut subtree = Subtree::default();
@@ -257,6 +70,15 @@ mod tests {
25770
subtree
25871
.token_trees
25972
.push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
73+
subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
74+
text: "Foo".into(),
75+
id: TokenId::unspecified(),
76+
})));
77+
subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
78+
char: '@',
79+
id: TokenId::unspecified(),
80+
spacing: Spacing::Joint,
81+
})));
26082
subtree.token_trees.push(TokenTree::Subtree(Subtree {
26183
delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
26284
token_trees: vec![],
@@ -268,22 +90,17 @@ mod tests {
26890
fn test_proc_macro_rpc_works() {
26991
let tt = fixture_token_tree();
27092
let task = ExpansionTask {
271-
macro_body: tt.clone(),
93+
macro_body: FlatTree::new(&tt),
27294
macro_name: Default::default(),
27395
attributes: None,
27496
lib: AbsPathBuf::assert(std::env::current_dir().unwrap()),
27597
env: Default::default(),
27698
};
27799

278100
let json = serde_json::to_string(&task).unwrap();
101+
println!("{}", json);
279102
let back: ExpansionTask = serde_json::from_str(&json).unwrap();
280103

281-
assert_eq!(task.macro_body, back.macro_body);
282-
283-
let result = ExpansionResult { expansion: tt };
284-
let json = serde_json::to_string(&result).unwrap();
285-
let back: ExpansionResult = serde_json::from_str(&json).unwrap();
286-
287-
assert_eq!(result, back);
104+
assert_eq!(tt, back.macro_body.to_subtree());
288105
}
289106
}

0 commit comments

Comments
 (0)