diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index b6aabb1758..387ff49541 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -40,6 +40,7 @@ use ir::var::Var; use quote; use proc_macro2::{self, Term, Span}; +use std; use std::borrow::Cow; use std::cell::Cell; use std::collections::{HashSet, VecDeque}; @@ -2103,11 +2104,15 @@ impl MethodCodegen for Method { } /// A helper type that represents different enum variations. -#[derive(Copy, Clone)] -enum EnumVariation { +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum EnumVariation { + /// The code for this enum will use a Rust enum Rust, + /// The code for this enum will use a bitfield Bitfield, + /// The code for this enum will use consts Consts, + /// The code for this enum will use a module containing consts ModuleConsts } @@ -2136,6 +2141,31 @@ impl EnumVariation { } } +impl Default for EnumVariation { + fn default() -> EnumVariation { + EnumVariation::Consts + } +} + +impl std::str::FromStr for EnumVariation { + type Err = std::io::Error; + + /// Create a `EnumVariation` from a string. + fn from_str(s: &str) -> Result { + match s { + "rust" => Ok(EnumVariation::Rust), + "bitfield" => Ok(EnumVariation::Bitfield), + "consts" => Ok(EnumVariation::Consts), + "moduleconsts" => Ok(EnumVariation::ModuleConsts), + _ => Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, + concat!("Got an invalid EnumVariation. Accepted values ", + "are 'rust', 'bitfield', 'consts', and ", + "'moduleconsts'."))), + } + } +} + + /// A helper type to construct different enum variations. enum EnumBuilder<'a> { Rust { @@ -2491,8 +2521,7 @@ impl CodeGenerator for Enum { } else if self.is_rustified_enum(ctx, item) { EnumVariation::Rust } else { - // We generate consts by default - EnumVariation::Consts + ctx.options().default_enum_style }; let mut attrs = vec![]; diff --git a/src/lib.rs b/src/lib.rs index 9f90ffb77a..9a2d4f14e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,6 +83,7 @@ use ir::context::{BindgenContext, ItemId}; use ir::item::Item; use parse::{ClangItemParser, ParseError}; use regex_set::RegexSet; +pub use codegen::EnumVariation; use std::borrow::Cow; use std::collections::HashMap; @@ -203,6 +204,16 @@ impl Builder { output_vector.push("--rust-target".into()); output_vector.push(self.options.rust_target.into()); + if self.options.default_enum_style != Default::default() { + output_vector.push("--default-enum-variant=".into()); + output_vector.push(match self.options.default_enum_style { + codegen::EnumVariation::Rust => "rust", + codegen::EnumVariation::Bitfield => "bitfield", + codegen::EnumVariation::Consts => "consts", + codegen::EnumVariation::ModuleConsts => "moduleconsts", + }.into()) + } + self.options .bitfield_enums .get_items() @@ -729,6 +740,11 @@ impl Builder { self.whitelist_var(arg) } + /// Set the default style of code to generate for enums + pub fn default_enum_style(mut self, arg: codegen::EnumVariation) -> Builder { + self.options.default_enum_style = arg; + self + } /// Mark the given enum (or set of enums, if using a pattern) as being /// bitfield-like. Regular expressions are supported. @@ -1240,6 +1256,9 @@ struct BindgenOptions { /// Whitelisted variables. See docs for `whitelisted_types` for more. whitelisted_vars: RegexSet, + /// The default style of code to generate for enums + default_enum_style: codegen::EnumVariation, + /// The enum patterns to mark an enum as bitfield. bitfield_enums: RegexSet, @@ -1458,6 +1477,7 @@ impl Default for BindgenOptions { whitelisted_types: Default::default(), whitelisted_functions: Default::default(), whitelisted_vars: Default::default(), + default_enum_style: Default::default(), bitfield_enums: Default::default(), rustified_enums: Default::default(), constified_enum_modules: Default::default(), diff --git a/src/options.rs b/src/options.rs index b3ddbbfdb3..97b2556b7b 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,4 +1,4 @@ -use bindgen::{Builder, CodegenConfig, RUST_TARGET_STRINGS, RustTarget, builder}; +use bindgen::{Builder, CodegenConfig, RUST_TARGET_STRINGS, RustTarget, builder, EnumVariation}; use clap::{App, Arg}; use std::fs::File; use std::io::{self, Error, ErrorKind, Write, stderr}; @@ -26,6 +26,13 @@ where Arg::with_name("header") .help("C or C++ header file") .required(true), + Arg::with_name("default-enum-style") + .long("default-enum-style") + .help("The default style of code used to generate enums.") + .value_name("variant") + .default_value("consts") + .possible_values(&["consts", "moduleconsts", "bitfield", "rust"]) + .multiple(false), Arg::with_name("bitfield-enum") .long("bitfield-enum") .help("Mark any enum whose name matches as a set of \ @@ -303,6 +310,10 @@ where builder = builder.rust_target(RustTarget::from_str(rust_target)?); } + if let Some(variant) = matches.value_of("default-enum-style") { + builder = builder.default_enum_style(EnumVariation::from_str(variant)?) + } + if let Some(bitfields) = matches.values_of("bitfield-enum") { for regex in bitfields { builder = builder.bitfield_enum(regex); diff --git a/tests/expectations/tests/bitfield-32bit-overflow.rs b/tests/expectations/tests/bitfield-32bit-overflow.rs index f64299a6ab..7270649e6b 100644 --- a/tests/expectations/tests/bitfield-32bit-overflow.rs +++ b/tests/expectations/tests/bitfield-32bit-overflow.rs @@ -1,9 +1,7 @@ /* automatically generated by rust-bindgen */ - #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] - #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit diff --git a/tests/expectations/tests/bitfield_align.rs b/tests/expectations/tests/bitfield_align.rs index d7ee04456d..9821aa6fdf 100644 --- a/tests/expectations/tests/bitfield_align.rs +++ b/tests/expectations/tests/bitfield_align.rs @@ -1,9 +1,7 @@ /* automatically generated by rust-bindgen */ - #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] - #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit diff --git a/tests/expectations/tests/enum-default-bitfield.rs b/tests/expectations/tests/enum-default-bitfield.rs new file mode 100644 index 0000000000..19172d0b49 --- /dev/null +++ b/tests/expectations/tests/enum-default-bitfield.rs @@ -0,0 +1,44 @@ +/* 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(0); +} +impl Foo { + pub const Qux: Foo = Foo(1); +} +impl ::std::ops::BitOr for Foo { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + Foo(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for Foo { + #[inline] + fn bitor_assign(&mut self, rhs: Foo) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for Foo { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + Foo(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for Foo { + #[inline] + fn bitand_assign(&mut self, rhs: Foo) { + self.0 &= rhs.0; + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Foo(pub u32); +pub mod Neg { + pub type Type = i32; + pub const MinusOne: Type = -1; + pub const One: Type = 1; +} diff --git a/tests/expectations/tests/enum-default-consts.rs b/tests/expectations/tests/enum-default-consts.rs new file mode 100644 index 0000000000..6ced4de085 --- /dev/null +++ b/tests/expectations/tests/enum-default-consts.rs @@ -0,0 +1,12 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + +pub const Foo_Bar: Foo = 0; +pub const Foo_Qux: Foo = 1; +pub type Foo = u32; +pub mod Neg { + pub type Type = i32; + pub const MinusOne: Type = -1; + pub const One: Type = 1; +} diff --git a/tests/expectations/tests/enum-default-module.rs b/tests/expectations/tests/enum-default-module.rs new file mode 100644 index 0000000000..953793c378 --- /dev/null +++ b/tests/expectations/tests/enum-default-module.rs @@ -0,0 +1,14 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + +pub mod Foo { + pub type Type = u32; + pub const Bar: Type = 0; + pub const Qux: Type = 1; +} +pub mod Neg { + pub type Type = i32; + pub const MinusOne: Type = -1; + pub const One: Type = 1; +} diff --git a/tests/expectations/tests/enum-default-rust.rs b/tests/expectations/tests/enum-default-rust.rs new file mode 100644 index 0000000000..1400e37395 --- /dev/null +++ b/tests/expectations/tests/enum-default-rust.rs @@ -0,0 +1,15 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { + Bar = 0, + Qux = 1, +} +pub mod Neg { + pub type Type = i32; + pub const MinusOne: Type = -1; + pub const One: Type = 1; +} diff --git a/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs b/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs index 806b3f161d..81c32bbf33 100644 --- a/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs +++ b/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs @@ -1,9 +1,7 @@ /* automatically generated by rust-bindgen */ - #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] - #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit diff --git a/tests/expectations/tests/struct_with_bitfields.rs b/tests/expectations/tests/struct_with_bitfields.rs index 85f37e103b..a45472d5a9 100644 --- a/tests/expectations/tests/struct_with_bitfields.rs +++ b/tests/expectations/tests/struct_with_bitfields.rs @@ -1,9 +1,7 @@ /* automatically generated by rust-bindgen */ - #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] - #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit diff --git a/tests/headers/enum-default-bitfield.h b/tests/headers/enum-default-bitfield.h new file mode 100644 index 0000000000..be2841329b --- /dev/null +++ b/tests/headers/enum-default-bitfield.h @@ -0,0 +1,11 @@ +// bindgen-flags: --default-enum-style=bitfield --constified-enum-module=Neg + +enum Foo { + Bar = 0, + Qux +}; + +enum Neg { + MinusOne = -1, + One = 1, +}; diff --git a/tests/headers/enum-default-consts.h b/tests/headers/enum-default-consts.h new file mode 100644 index 0000000000..448c3030a8 --- /dev/null +++ b/tests/headers/enum-default-consts.h @@ -0,0 +1,11 @@ +// bindgen-flags: --default-enum-style=consts --constified-enum-module=Neg + +enum Foo { + Bar = 0, + Qux +}; + +enum Neg { + MinusOne = -1, + One = 1, +}; diff --git a/tests/headers/enum-default-module.h b/tests/headers/enum-default-module.h new file mode 100644 index 0000000000..a2f3d7adfd --- /dev/null +++ b/tests/headers/enum-default-module.h @@ -0,0 +1,11 @@ +// bindgen-flags: --default-enum-style=moduleconsts --constified-enum-module=Neg + +enum Foo { + Bar = 0, + Qux +}; + +enum Neg { + MinusOne = -1, + One = 1, +}; diff --git a/tests/headers/enum-default-rust.h b/tests/headers/enum-default-rust.h new file mode 100644 index 0000000000..282c62f3ff --- /dev/null +++ b/tests/headers/enum-default-rust.h @@ -0,0 +1,11 @@ +// bindgen-flags: --default-enum-style=rust --constified-enum-module=Neg + +enum Foo { + Bar = 0, + Qux +}; + +enum Neg { + MinusOne = -1, + One = 1, +};