bindgen/codegen/postprocessing/merge_extern_blocks.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 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)
}
}