Clean-up postprocessing to use less macro magic. · rust-lang/rust-bindgen@0798bda (original) (raw)
`@@ -4,145 +4,126 @@ use syn::Item;
`
4
4
``
5
5
`use crate::BindgenOptions;
`
6
6
``
7
``
`-
macro_rules! decl_postprocessing {
`
8
``
`-
($($ty:ty),*) => {
`
9
``
`-
pub(crate) fn postprocessing(
`
10
``
`-
items: Vec,
`
11
``
`-
options: &BindgenOptions,
`
12
``
`-
) -> TokenStream {
`
13
``
`` -
// Whether any of the enabled options requires syn
.
``
14
``
`-
let require_syn = (<(<(<ty as PostProcessing>::should_run(options))||*;
`
15
``
-
16
``
`-
if !require_syn {
`
17
``
`-
return items.into_iter().collect();
`
18
``
`-
}
`
19
``
-
20
``
`-
let module_wrapped_tokens =
`
21
``
`-
quote!(mod wrapper_for_sorting_hack { #( #items )* });
`
22
``
-
23
``
`-
// This syn business is a hack, for now. This means that we are re-parsing already
`
24
``
`` -
// generated code using syn
(as opposed to quote
) because syn
provides us more
``
25
``
`-
// control over the elements.
`
26
``
`` -
// One caveat is that some of the items coming from quote
d output might have
``
27
``
`` -
// multiple items within them. Hence, we have to wrap the incoming in a mod
.
``
28
``
`` -
// The two unwrap
s here are deliberate because
``
29
``
`` -
// The first one won't panic because we build the mod
and know it is there
``
30
``
`-
// The second one won't panic because we know original output has something in
`
31
``
`-
// it already.
`
32
``
`-
let mut items =
`
33
``
`-
syn::parse2::syn::ItemMod(module_wrapped_tokens)
`
34
``
`-
.unwrap()
`
35
``
`-
.content
`
36
``
`-
.unwrap()
`
37
``
`-
.1;
`
38
``
-
39
``
`-
(if<(if <(if<ty as PostProcessing>::should_run(options) {
`
40
``
`-
<$ty as PostProcessing>::run(&mut items);
`
41
``
`-
})*
`
42
``
-
43
``
`-
let synful_items = items
`
44
``
`-
.into_iter()
`
45
``
`-
.map(|item| item.into_token_stream());
`
``
7
`+
struct PostProcessingPass {
`
``
8
`+
should_run: fn(&BindgenOptions) -> bool,
`
``
9
`+
run: fn(&mut Vec),
`
``
10
`+
}
`
46
11
``
47
``
`-
quote! { #( #synful_items )* }
`
``
12
`+
// TODO: This can be a const fn when mutable references are allowed in const
`
``
13
`+
// context.
`
``
14
`+
macro_rules! pass {
`
``
15
`+
($pass:ident) => {
`
``
16
`+
PostProcessingPass {
`
``
17
`+
should_run: |options| options.$pass,
`
``
18
`+
run: $pass,
`
48
19
`}
`
49
20
`};
`
50
21
`}
`
51
22
``
52
``
`-
decl_postprocessing! {
`
53
``
`-
MergeExternBlocks,
`
54
``
`-
SortSemantically
`
55
``
`-
}
`
56
``
-
57
``
`-
trait PostProcessing {
`
58
``
`-
fn should_run(options: &BindgenOptions) -> bool;
`
59
``
-
60
``
`-
fn run(items: &mut Vec);
`
61
``
`-
}
`
62
``
-
63
``
`-
struct SortSemantically;
`
``
23
`+
static PASSES: [PostProcessingPass; 2] =
`
``
24
`+
[pass!(merge_extern_blocks), pass!(sort_semantically)];
`
64
25
``
65
``
`-
impl PostProcessing for SortSemantically {
`
66
``
`-
#[inline]
`
67
``
`-
fn should_run(options: &BindgenOptions) -> bool {
`
68
``
`-
options.sort_semantically
`
``
26
`+
pub(crate) fn postprocessing(
`
``
27
`+
items: Vec,
`
``
28
`+
options: &BindgenOptions,
`
``
29
`+
) -> TokenStream {
`
``
30
`+
let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options));
`
``
31
`+
if !require_syn {
`
``
32
`+
return items.into_iter().collect();
`
69
33
`}
`
70
``
-
71
``
`-
fn run(items: &mut Vec) {
`
72
``
`-
items.sort_by_key(|item| match item {
`
73
``
`-
Item::Type(_) => 0,
`
74
``
`-
Item::Struct(_) => 1,
`
75
``
`-
Item::Const(_) => 2,
`
76
``
`-
Item::Fn(_) => 3,
`
77
``
`-
Item::Enum(_) => 4,
`
78
``
`-
Item::Union(_) => 5,
`
79
``
`-
Item::Static(_) => 6,
`
80
``
`-
Item::Trait(_) => 7,
`
81
``
`-
Item::TraitAlias(_) => 8,
`
82
``
`-
Item::Impl(_) => 9,
`
83
``
`-
Item::Mod(_) => 10,
`
84
``
`-
Item::Use(_) => 11,
`
85
``
`-
Item::Verbatim(_) => 12,
`
86
``
`-
Item::ExternCrate(_) => 13,
`
87
``
`-
Item::ForeignMod(_) => 14,
`
88
``
`-
Item::Macro(_) => 15,
`
89
``
`-
Item::Macro2(_) => 16,
`
90
``
`-
_ => 18,
`
91
``
`-
});
`
``
34
`+
let module_wrapped_tokens =
`
``
35
`+
quote!(mod wrapper_for_sorting_hack { #( #items )* });
`
``
36
+
``
37
`+
// This syn business is a hack, for now. This means that we are re-parsing already
`
``
38
`` +
// generated code using syn
(as opposed to quote
) because syn
provides us more
``
``
39
`+
// control over the elements.
`
``
40
`` +
// One caveat is that some of the items coming from quote
d output might have
``
``
41
`` +
// multiple items within them. Hence, we have to wrap the incoming in a mod
.
``
``
42
`` +
// The two unwrap
s here are deliberate because
``
``
43
`` +
// The first one won't panic because we build the mod
and know it is there
``
``
44
`+
// The second one won't panic because we know original output has something in
`
``
45
`+
// it already.
`
``
46
`+
let mut items = syn::parse2::syn::ItemMod(module_wrapped_tokens)
`
``
47
`+
.unwrap()
`
``
48
`+
.content
`
``
49
`+
.unwrap()
`
``
50
`+
.1;
`
``
51
+
``
52
`+
for pass in PASSES.iter() {
`
``
53
`+
if (pass.should_run)(options) {
`
``
54
`+
(pass.run)(&mut items);
`
``
55
`+
}
`
92
56
`}
`
93
``
`-
}
`
94
57
``
95
``
`-
struct MergeExternBlocks;
`
``
58
`+
let synful_items = items.into_iter().map(|item| item.into_token_stream());
`
96
59
``
97
``
`-
impl PostProcessing for MergeExternBlocks {
`
98
``
`-
#[inline]
`
99
``
`-
fn should_run(options: &BindgenOptions) -> bool {
`
100
``
`-
options.merge_extern_blocks
`
101
``
`-
}
`
``
60
`+
quote! { #( #synful_items )* }
`
``
61
`+
}
`
102
62
``
103
``
`-
fn run(items: &mut Vec) {
`
104
``
`` -
// Keep all the extern blocks in a different Vec
for faster search.
``
105
``
`-
let mut foreign_mods = Vec::syn::ItemForeignMod::new();
`
``
63
`+
fn sort_semantically(items: &mut Vec) {
`
``
64
`+
items.sort_by_key(|item| match item {
`
``
65
`+
Item::Type(_) => 0,
`
``
66
`+
Item::Struct(_) => 1,
`
``
67
`+
Item::Const(_) => 2,
`
``
68
`+
Item::Fn(_) => 3,
`
``
69
`+
Item::Enum(_) => 4,
`
``
70
`+
Item::Union(_) => 5,
`
``
71
`+
Item::Static(_) => 6,
`
``
72
`+
Item::Trait(_) => 7,
`
``
73
`+
Item::TraitAlias(_) => 8,
`
``
74
`+
Item::Impl(_) => 9,
`
``
75
`+
Item::Mod(_) => 10,
`
``
76
`+
Item::Use(_) => 11,
`
``
77
`+
Item::Verbatim(_) => 12,
`
``
78
`+
Item::ExternCrate(_) => 13,
`
``
79
`+
Item::ForeignMod(_) => 14,
`
``
80
`+
Item::Macro(_) => 15,
`
``
81
`+
Item::Macro2(_) => 16,
`
``
82
`+
_ => 18,
`
``
83
`+
});
`
``
84
`+
}
`
106
85
``
107
``
`-
for item in std::mem::take(items) {
`
108
``
`-
match item {
`
109
``
`-
Item::ForeignMod(syn::ItemForeignMod {
`
110
``
`-
attrs,
`
111
``
`-
abi,
`
112
``
`-
brace_token,
`
113
``
`-
items: foreign_items,
`
114
``
`-
}) => {
`
115
``
`-
let mut exists = false;
`
116
``
`-
for foreign_mod in &mut foreign_mods {
`
117
``
`-
// Check if there is a extern block with the same ABI and
`
118
``
`-
// attributes.
`
119
``
`-
if foreign_mod.attrs == attrs && foreign_mod.abi == abi
`
120
``
`-
{
`
121
``
`-
// Merge the items of the two blocks.
`
122
``
`-
foreign_mod.items.extend_from_slice(&foreign_items);
`
123
``
`-
exists = true;
`
124
``
`-
break;
`
125
``
`-
}
`
126
``
`-
}
`
127
``
`-
// If no existing extern block had the same ABI and attributes, store
`
128
``
`-
// it.
`
129
``
`-
if !exists {
`
130
``
`-
foreign_mods.push(syn::ItemForeignMod {
`
131
``
`-
attrs,
`
132
``
`-
abi,
`
133
``
`-
brace_token,
`
134
``
`-
items: foreign_items,
`
135
``
`-
});
`
``
86
`+
fn merge_extern_blocks(items: &mut Vec) {
`
``
87
`` +
// Keep all the extern blocks in a different Vec
for faster search.
``
``
88
`+
let mut foreign_mods = Vec::syn::ItemForeignMod::new();
`
``
89
+
``
90
`+
for item in std::mem::take(items) {
`
``
91
`+
match item {
`
``
92
`+
Item::ForeignMod(syn::ItemForeignMod {
`
``
93
`+
attrs,
`
``
94
`+
abi,
`
``
95
`+
brace_token,
`
``
96
`+
items: foreign_items,
`
``
97
`+
}) => {
`
``
98
`+
let mut exists = false;
`
``
99
`+
for foreign_mod in &mut foreign_mods {
`
``
100
`+
// Check if there is a extern block with the same ABI and
`
``
101
`+
// attributes.
`
``
102
`+
if foreign_mod.attrs == attrs && foreign_mod.abi == abi {
`
``
103
`+
// Merge the items of the two blocks.
`
``
104
`+
foreign_mod.items.extend_from_slice(&foreign_items);
`
``
105
`+
exists = true;
`
``
106
`+
break;
`
136
107
`}
`
137
108
`}
`
138
``
`-
// If the item is not an extern block, we don't have to do anything.
`
139
``
`-
_ => items.push(item),
`
``
109
`+
// If no existing extern block had the same ABI and attributes, store
`
``
110
`+
// it.
`
``
111
`+
if !exists {
`
``
112
`+
foreign_mods.push(syn::ItemForeignMod {
`
``
113
`+
attrs,
`
``
114
`+
abi,
`
``
115
`+
brace_token,
`
``
116
`+
items: foreign_items,
`
``
117
`+
});
`
``
118
`+
}
`
140
119
`}
`
``
120
`+
// If the item is not an extern block, we don't have to do anything.
`
``
121
`+
_ => items.push(item),
`
141
122
`}
`
``
123
`+
}
`
142
124
``
143
``
`-
// Move all the extern blocks alongiside the rest of the items.
`
144
``
`-
for foreign_mod in foreign_mods {
`
145
``
`-
items.push(Item::ForeignMod(foreign_mod));
`
146
``
`-
}
`
``
125
`+
// Move all the extern blocks alongside the rest of the items.
`
``
126
`+
for foreign_mod in foreign_mods {
`
``
127
`+
items.push(Item::ForeignMod(foreign_mod));
`
147
128
`}
`
148
129
`}
`