summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-01-11 03:07:26 -0800
committerGitHub <noreply@github.com>2017-01-11 03:07:26 -0800
commit6bfeae155155a12849033e1c5199ca6e48e8b22c (patch)
tree4b1a0e42b32238565eb3ab61e67623e13459a06f
parentdf043bf3dcc11bfd5c22cee5d3c6ba04d41c5f00 (diff)
parentfee7e96875f1d7c805a09e8ec8e02988de25e370 (diff)
Auto merge of #393 - emilio:enum-const-api, r=upsuper
Provide an API to constify enum variants. r? @upsuper
-rw-r--r--libbindgen/src/chooser.rs12
-rw-r--r--libbindgen/src/codegen/mod.rs28
-rw-r--r--libbindgen/src/ir/annotations.rs28
-rw-r--r--libbindgen/src/ir/context.rs6
-rw-r--r--libbindgen/src/ir/enum_ty.rs54
-rw-r--r--libbindgen/src/ir/var.rs4
-rw-r--r--libbindgen/tests/expectations/tests/constify-enum.rs20
-rw-r--r--libbindgen/tests/headers/constify-enum.h13
8 files changed, 153 insertions, 12 deletions
diff --git a/libbindgen/src/chooser.rs b/libbindgen/src/chooser.rs
index 10a77dc9..51392d70 100644
--- a/libbindgen/src/chooser.rs
+++ b/libbindgen/src/chooser.rs
@@ -1,6 +1,7 @@
//! A public API for more fine-grained customization of bindgen behavior.
pub use ir::int::IntKind;
+pub use ir::enum_ty::{EnumVariantValue, EnumVariantCustomBehavior};
use std::fmt;
/// A trait to allow configuring different kinds of types in different
@@ -11,4 +12,15 @@ pub trait TypeChooser: fmt::Debug {
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
None
}
+
+ /// This function should return whether, given the a given enum variant
+ /// name, and value, returns whether this enum variant will forcibly be a
+ /// constant.
+ fn enum_variant_behavior(&self,
+ _enum_name: Option<&str>,
+ _variant_name: &str,
+ _variant_value: EnumVariantValue)
+ -> Option<EnumVariantCustomBehavior> {
+ None
+ }
}
diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs
index c6d5fd39..6e63a791 100644
--- a/libbindgen/src/codegen/mod.rs
+++ b/libbindgen/src/codegen/mod.rs
@@ -1,6 +1,5 @@
mod helpers;
-
use aster;
use ir::annotations::FieldAccessorKind;
@@ -21,7 +20,7 @@ use self::helpers::{BlobTyBuilder, attributes};
use std::borrow::Cow;
use std::cell::Cell;
-use std::collections::HashSet;
+use std::collections::{HashSet, VecDeque};
use std::collections::hash_map::{Entry, HashMap};
use std::fmt::Write;
use std::iter;
@@ -1671,7 +1670,22 @@ impl CodeGenerator for Enum {
Some(&name)
};
- for variant in self.variants().iter() {
+ // NB: We defer the creation of constified variants, in case we find
+ // another variant with the same value (which is the common thing to
+ // do).
+ let mut constified_variants = VecDeque::new();
+
+ let mut iter = self.variants().iter().peekable();
+ while let Some(variant) = iter.next().or_else(|| constified_variants.pop_front()) {
+ if variant.hidden() {
+ continue;
+ }
+
+ if variant.force_constification() && iter.peek().is_some() {
+ constified_variants.push_back(variant);
+ continue;
+ }
+
match seen_values.entry(variant.val()) {
Entry::Occupied(ref entry) => {
if is_rust_enum {
@@ -1711,9 +1725,11 @@ impl CodeGenerator for Enum {
let variant_name = ctx.rust_mangle(variant.name());
- // If it's an unnamed enum, we also generate a constant so
- // it can be properly accessed.
- if is_rust_enum && enum_ty.name().is_none() {
+ // If it's an unnamed enum, or constification is enforced,
+ // we also generate a constant so it can be properly
+ // accessed.
+ if (is_rust_enum && enum_ty.name().is_none()) ||
+ variant.force_constification() {
let mangled_name = if is_toplevel {
variant_name.clone()
} else {
diff --git a/libbindgen/src/ir/annotations.rs b/libbindgen/src/ir/annotations.rs
index 3598c78c..98be0540 100644
--- a/libbindgen/src/ir/annotations.rs
+++ b/libbindgen/src/ir/annotations.rs
@@ -20,12 +20,17 @@ pub enum FieldAccessorKind {
}
/// Annotations for a given item, or a field.
+///
+/// You can see the kind of comments that are accepted in the Doxygen
+/// documentation:
+///
+/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
#[derive(Clone, PartialEq, Debug)]
pub struct Annotations {
/// Whether this item is marked as opaque. Only applies to types.
opaque: bool,
/// Whether this item should be hidden from the output. Only applies to
- /// types.
+ /// types, or enum variants.
hide: bool,
/// Whether this type should be replaced by another. The name is a
/// namespace-aware path.
@@ -39,6 +44,20 @@ pub struct Annotations {
/// The kind of accessor this field will have. Also can be applied to
/// structs so all the fields inside share it by default.
accessor_kind: Option<FieldAccessorKind>,
+ /// Whether this enum variant should be constified.
+ ///
+ /// This is controlled by the `constant` attribute, this way:
+ ///
+ /// ```cpp
+ /// enum Foo {
+ /// Bar = 0, /**< <div rustbindgen constant></div> */
+ /// Baz = 0,
+ /// };
+ /// ```
+ ///
+ /// In that case, bindgen will generate a constant for `Bar` instead of
+ /// `Baz`.
+ constify_enum_variant: bool,
}
fn parse_accessor(s: &str) -> FieldAccessorKind {
@@ -59,6 +78,7 @@ impl Default for Annotations {
disallow_copy: false,
private_fields: None,
accessor_kind: None,
+ constify_enum_variant: false,
}
}
}
@@ -150,6 +170,7 @@ impl Annotations {
"accessor" => {
self.accessor_kind = Some(parse_accessor(&attr.value))
}
+ "constant" => self.constify_enum_variant = true,
_ => {}
}
}
@@ -159,4 +180,9 @@ impl Annotations {
self.parse(&child, matched);
}
}
+
+ /// Returns whether we've parsed a "constant" attribute.
+ pub fn constify_enum_variant(&self) -> bool {
+ self.constify_enum_variant
+ }
}
diff --git a/libbindgen/src/ir/context.rs b/libbindgen/src/ir/context.rs
index e3dc3384..2d877920 100644
--- a/libbindgen/src/ir/context.rs
+++ b/libbindgen/src/ir/context.rs
@@ -2,6 +2,7 @@
use BindgenOptions;
use cexpr;
+use chooser::TypeChooser;
use clang::{self, Cursor};
use parse::ClangItemParser;
use std::borrow::Cow;
@@ -184,6 +185,11 @@ impl<'ctx> BindgenContext<'ctx> {
me
}
+ /// Get the user-provided type chooser by reference, if any.
+ pub fn type_chooser(&self) -> Option<&TypeChooser> {
+ self.options().type_chooser.as_ref().map(|t| &**t)
+ }
+
/// Define a new item.
///
/// This inserts it into the internal items set, and its type into the
diff --git a/libbindgen/src/ir/enum_ty.rs b/libbindgen/src/ir/enum_ty.rs
index 5c1ead45..ca4e77db 100644
--- a/libbindgen/src/ir/enum_ty.rs
+++ b/libbindgen/src/ir/enum_ty.rs
@@ -1,11 +1,21 @@
//! Intermediate representation for C/C++ enumerations.
use clang;
+use ir::annotations::Annotations;
use parse::{ClangItemParser, ParseError};
use super::context::{BindgenContext, ItemId};
use super::item::Item;
use super::ty::TypeKind;
+/// An enum representing custom handling that can be given to a variant.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum EnumVariantCustomBehavior {
+ /// This variant will be constified, that is, forced to generate a constant.
+ Constify,
+ /// This variant will be hidden entirely from the resulting enum.
+ Hide,
+}
+
/// A C/C++ enumeration.
#[derive(Debug)]
pub struct Enum {
@@ -66,6 +76,10 @@ impl Enum {
}
});
+ let type_name = ty.spelling();
+ let type_name = if type_name.is_empty() { None } else { Some(type_name) };
+ let type_name = type_name.as_ref().map(String::as_str);
+
declaration.visit(|cursor| {
if cursor.kind() == CXCursor_EnumConstantDecl {
let value = if is_signed {
@@ -75,8 +89,25 @@ impl Enum {
};
if let Some(val) = value {
let name = cursor.spelling();
+ let custom_behavior = ctx.type_chooser()
+ .and_then(|t| {
+ t.enum_variant_behavior(type_name, &name, val)
+ })
+ .or_else(|| {
+ Annotations::new(&cursor).and_then(|anno| {
+ if anno.hide() {
+ Some(EnumVariantCustomBehavior::Hide)
+ } else if anno.constify_enum_variant() {
+ Some(EnumVariantCustomBehavior::Constify)
+ } else {
+ None
+ }
+ })
+ });
+
let comment = cursor.raw_comment();
- variants.push(EnumVariant::new(name, comment, val));
+ variants.push(
+ EnumVariant::new(name, comment, val, custom_behavior));
}
}
CXChildVisit_Continue
@@ -96,6 +127,9 @@ pub struct EnumVariant {
/// The integer value of the variant.
val: EnumVariantValue,
+
+ /// The custom behavior this variant may have, if any.
+ custom_behavior: Option<EnumVariantCustomBehavior>,
}
/// A constant value assigned to an enumeration variant.
@@ -112,12 +146,14 @@ impl EnumVariant {
/// Construct a new enumeration variant from the given parts.
pub fn new(name: String,
comment: Option<String>,
- val: EnumVariantValue)
+ val: EnumVariantValue,
+ custom_behavior: Option<EnumVariantCustomBehavior>)
-> Self {
EnumVariant {
name: name,
comment: comment,
val: val,
+ custom_behavior: custom_behavior,
}
}
@@ -130,4 +166,18 @@ impl EnumVariant {
pub fn val(&self) -> EnumVariantValue {
self.val
}
+
+ /// Returns whether this variant should be enforced to be a constant by code
+ /// generation.
+ pub fn force_constification(&self) -> bool {
+ self.custom_behavior
+ .map_or(false, |b| b == EnumVariantCustomBehavior::Constify)
+ }
+
+ /// Returns whether the current variant should be hidden completely from the
+ /// resulting rust enum.
+ pub fn hidden(&self) -> bool {
+ self.custom_behavior
+ .map_or(false, |b| b == EnumVariantCustomBehavior::Hide)
+ }
}
diff --git a/libbindgen/src/ir/var.rs b/libbindgen/src/ir/var.rs
index e18af91b..329393fa 100644
--- a/libbindgen/src/ir/var.rs
+++ b/libbindgen/src/ir/var.rs
@@ -147,9 +147,7 @@ impl ClangSubItemParser for Var {
(TypeKind::Pointer(char_ty), VarType::String(val))
}
EvalResult::Int(Wrapping(value)) => {
- let kind = ctx.options()
- .type_chooser
- .as_ref()
+ let kind = ctx.type_chooser()
.and_then(|c| c.int_macro(&name, value))
.unwrap_or_else(|| {
if value < 0 {
diff --git a/libbindgen/tests/expectations/tests/constify-enum.rs b/libbindgen/tests/expectations/tests/constify-enum.rs
new file mode 100644
index 00000000..989c5197
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/constify-enum.rs
@@ -0,0 +1,20 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub const nsCSSPropertyID_eCSSProperty_COUNT_unexistingVariantValue:
+ nsCSSPropertyID =
+ nsCSSPropertyID::eCSSProperty_COUNT_unexistingVariantValue;
+pub const nsCSSPropertyID_eCSSProperty_COUNT: nsCSSPropertyID =
+ nsCSSPropertyID::eCSSPropertyAlias_aa;
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum nsCSSPropertyID {
+ eCSSProperty_a = 0,
+ eCSSProperty_b = 1,
+ eCSSPropertyAlias_aa = 2,
+ eCSSPropertyAlias_bb = 3,
+ eCSSProperty_COUNT_unexistingVariantValue = 4,
+}
diff --git a/libbindgen/tests/headers/constify-enum.h b/libbindgen/tests/headers/constify-enum.h
new file mode 100644
index 00000000..a5b4052c
--- /dev/null
+++ b/libbindgen/tests/headers/constify-enum.h
@@ -0,0 +1,13 @@
+
+enum nsCSSPropertyID {
+ eCSSProperty_a,
+ eCSSProperty_b,
+
+ eCSSProperty_COUNT, /**< <div rustbindgen constant></div> */
+ eCSSProperty_COUNT_DUMMY2 = eCSSProperty_COUNT - 1, /**< <div rustbindgen hide></div> */
+
+ eCSSPropertyAlias_aa,
+ eCSSPropertyAlias_bb,
+
+ eCSSProperty_COUNT_unexistingVariantValue, /**< <div rustbindgen constant></div> */
+};