summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/mod.rs106
-rw-r--r--src/lib.rs97
-rw-r--r--src/options.rs67
3 files changed, 264 insertions, 6 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index a3755867..ea01d4b7 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -749,6 +749,16 @@ impl CodeGenerator for Type {
quote! {}
};
+ let alias_style = if ctx.options().type_alias.matches(&name) {
+ AliasVariation::TypeAlias
+ } else if ctx.options().new_type_alias.matches(&name) {
+ AliasVariation::NewType
+ } else if ctx.options().new_type_alias_deref.matches(&name) {
+ AliasVariation::NewTypeDeref
+ } else {
+ ctx.options().default_alias_style
+ };
+
// We prefer using `pub use` over `pub type` because of:
// https://github.com/rust-lang/rust/issues/26264
if inner_rust_type.to_string().chars().all(|c| match c {
@@ -758,6 +768,7 @@ impl CodeGenerator for Type {
_ => false,
}) && outer_params.is_empty() &&
!is_opaque &&
+ alias_style == AliasVariation::TypeAlias &&
inner_item.expect_type().canonical_type(ctx).is_enum()
{
tokens.append_all(quote! {
@@ -772,8 +783,21 @@ impl CodeGenerator for Type {
return;
}
- tokens.append_all(quote! {
- pub type #rust_name
+ tokens.append_all(match alias_style {
+ AliasVariation::TypeAlias => quote! {
+ pub type #rust_name
+ },
+ AliasVariation::NewType | AliasVariation::NewTypeDeref => {
+ assert!(
+ ctx.options().rust_features().repr_transparent,
+ "repr_transparent feature is required to use {:?}",
+ alias_style
+ );
+ quote! {
+ #[repr(transparent)]
+ pub struct #rust_name
+ }
+ }
});
let params: Vec<_> = outer_params
@@ -806,10 +830,36 @@ impl CodeGenerator for Type {
});
}
- tokens.append_all(quote! {
- = #inner_rust_type ;
+ tokens.append_all(match alias_style {
+ AliasVariation::TypeAlias => quote! {
+ = #inner_rust_type ;
+ },
+ AliasVariation::NewType | AliasVariation::NewTypeDeref => {
+ quote! {
+ (pub #inner_rust_type) ;
+ }
+ }
});
+ if alias_style == AliasVariation::NewTypeDeref {
+ let prefix = ctx.trait_prefix();
+ tokens.append_all(quote! {
+ impl ::#prefix::ops::Deref for #rust_name {
+ type Target = #inner_rust_type;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ impl ::#prefix::ops::DerefMut for #rust_name {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+ }
+ });
+ }
+
result.push(tokens);
}
TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item),
@@ -2870,6 +2920,54 @@ impl CodeGenerator for Enum {
}
}
+/// Enum for how aliases should be translated.
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum AliasVariation {
+ /// Convert to regular Rust alias
+ TypeAlias,
+ /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)]
+ NewType,
+ /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type
+ NewTypeDeref,
+}
+
+impl AliasVariation {
+ /// Convert an `AliasVariation` to its str representation.
+ pub fn as_str(&self) -> &str {
+ match self {
+ AliasVariation::TypeAlias => "type_alias",
+ AliasVariation::NewType => "new_type",
+ AliasVariation::NewTypeDeref => "new_type_deref",
+ }
+ }
+}
+
+impl Default for AliasVariation {
+ fn default() -> AliasVariation {
+ AliasVariation::TypeAlias
+ }
+}
+
+impl std::str::FromStr for AliasVariation {
+ type Err = std::io::Error;
+
+ /// Create an `AliasVariation` from a string.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "type_alias" => Ok(AliasVariation::TypeAlias),
+ "new_type" => Ok(AliasVariation::NewType),
+ "new_type_deref" => Ok(AliasVariation::NewTypeDeref),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid AliasVariation. Accepted values ",
+ "are 'type_alias', 'new_type', and 'new_type_deref'"
+ ),
+ )),
+ }
+ }
+}
+
/// Fallible conversion to an opaque blob.
///
/// Implementors of this trait should provide the `try_get_layout` method to
diff --git a/src/lib.rs b/src/lib.rs
index 4df89454..8fa1b3df 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -83,7 +83,7 @@ doc_mod!(ir, ir_docs);
doc_mod!(parse, parse_docs);
doc_mod!(regex_set, regex_set_docs);
-pub use codegen::EnumVariation;
+pub use codegen::{AliasVariation, EnumVariation};
use features::RustFeatures;
pub use features::{RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS};
use ir::context::{BindgenContext, ItemId};
@@ -292,6 +292,42 @@ impl Builder {
})
.count();
+ if self.options.default_alias_style != Default::default() {
+ output_vector.push("--default-alias-style=".into());
+ output_vector
+ .push(self.options.default_alias_style.as_str().into());
+ }
+
+ self.options
+ .type_alias
+ .get_items()
+ .iter()
+ .map(|item| {
+ output_vector.push("--type-alias".into());
+ output_vector.push(item.to_owned());
+ })
+ .count();
+
+ self.options
+ .new_type_alias
+ .get_items()
+ .iter()
+ .map(|item| {
+ output_vector.push("--new-type-alias".into());
+ output_vector.push(item.to_owned());
+ })
+ .count();
+
+ self.options
+ .new_type_alias_deref
+ .get_items()
+ .iter()
+ .map(|item| {
+ output_vector.push("--new-type-alias-deref".into());
+ output_vector.push(item.to_owned());
+ })
+ .count();
+
self.options
.blacklisted_types
.get_items()
@@ -873,6 +909,45 @@ impl Builder {
self
}
+ /// Set the default style of code to generate for typedefs
+ pub fn default_alias_style(
+ mut self,
+ arg: codegen::AliasVariation,
+ ) -> Builder {
+ self.options.default_alias_style = arg;
+ self
+ }
+
+ /// Mark the given typedef alias (or set of aliases, if using a pattern) to
+ /// use regular Rust type aliasing.
+ ///
+ /// This is the default behavior and should be used if `default_alias_style`
+ /// was set to NewType or NewTypeDeref and you want to override it for a
+ /// set of typedefs.
+ pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.type_alias.insert(arg);
+ self
+ }
+
+ /// Mark the given typedef alias (or set of aliases, if using a pattern) to
+ /// be generated as a new type by having the aliased type be wrapped in a
+ /// #[repr(transparent)] struct.
+ ///
+ /// Used to enforce stricter type checking.
+ pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.new_type_alias.insert(arg);
+ self
+ }
+
+ /// Mark the given typedef alias (or set of aliases, if using a pattern) to
+ /// be generated as a new type by having the aliased type be wrapped in a
+ /// #[repr(transparent)] struct and also have an automatically generated
+ /// impl's of `Deref` and `DerefMut` to their aliased type.
+ pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.new_type_alias_deref.insert(arg);
+ self
+ }
+
/// Add a string to prepend to the generated bindings. The string is passed
/// through without any modification.
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
@@ -1443,6 +1518,19 @@ struct BindgenOptions {
/// The enum patterns to mark an enum as a set of constants.
constified_enums: RegexSet,
+ /// The default style of code to generate for typedefs.
+ default_alias_style: codegen::AliasVariation,
+
+ /// Typedef patterns that will use regular type aliasing.
+ type_alias: RegexSet,
+
+ /// Typedef patterns that will be aliased by creating a new struct.
+ new_type_alias: RegexSet,
+
+ /// Typedef patterns that will be wrapped in a new struct and have
+ /// Deref and Deref to their aliased type.
+ new_type_alias_deref: RegexSet,
+
/// Whether we should generate builtins or not.
builtins: bool,
@@ -1651,6 +1739,9 @@ impl BindgenOptions {
&mut self.constified_enum_modules,
&mut self.rustified_enums,
&mut self.rustified_non_exhaustive_enums,
+ &mut self.type_alias,
+ &mut self.new_type_alias,
+ &mut self.new_type_alias_deref,
&mut self.no_partialeq_types,
&mut self.no_copy_types,
&mut self.no_hash_types,
@@ -1696,6 +1787,10 @@ impl Default for BindgenOptions {
rustified_non_exhaustive_enums: Default::default(),
constified_enums: Default::default(),
constified_enum_modules: Default::default(),
+ default_alias_style: Default::default(),
+ type_alias: Default::default(),
+ new_type_alias: Default::default(),
+ new_type_alias_deref: Default::default(),
builtins: false,
emit_ast: false,
emit_ir: false,
diff --git a/src/options.rs b/src/options.rs
index af50466c..4f872408 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -1,5 +1,5 @@
use bindgen::{
- builder, Builder, CodegenConfig, EnumVariation, RustTarget,
+ builder, AliasVariation, Builder, CodegenConfig, EnumVariation, RustTarget,
RUST_TARGET_STRINGS,
};
use clap::{App, Arg};
@@ -79,6 +79,47 @@ where
.takes_value(true)
.multiple(true)
.number_of_values(1),
+ Arg::with_name("default-alias-style")
+ .long("default-alias-style")
+ .help("The default style of code used to generate typedefs.")
+ .value_name("variant")
+ .default_value("type_alias")
+ .possible_values(&[
+ "type_alias",
+ "new_type",
+ "new_type_deref",
+ ])
+ .multiple(false),
+ Arg::with_name("normal-alias")
+ .long("normal-alias")
+ .help(
+ "Mark any typedef alias whose name matches <regex> to use \
+ normal type aliasing.",
+ )
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("new-type-alias")
+ .long("new-type-alias")
+ .help(
+ "Mark any typedef alias whose name matches <regex> to have \
+ a new type generated for it.",
+ )
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
+ Arg::with_name("new-type-alias-deref")
+ .long("new-type-alias-deref")
+ .help(
+ "Mark any typedef alias whose name matches <regex> to have \
+ a new type with Deref and DerefMut to the inner type.",
+ )
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
Arg::with_name("blacklist-type")
.long("blacklist-type")
.help("Mark <type> as hidden.")
@@ -436,6 +477,30 @@ where
builder = builder.constified_enum_module(regex);
}
}
+
+ if let Some(variant) = matches.value_of("default-alias-style") {
+ builder =
+ builder.default_alias_style(AliasVariation::from_str(variant)?);
+ }
+
+ if let Some(type_alias) = matches.values_of("normal-alias") {
+ for regex in type_alias {
+ builder = builder.type_alias(regex);
+ }
+ }
+
+ if let Some(new_type) = matches.values_of("new-type-alias") {
+ for regex in new_type {
+ builder = builder.new_type_alias(regex);
+ }
+ }
+
+ if let Some(new_type_deref) = matches.values_of("new-type-alias-deref") {
+ for regex in new_type_deref {
+ builder = builder.new_type_alias_deref(regex);
+ }
+ }
+
if let Some(hidden_types) = matches.values_of("blacklist-type") {
for ty in hidden_types {
builder = builder.blacklist_type(ty);