diff options
author | David Vo <auscompgeek@users.noreply.github.com> | 2019-11-14 22:55:05 +1100 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2019-11-14 17:35:38 +0100 |
commit | ac498475e04b44e3c555002213fa9cba0658198e (patch) | |
tree | 748c5addf3c70199cfae791e8741708707620f3d | |
parent | f27fe97089b5c124dae4afbbbfeb66a3b44579d5 (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.rs | 33 | ||||
-rw-r--r-- | src/ir/enum_ty.rs | 8 | ||||
-rw-r--r-- | src/lib.rs | 48 | ||||
-rw-r--r-- | src/options.rs | 20 | ||||
-rw-r--r-- | tests/expectations/tests/newtype-enum.rs | 24 | ||||
-rw-r--r-- | tests/headers/newtype-enum.hpp | 8 |
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, @@ -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, +}; |