Skip to content

Commit 0798bda

Browse files
committed
Clean-up postprocessing to use less macro magic.
1 parent 3dfbc60 commit 0798bda

File tree

1 file changed

+104
-123
lines changed

1 file changed

+104
-123
lines changed

Diff for: src/codegen/postprocessing.rs

+104-123
Original file line numberDiff line numberDiff line change
@@ -4,145 +4,126 @@ use syn::Item;
44

55
use crate::BindgenOptions;
66

7-
macro_rules! decl_postprocessing {
8-
($($ty:ty),*) => {
9-
pub(crate) fn postprocessing(
10-
items: Vec<TokenStream>,
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 <$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<Item>),
10+
}
4611

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,
4819
}
4920
};
5021
}
5122

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<Item>);
61-
}
62-
63-
struct SortSemantically;
23+
static PASSES: [PostProcessingPass; 2] =
24+
[pass!(merge_extern_blocks), pass!(sort_semantically)];
6425

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<TokenStream>,
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();
6933
}
70-
71-
fn run(items: &mut Vec<Item>) {
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+
}
9256
}
93-
}
9457

95-
struct MergeExternBlocks;
58+
let synful_items = items.into_iter().map(|item| item.into_token_stream());
9659

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+
}
10262

103-
fn run(items: &mut Vec<Item>) {
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<Item>) {
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+
}
10685

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<Item>) {
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;
136107
}
137108
}
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+
}
140119
}
120+
// If the item is not an extern block, we don't have to do anything.
121+
_ => items.push(item),
141122
}
123+
}
142124

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));
147128
}
148129
}

0 commit comments

Comments
 (0)