summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/helpers.rs6
-rw-r--r--src/codegen/mod.rs46
-rw-r--r--src/ir/enum_ty.rs4
-rw-r--r--src/lib.rs33
-rw-r--r--src/options.rs2
5 files changed, 63 insertions, 28 deletions
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs
index b630a70b..1e8534ee 100644
--- a/src/codegen/helpers.rs
+++ b/src/codegen/helpers.rs
@@ -42,6 +42,12 @@ pub mod attributes {
}
}
+ pub fn non_exhaustive() -> TokenStream {
+ quote! {
+ #[non_exhaustive]
+ }
+ }
+
pub fn doc(comment: String) -> TokenStream {
// NOTE(emilio): By this point comments are already preprocessed and in
// `///` form. Quote turns them into `#[doc]` comments, but oh well.
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index ceb2f5b8..36206892 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -2170,7 +2170,10 @@ impl MethodCodegen for Method {
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum EnumVariation {
/// The code for this enum will use a Rust enum
- Rust,
+ ///
+ /// When the boolean parameter on this variant is set to true,
+ /// the generated enum should be non_exhaustive.
+ Rust(bool),
/// The code for this enum will use a bitfield
Bitfield,
/// The code for this enum will use consts
@@ -2182,14 +2185,7 @@ pub enum EnumVariation {
impl EnumVariation {
fn is_rust(&self) -> bool {
match *self {
- EnumVariation::Rust => true,
- _ => false
- }
- }
-
- fn is_bitfield(&self) -> bool {
- match *self {
- EnumVariation::Bitfield {..} => true,
+ EnumVariation::Rust(_) => true,
_ => false
}
}
@@ -2216,13 +2212,14 @@ impl std::str::FromStr for EnumVariation {
/// Create a `EnumVariation` from a string.
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
- "rust" => Ok(EnumVariation::Rust),
+ "rust" => Ok(EnumVariation::Rust(false)),
+ "rust_non_exhaustive" => Ok(EnumVariation::Rust(true)),
"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 ",
+ "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts', and ",
"'moduleconsts'."))),
}
}
@@ -2288,7 +2285,7 @@ impl<'a> EnumBuilder<'a> {
}
}
- EnumVariation::Rust => {
+ EnumVariation::Rust(_) => {
let tokens = quote!();
EnumBuilder::Rust {
codegen_depth: enum_codegen_depth + 1,
@@ -2580,15 +2577,22 @@ impl CodeGenerator for Enum {
let variation = self.computed_enum_variation(ctx, item);
// TODO(emilio): Delegate this to the builders?
- if variation.is_rust() {
- attrs.push(attributes::repr(repr_name));
- } else if variation.is_bitfield() {
- if ctx.options().rust_features.repr_transparent {
- attrs.push(attributes::repr("transparent"));
- } else {
- attrs.push(attributes::repr("C"));
- }
- }
+ match variation {
+ EnumVariation::Rust(non_exhaustive) => {
+ attrs.push(attributes::repr(repr_name));
+ if non_exhaustive {
+ attrs.push(attributes::non_exhaustive());
+ }
+ },
+ EnumVariation::Bitfield => {
+ if ctx.options().rust_features.repr_transparent {
+ attrs.push(attributes::repr("transparent"));
+ } else {
+ attrs.push(attributes::repr("C"));
+ }
+ },
+ _ => {},
+ };
if let Some(comment) = item.comment(ctx) {
attrs.push(attributes::doc(comment));
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index f3da2199..d4fbdf3a 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -164,7 +164,9 @@ impl Enum {
} else if self.is_matching_enum(ctx, &ctx.options().bitfield_enums, item) {
EnumVariation::Bitfield
} else if self.is_matching_enum(ctx, &ctx.options().rustified_enums, item) {
- EnumVariation::Rust
+ EnumVariation::Rust(false)
+ } else if self.is_matching_enum(ctx, &ctx.options().rustified_enums_non_exhaustive, item) {
+ EnumVariation::Rust(true)
} else if self.is_matching_enum(ctx, &ctx.options().constified_enums, item) {
EnumVariation::Consts
} else {
diff --git a/src/lib.rs b/src/lib.rs
index 4a695f60..26d15f1d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -226,7 +226,8 @@ impl Builder {
if self.options.default_enum_style != Default::default() {
output_vector.push("--default-enum-style=".into());
output_vector.push(match self.options.default_enum_style {
- codegen::EnumVariation::Rust => "rust",
+ codegen::EnumVariation::Rust(false) => "rust",
+ codegen::EnumVariation::Rust(true) => "rust_non_exhaustive",
codegen::EnumVariation::Bitfield => "bitfield",
codegen::EnumVariation::Consts => "consts",
codegen::EnumVariation::ModuleConsts => "moduleconsts",
@@ -254,6 +255,16 @@ impl Builder {
.count();
self.options
+ .rustified_enums_non_exhaustive
+ .get_items()
+ .iter()
+ .map(|item| {
+ output_vector.push("--rustified-enum-non-exhaustive".into());
+ output_vector.push(item.to_owned());
+ })
+ .count();
+
+ self.options
.constified_enum_modules
.get_items()
.iter()
@@ -810,15 +821,24 @@ impl Builder {
/// This makes bindgen generate enums instead of constants. Regular
/// expressions are supported.
///
- /// **Use this with caution.** You should not be using Rust enums unless
- /// you have complete control of the C/C++ code that you're binding to.
- /// Take a look at https://github.com/rust-lang/rust/issues/36927 for
- /// more information.
+ /// **Use this with caution,** you probably want to use the non_exhaustive
+ /// flavor of rust enums instead of this one. Take a look at
+ /// https://github.com/rust-lang/rust/issues/36927 for more information.
pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.rustified_enums.insert(arg);
self
}
+ /// Mark the given enum (or set of enums, if using a pattern) as a Rust
+ /// enum with the #[non_exhaustive] attribute.
+ ///
+ /// This makes bindgen generate enums instead of constants. Regular
+ /// expressions are supported.
+ pub fn rustified_enum_non_exhaustive<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.rustified_enums_non_exhaustive.insert(arg);
+ self
+ }
+
/// Mark the given enum (or set of enums, if using a pattern) as a set of
/// constants that are not to be put into a module.
pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
@@ -1367,6 +1387,8 @@ struct BindgenOptions {
/// The enum patterns to mark an enum as a Rust enum.
rustified_enums: RegexSet,
+ rustified_enums_non_exhaustive: RegexSet,
+
/// The enum patterns to mark an enum as a module of constants.
constified_enum_modules: RegexSet,
@@ -1620,6 +1642,7 @@ impl Default for BindgenOptions {
default_enum_style: Default::default(),
bitfield_enums: Default::default(),
rustified_enums: Default::default(),
+ rustified_enums_non_exhaustive: Default::default(),
constified_enums: Default::default(),
constified_enum_modules: Default::default(),
builtins: false,
diff --git a/src/options.rs b/src/options.rs
index 300036e0..43ad2edc 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -31,7 +31,7 @@ where
.help("The default style of code used to generate enums.")
.value_name("variant")
.default_value("consts")
- .possible_values(&["consts", "moduleconsts", "bitfield", "rust"])
+ .possible_values(&["consts", "moduleconsts", "bitfield", "rust", "rust_non_exhaustive"])
.multiple(false),
Arg::with_name("bitfield-enum")
.long("bitfield-enum")