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 
postprocessing( items: Vec<TokenStream>, options: &BindgenOptions, ) -> TokenStream32 pub(crate) fn postprocessing(
33     items: Vec<TokenStream>,
34     options: &BindgenOptions,
35 ) -> TokenStream {
36     let items = items.into_iter().collect();
37     let require_syn = PASSES.iter().any(|pass| (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 = parse2::<File>(items).unwrap();
49 
50     for pass in PASSES {
51         if (pass.should_run)(options) {
52             (pass.run)(&mut file);
53         }
54     }
55 
56     file.into_token_stream()
57 }
58