diff options
author | Justin W Smith <103147162+justsmth@users.noreply.github.com> | 2022-09-09 08:49:01 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-09 08:49:01 -0400 |
commit | a8f2634cf6bdc9c20368b4edf3ed46acc68adf3d (patch) | |
tree | 0a49e774df6b5deed35a95b0c2ae73874afe3c3c /src/lib.rs | |
parent | 3c8d6e9c2cdffda944d7f7e7b17fd1abc2cceca4 (diff) | |
parent | 9677e412c49e303e078e37ee30105cc635bb0ff8 (diff) |
Merge branch 'rust-lang:master' into generated_name_override
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 92 |
1 files changed, 91 insertions, 1 deletions
@@ -86,6 +86,7 @@ use std::{env, iter}; // Some convenient typedefs for a fast hash map and hash set. type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>; type HashSet<K> = ::rustc_hash::FxHashSet<K>; +use quote::ToTokens; pub(crate) use std::collections::hash_map::Entry; /// Default prefix for the anon fields. @@ -587,6 +588,10 @@ impl Builder { output_vector.push("--vtable-generation".into()); } + if self.options.sort_semantically { + output_vector.push("--sort-semantically".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1476,6 +1481,14 @@ impl Builder { self } + /// 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 { + self.options.sort_semantically = 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. @@ -2005,6 +2018,9 @@ struct BindgenOptions { /// Emit vtable functions. vtable_generation: bool, + + /// Sort the code generation + sort_semantically: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -2153,6 +2169,7 @@ impl Default for BindgenOptions { c_naming: false, force_explicit_padding: false, vtable_generation: false, + sort_semantically: false, } } } @@ -2222,6 +2239,7 @@ impl std::error::Error for BindgenError {} #[derive(Debug)] pub struct Bindings { options: BindgenOptions, + warnings: Vec<String>, module: proc_macro2::TokenStream, } @@ -2435,10 +2453,65 @@ impl Bindings { parse(&mut context)?; } - let (items, options) = codegen::codegen(context); + let (items, options, warnings) = codegen::codegen(context); + + if options.sort_semantically { + let module_wrapped_tokens = + quote!(mod wrapper_for_sorting_hack { #( #items )* }); + + // This semantically sorting business is a hack, for now. This means that we are + // re-parsing already generated code using `syn` (as opposed to `quote`) because + // `syn` provides us more control over the elements. + // One caveat is that some of the items coming from `quote`d output might have + // multiple items within them. Hence, we have to wrap the incoming in a `mod`. + // The two `unwrap`s here are deliberate because + // The first one won't panic because we build the `mod` and know it is there + // The second one won't panic because we know original output has something in + // it already. + let mut syn_parsed_items = + syn::parse2::<syn::ItemMod>(module_wrapped_tokens) + .unwrap() + .content + .unwrap() + .1; + + syn_parsed_items.sort_by_key(|item| match item { + syn::Item::Type(_) => 0, + syn::Item::Struct(_) => 1, + syn::Item::Const(_) => 2, + syn::Item::Fn(_) => 3, + syn::Item::Enum(_) => 4, + syn::Item::Union(_) => 5, + syn::Item::Static(_) => 6, + syn::Item::Trait(_) => 7, + syn::Item::TraitAlias(_) => 8, + syn::Item::Impl(_) => 9, + syn::Item::Mod(_) => 10, + syn::Item::Use(_) => 11, + syn::Item::Verbatim(_) => 12, + syn::Item::ExternCrate(_) => 13, + syn::Item::ForeignMod(_) => 14, + syn::Item::Macro(_) => 15, + syn::Item::Macro2(_) => 16, + _ => 18, + }); + + let synful_items = syn_parsed_items + .into_iter() + .map(|item| item.into_token_stream()); + + return Ok(Bindings { + options, + warnings, + module: quote! { + #( #synful_items )* + }, + }); + } Ok(Bindings { options, + warnings, module: quote! { #( #items )* }, @@ -2583,6 +2656,23 @@ impl Bindings { _ => Ok(Cow::Owned(source)), } } + + /// Emit all the warning messages raised while generating the bindings in a build script. + /// + /// If you are using `bindgen` outside of a build script you should use [`Bindings::warnings`] + /// and handle the messages accordingly instead. + #[inline] + pub fn emit_warnings(&self) { + for message in &self.warnings { + println!("cargo:warning={}", message); + } + } + + /// Return all the warning messages raised while generating the bindings. + #[inline] + pub fn warnings(&self) -> &[String] { + &self.warnings + } } impl std::fmt::Display for Bindings { |