diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 73 |
1 files changed, 70 insertions, 3 deletions
@@ -615,6 +615,10 @@ impl Builder { output_vector.push("--sort-semantically".into()); } + if self.options.merge_extern_blocks { + output_vector.push("--merge-extern-blocks".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1542,7 +1546,7 @@ impl Builder { self } - /// If true, enables the sorting of the output in a predefined manner + /// If true, enables the sorting of the output in a predefined manner. /// /// TODO: Perhaps move the sorting order out into a config pub fn sort_semantically(mut self, doit: bool) -> Self { @@ -1550,6 +1554,12 @@ impl Builder { self } + /// If true, merges extern blocks. + pub fn merge_extern_blocks(mut self, doit: bool) -> Self { + self.options.merge_extern_blocks = doit; + self + } + /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result<Bindings, BindgenError> { // Add any extra arguments from the environment to the clang command line. @@ -2095,8 +2105,11 @@ struct BindgenOptions { /// Emit vtable functions. vtable_generation: bool, - /// Sort the code generation + /// Sort the code generation. sort_semantically: bool, + + /// Deduplicate `extern` blocks. + merge_extern_blocks: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -2107,7 +2120,7 @@ impl ::std::panic::UnwindSafe for BindgenOptions {} impl BindgenOptions { /// Whether any of the enabled options requires `syn`. fn require_syn(&self) -> bool { - self.sort_semantically + self.sort_semantically || self.merge_extern_blocks } fn build(&mut self) { @@ -2258,6 +2271,7 @@ impl Default for BindgenOptions { force_explicit_padding: false, vtable_generation: false, sort_semantically: false, + merge_extern_blocks: false, } } } @@ -2563,6 +2577,59 @@ impl Bindings { .unwrap() .1; + if options.merge_extern_blocks { + // Here we will store all the items after deduplication. + let mut items = Vec::new(); + + // Keep all the extern blocks in a different `Vec` for faster search. + let mut foreign_mods = Vec::<syn::ItemForeignMod>::new(); + for item in syn_parsed_items { + match item { + syn::Item::ForeignMod(syn::ItemForeignMod { + attrs, + abi, + brace_token, + items: foreign_items, + }) => { + let mut exists = false; + for foreign_mod in &mut foreign_mods { + // Check if there is a extern block with the same ABI and + // attributes. + if foreign_mod.attrs == attrs && + foreign_mod.abi == abi + { + // Merge the items of the two blocks. + foreign_mod + .items + .extend_from_slice(&foreign_items); + exists = true; + break; + } + } + // If no existing extern block had the same ABI and attributes, store + // it. + if !exists { + foreign_mods.push(syn::ItemForeignMod { + attrs, + abi, + brace_token, + items: foreign_items, + }); + } + } + // If the item is not an extern block, we don't have to do anything. + _ => items.push(item), + } + } + + // Move all the extern blocks alongiside the rest of the items. + for foreign_mod in foreign_mods { + items.push(syn::Item::ForeignMod(foreign_mod)); + } + + syn_parsed_items = items; + } + if options.sort_semantically { syn_parsed_items.sort_by_key(|item| match item { syn::Item::Type(_) => 0, |