diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 106 | ||||
-rw-r--r-- | src/lib.rs | 97 | ||||
-rw-r--r-- | src/options.rs | 67 |
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 @@ -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); |