67 lines
2.4 KiB
Rust
67 lines
2.4 KiB
Rust
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)
|
|
}
|
|
}
|