summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Vo <auscompgeek@users.noreply.github.com>2019-11-14 22:55:05 +1100
committerEmilio Cobos Álvarez <emilio@crisal.io>2019-11-14 17:35:38 +0100
commitac498475e04b44e3c555002213fa9cba0658198e (patch)
tree748c5addf3c70199cfae791e8741708707620f3d
parentf27fe97089b5c124dae4afbbbfeb66a3b44579d5 (diff)
Add newtype enum style
This adds an enum style similar to the existing bitfield style, without the bitwise operator impls. Closes: #1669
-rw-r--r--src/codegen/mod.rs33
-rw-r--r--src/ir/enum_ty.rs8
-rw-r--r--src/lib.rs48
-rw-r--r--src/options.rs20
-rw-r--r--tests/expectations/tests/newtype-enum.rs24
-rw-r--r--tests/headers/newtype-enum.hpp8
6 files changed, 120 insertions, 21 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 1173984b..90314a57 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -2282,8 +2282,11 @@ pub enum EnumVariation {
/// Indicates whether the generated struct should be #[non_exhaustive]
non_exhaustive: bool,
},
- /// The code for this enum will use a bitfield
- Bitfield,
+ /// The code for this enum will use a newtype
+ NewType {
+ /// Indicates whether the newtype will have bitwise operators
+ is_bitfield: bool,
+ },
/// The code for this enum will use consts
Consts,
/// The code for this enum will use a module containing consts
@@ -2322,13 +2325,14 @@ impl std::str::FromStr for EnumVariation {
match s {
"rust" => Ok(EnumVariation::Rust{ non_exhaustive: false }),
"rust_non_exhaustive" => Ok(EnumVariation::Rust{ non_exhaustive: true }),
- "bitfield" => Ok(EnumVariation::Bitfield),
+ "bitfield" => Ok(EnumVariation::NewType { is_bitfield: true }),
"consts" => Ok(EnumVariation::Consts),
"moduleconsts" => Ok(EnumVariation::ModuleConsts),
+ "newtype" => Ok(EnumVariation::NewType { is_bitfield: false }),
_ => Err(std::io::Error::new(std::io::ErrorKind::InvalidInput,
concat!("Got an invalid EnumVariation. Accepted values ",
- "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts', and ",
- "'moduleconsts'."))),
+ "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts',",
+ "'moduleconsts', and 'newtype'."))),
}
}
}
@@ -2342,10 +2346,11 @@ enum EnumBuilder<'a> {
tokens: proc_macro2::TokenStream,
emitted_any_variants: bool,
},
- Bitfield {
+ NewType {
codegen_depth: usize,
canonical_name: &'a str,
tokens: proc_macro2::TokenStream,
+ is_bitfield: bool,
},
Consts {
variants: Vec<proc_macro2::TokenStream>,
@@ -2363,7 +2368,7 @@ impl<'a> EnumBuilder<'a> {
fn codegen_depth(&self) -> usize {
match *self {
EnumBuilder::Rust { codegen_depth, .. } |
- EnumBuilder::Bitfield { codegen_depth, .. } |
+ EnumBuilder::NewType { codegen_depth, .. } |
EnumBuilder::ModuleConsts { codegen_depth, .. } |
EnumBuilder::Consts { codegen_depth, .. } => codegen_depth,
}
@@ -2381,13 +2386,14 @@ impl<'a> EnumBuilder<'a> {
let ident = Ident::new(name, Span::call_site());
match enum_variation {
- EnumVariation::Bitfield => EnumBuilder::Bitfield {
+ EnumVariation::NewType { is_bitfield } => EnumBuilder::NewType {
codegen_depth: enum_codegen_depth,
canonical_name: name,
tokens: quote! {
#( #attrs )*
pub struct #ident (pub #repr);
},
+ is_bitfield,
},
EnumVariation::Rust { .. } => {
@@ -2475,7 +2481,7 @@ impl<'a> EnumBuilder<'a> {
}
}
- EnumBuilder::Bitfield { canonical_name, .. } => {
+ EnumBuilder::NewType { canonical_name, .. } => {
if ctx.options().rust_features().associated_const && is_ty_named
{
let enum_ident = ctx.rust_ident(canonical_name);
@@ -2566,11 +2572,16 @@ impl<'a> EnumBuilder<'a> {
}
}
}
- EnumBuilder::Bitfield {
+ EnumBuilder::NewType {
canonical_name,
tokens,
+ is_bitfield,
..
} => {
+ if !is_bitfield {
+ return tokens;
+ }
+
let rust_ty_name = ctx.rust_ident_raw(canonical_name);
let prefix = ctx.trait_prefix();
@@ -2704,7 +2715,7 @@ impl CodeGenerator for Enum {
panic!("The rust target you're using doesn't seem to support non_exhaustive enums");
}
}
- EnumVariation::Bitfield => {
+ EnumVariation::NewType { .. } => {
if ctx.options().rust_features.repr_transparent {
attrs.push(attributes::repr("transparent"));
} else {
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index 442b5e2e..95e7e1fa 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -183,7 +183,13 @@ impl Enum {
&ctx.options().bitfield_enums,
item,
) {
- EnumVariation::Bitfield
+ EnumVariation::NewType { is_bitfield: true }
+ } else if self.is_matching_enum(
+ ctx,
+ &ctx.options().newtype_enums,
+ item,
+ ) {
+ EnumVariation::NewType { is_bitfield: false }
} else if self.is_matching_enum(
ctx,
&ctx.options().rustified_enums,
diff --git a/src/lib.rs b/src/lib.rs
index 8fa1b3df..c15d20bc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -189,13 +189,15 @@ impl Default for CodegenConfig {
///
/// 1. [`constified_enum_module()`](#method.constified_enum_module)
/// 2. [`bitfield_enum()`](#method.bitfield_enum)
-/// 3. [`rustified_enum()`](#method.rustified_enum)
+/// 3. [`newtype_enum()`](#method.newtype_enum)
+/// 4. [`rustified_enum()`](#method.rustified_enum)
///
/// For each C enum, bindgen tries to match the pattern in the following order:
///
/// 1. Constified enum module
/// 2. Bitfield enum
-/// 3. Rustified enum
+/// 3. Newtype enum
+/// 4. Rustified enum
///
/// If none of the above patterns match, then bindgen will generate a set of Rust constants.
#[derive(Debug, Default)]
@@ -234,7 +236,12 @@ impl Builder {
codegen::EnumVariation::Rust {
non_exhaustive: true,
} => "rust_non_exhaustive",
- codegen::EnumVariation::Bitfield => "bitfield",
+ codegen::EnumVariation::NewType {
+ is_bitfield: true,
+ } => "bitfield",
+ codegen::EnumVariation::NewType {
+ is_bitfield: false,
+ } => "newtype",
codegen::EnumVariation::Consts => "consts",
codegen::EnumVariation::ModuleConsts => "moduleconsts",
}
@@ -253,6 +260,16 @@ impl Builder {
.count();
self.options
+ .newtype_enums
+ .get_items()
+ .iter()
+ .map(|item| {
+ output_vector.push("--newtype-enum".into());
+ output_vector.push(item.to_owned());
+ })
+ .count();
+
+ self.options
.rustified_enums
.get_items()
.iter()
@@ -860,11 +877,24 @@ impl Builder {
///
/// This makes bindgen generate a type that isn't a rust `enum`. Regular
/// expressions are supported.
+ ///
+ /// This is similar to the newtype enum style, but with the bitwise
+ /// operators implemented.
pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.bitfield_enums.insert(arg);
self
}
+ /// Mark the given enum (or set of enums, if using a pattern) as a newtype.
+ /// Regular expressions are supported.
+ ///
+ /// This makes bindgen generate a type that isn't a Rust `enum`. Regular
+ /// expressions are supported.
+ pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.newtype_enums.insert(arg);
+ self
+ }
+
/// Mark the given enum (or set of enums, if using a pattern) as a Rust
/// enum.
///
@@ -1280,7 +1310,7 @@ impl Builder {
self
}
- /// Prepend the enum name to constant or bitfield variants.
+ /// Prepend the enum name to constant or newtype variants.
pub fn prepend_enum_name(mut self, doit: bool) -> Self {
self.options.prepend_enum_name = doit;
self
@@ -1503,9 +1533,13 @@ struct BindgenOptions {
/// The default style of code to generate for enums
default_enum_style: codegen::EnumVariation,
- /// The enum patterns to mark an enum as bitfield.
+ /// The enum patterns to mark an enum as a bitfield
+ /// (newtype with bitwise operations).
bitfield_enums: RegexSet,
+ /// The enum patterns to mark an enum as a newtype.
+ newtype_enums: RegexSet,
+
/// The enum patterns to mark an enum as a Rust enum.
rustified_enums: RegexSet,
@@ -1684,7 +1718,7 @@ struct BindgenOptions {
/// Whether to detect include paths using clang_sys.
detect_include_paths: bool,
- /// Whether to prepend the enum name to bitfield or constant variants.
+ /// Whether to prepend the enum name to constant or newtype variants.
prepend_enum_name: bool,
/// Version of the Rust compiler to target
@@ -1737,6 +1771,7 @@ impl BindgenOptions {
&mut self.bitfield_enums,
&mut self.constified_enums,
&mut self.constified_enum_modules,
+ &mut self.newtype_enums,
&mut self.rustified_enums,
&mut self.rustified_non_exhaustive_enums,
&mut self.type_alias,
@@ -1783,6 +1818,7 @@ impl Default for BindgenOptions {
whitelisted_vars: Default::default(),
default_enum_style: Default::default(),
bitfield_enums: Default::default(),
+ newtype_enums: Default::default(),
rustified_enums: Default::default(),
rustified_non_exhaustive_enums: Default::default(),
constified_enums: Default::default(),
diff --git a/src/options.rs b/src/options.rs
index 4f872408..b09ba919 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -38,6 +38,7 @@ where
"consts",
"moduleconsts",
"bitfield",
+ "newtype",
"rust",
"rust_non_exhaustive",
])
@@ -52,6 +53,13 @@ where
.takes_value(true)
.multiple(true)
.number_of_values(1),
+ Arg::with_name("newtype-enum")
+ .long("newtype-enum")
+ .help("Mark any enum whose name matches <regex> as a newtype.")
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
Arg::with_name("rustified-enum")
.long("rustified-enum")
.help("Mark any enum whose name matches <regex> as a Rust enum.")
@@ -281,7 +289,7 @@ where
.help("Do not automatically convert floats to f32/f64."),
Arg::with_name("no-prepend-enum-name")
.long("no-prepend-enum-name")
- .help("Do not prepend the enum name to bitfield or constant variants."),
+ .help("Do not prepend the enum name to constant or newtype variants."),
Arg::with_name("no-include-path-detection")
.long("no-include-path-detection")
.help("Do not try to detect default include paths"),
@@ -460,14 +468,20 @@ where
}
}
+ if let Some(newtypes) = matches.values_of("newtype-enum") {
+ for regex in newtypes {
+ builder = builder.newtype_enum(regex);
+ }
+ }
+
if let Some(rustifieds) = matches.values_of("rustified-enum") {
for regex in rustifieds {
builder = builder.rustified_enum(regex);
}
}
- if let Some(bitfields) = matches.values_of("constified-enum") {
- for regex in bitfields {
+ if let Some(const_enums) = matches.values_of("constified-enum") {
+ for regex in const_enums {
builder = builder.constified_enum(regex);
}
}
diff --git a/tests/expectations/tests/newtype-enum.rs b/tests/expectations/tests/newtype-enum.rs
new file mode 100644
index 00000000..6653aea7
--- /dev/null
+++ b/tests/expectations/tests/newtype-enum.rs
@@ -0,0 +1,24 @@
+/* automatically generated by rust-bindgen */
+
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+impl Foo {
+ pub const Bar: Foo = Foo(2);
+}
+impl Foo {
+ pub const Baz: Foo = Foo(4);
+}
+impl Foo {
+ pub const Duplicated: Foo = Foo(4);
+}
+impl Foo {
+ pub const Negative: Foo = Foo(-3);
+}
+#[repr(transparent)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Foo(pub i32);
diff --git a/tests/headers/newtype-enum.hpp b/tests/headers/newtype-enum.hpp
new file mode 100644
index 00000000..890683ae
--- /dev/null
+++ b/tests/headers/newtype-enum.hpp
@@ -0,0 +1,8 @@
+// bindgen-flags: --newtype-enum "Foo" --rust-target 1.28 -- -std=c++11
+
+enum Foo {
+ Bar = 1 << 1,
+ Baz = 1 << 2,
+ Duplicated = 1 << 2,
+ Negative = -3,
+};