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::::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) } }