diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/bindgen/codegen/postprocessing | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/bindgen/codegen/postprocessing')
3 files changed, 170 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs b/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs new file mode 100644 index 0000000000..05e7e9ef39 --- /dev/null +++ b/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs @@ -0,0 +1,66 @@ +use syn::{ + visit_mut::{visit_item_mod_mut, VisitMut}, + Item, ItemForeignMod, ItemMod, +}; + +pub(super) fn merge_extern_blocks(item_mod: &mut ItemMod) { + Visitor.visit_item_mod_mut(item_mod) +} + +struct Visitor; + +impl VisitMut for Visitor { + fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { + if let Some((_, ref mut items)) = item_mod.content { + // Keep all the extern blocks in a different `Vec` for faster search. + let mut extern_blocks = Vec::<ItemForeignMod>::new(); + + for item in std::mem::take(items) { + if let Item::ForeignMod(ItemForeignMod { + attrs, + abi, + brace_token, + items: extern_block_items, + }) = item + { + let mut exists = false; + for extern_block in &mut extern_blocks { + // Check if there is a extern block with the same ABI and + // attributes. + if extern_block.attrs == attrs && + extern_block.abi == abi + { + // Merge the items of the two blocks. + extern_block + .items + .extend_from_slice(&extern_block_items); + exists = true; + break; + } + } + // If no existing extern block had the same ABI and attributes, store + // it. + if !exists { + extern_blocks.push(ItemForeignMod { + attrs, + abi, + brace_token, + items: extern_block_items, + }); + } + } else { + // If the item is not an extern block, we don't have to do anything and just + // push it back. + items.push(item); + } + } + + // Move all the extern blocks alongside the rest of the items. + for extern_block in extern_blocks { + items.push(Item::ForeignMod(extern_block)); + } + } + + visit_item_mod_mut(self, item_mod) + } +} diff --git a/third_party/rust/bindgen/codegen/postprocessing/mod.rs b/third_party/rust/bindgen/codegen/postprocessing/mod.rs new file mode 100644 index 0000000000..1d5a4983bd --- /dev/null +++ b/third_party/rust/bindgen/codegen/postprocessing/mod.rs @@ -0,0 +1,66 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{parse2, ItemMod}; + +use crate::BindgenOptions; + +mod merge_extern_blocks; +mod sort_semantically; + +use merge_extern_blocks::merge_extern_blocks; +use sort_semantically::sort_semantically; + +struct PostProcessingPass { + should_run: fn(&BindgenOptions) -> bool, + run: fn(&mut ItemMod), +} + +// TODO: This can be a const fn when mutable references are allowed in const +// context. +macro_rules! pass { + ($pass:ident) => { + PostProcessingPass { + should_run: |options| options.$pass, + run: |item_mod| $pass(item_mod), + } + }; +} + +const PASSES: &[PostProcessingPass] = + &[pass!(merge_extern_blocks), pass!(sort_semantically)]; + +pub(crate) fn postprocessing( + items: Vec<TokenStream>, + options: &BindgenOptions, +) -> TokenStream { + let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options)); + if !require_syn { + return items.into_iter().collect(); + } + let module_wrapped_tokens = + quote!(mod wrapper_for_postprocessing_hack { #( #items )* }); + + // This syn business is a hack, for now. This means that we are re-parsing already + // generated code using `syn` (as opposed to `quote`) because `syn` provides us more + // control over the elements. + // One caveat is that some of the items coming from `quote`d output might have + // multiple items within them. Hence, we have to wrap the incoming in a `mod`. + // The `unwrap` here is deliberate because bindgen should generate valid rust items at all + // times. + let mut item_mod = parse2::<ItemMod>(module_wrapped_tokens).unwrap(); + + for pass in PASSES { + if (pass.should_run)(options) { + (pass.run)(&mut item_mod); + } + } + + let synful_items = item_mod + .content + .map(|(_, items)| items) + .unwrap_or_default() + .into_iter() + .map(|item| item.into_token_stream()); + + quote! { #( #synful_items )* } +} diff --git a/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs b/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs new file mode 100644 index 0000000000..4f23ab73a3 --- /dev/null +++ b/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs @@ -0,0 +1,38 @@ +use syn::{ + visit_mut::{visit_item_mod_mut, VisitMut}, + Item, ItemMod, +}; + +pub(super) fn sort_semantically(item_mod: &mut ItemMod) { + Visitor.visit_item_mod_mut(item_mod) +} + +struct Visitor; + +impl VisitMut for Visitor { + fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { + if let Some((_, ref mut items)) = item_mod.content { + items.sort_by_key(|item| match item { + Item::Type(_) => 0, + Item::Struct(_) => 1, + Item::Const(_) => 2, + Item::Fn(_) => 3, + Item::Enum(_) => 4, + Item::Union(_) => 5, + Item::Static(_) => 6, + Item::Trait(_) => 7, + Item::TraitAlias(_) => 8, + Item::Impl(_) => 9, + Item::Mod(_) => 10, + Item::Use(_) => 11, + Item::Verbatim(_) => 12, + Item::ExternCrate(_) => 13, + Item::ForeignMod(_) => 14, + Item::Macro(_) => 15, + Item::Macro2(_) => 16, + _ => 18, + }); + } + visit_item_mod_mut(self, item_mod) + } +} |