1 | use proc_macro2::TokenStream; |
2 | use quote::ToTokens; |
3 | use syn::{parse2, File}; |
4 | |
5 | use crate::BindgenOptions; |
6 | |
7 | mod merge_extern_blocks; |
8 | mod sort_semantically; |
9 | |
10 | use merge_extern_blocks::merge_extern_blocks; |
11 | use sort_semantically::sort_semantically; |
12 | |
13 | struct PostProcessingPass { |
14 | should_run: fn(&BindgenOptions) -> bool, |
15 | run: fn(&mut File), |
16 | } |
17 | |
18 | // TODO: This can be a const fn when mutable references are allowed in const |
19 | // context. |
20 | macro_rules! pass { |
21 | ($pass:ident) => { |
22 | PostProcessingPass { |
23 | should_run: |options| options.$pass, |
24 | run: |file| $pass(file), |
25 | } |
26 | }; |
27 | } |
28 | |
29 | const PASSES: &[PostProcessingPass] = |
30 | &[pass!(merge_extern_blocks), pass!(sort_semantically)]; |
31 | |
32 | pub(crate) fn postprocessing( |
33 | items: Vec<TokenStream>, |
34 | options: &BindgenOptions, |
35 | ) -> TokenStream { |
36 | let items: TokenStream = items.into_iter().collect(); |
37 | let require_syn: bool = PASSES.iter().any(|pass: &PostProcessingPass| (pass.should_run)(options)); |
38 | |
39 | if !require_syn { |
40 | return items; |
41 | } |
42 | |
43 | // This syn business is a hack, for now. This means that we are re-parsing already |
44 | // generated code using `syn` (as opposed to `quote`) because `syn` provides us more |
45 | // control over the elements. |
46 | // The `unwrap` here is deliberate because bindgen should generate valid rust items at all |
47 | // times. |
48 | let mut file: File = parse2::<File>(tokens:items).unwrap(); |
49 | |
50 | for pass: &PostProcessingPass in PASSES { |
51 | if (pass.should_run)(options) { |
52 | (pass.run)(&mut file); |
53 | } |
54 | } |
55 | |
56 | file.into_token_stream() |
57 | } |
58 | |