| 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 | |