File: merge_extern_blocks.rs

package info (click to toggle)
rust-bindgen 0.72.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,412 kB
  • sloc: makefile: 8
file content (72 lines) | stat: -rw-r--r-- 2,242 bytes parent folder | download | duplicates (3)
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
67
68
69
70
71
72
use syn::{
    visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut},
    File, Item, ItemForeignMod, ItemMod,
};

pub(super) fn merge_extern_blocks(file: &mut File) {
    Visitor.visit_file_mut(file);
}

struct Visitor;

impl VisitMut for Visitor {
    fn visit_file_mut(&mut self, file: &mut File) {
        visit_items(&mut file.items);
        visit_file_mut(self, file);
    }

    fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
        if let Some((_, ref mut items)) = item_mod.content {
            visit_items(items);
        }
        visit_item_mod_mut(self, item_mod);
    }
}

fn visit_items(items: &mut Vec<Item>) {
    // 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,
            unsafety,
            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,
                    unsafety,
                    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));
    }
}