Skip to content

Commit 5762339

Browse files
committed
Adds --constified-enum-module option per #699
1 parent 31c06fb commit 5762339

File tree

7 files changed

+181
-11
lines changed

7 files changed

+181
-11
lines changed

src/codegen/mod.rs

+67-7
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ use std::mem;
3636
use std::ops;
3737
use syntax::abi;
3838
use syntax::ast;
39-
use syntax::codemap::{Span, respan};
39+
use syntax::codemap::{DUMMY_SP, Span, respan};
4040
use syntax::ptr::P;
4141

42+
// Name of type defined in constified enum module
43+
pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &'static str = "Type";
44+
4245
fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize {
4346
if !ctx.options().enable_cxx_namespaces {
4447
return 0;
@@ -244,7 +247,6 @@ impl ForeignModBuilder {
244247
}
245248

246249
fn build(self, ctx: &BindgenContext) -> P<ast::Item> {
247-
use syntax::codemap::DUMMY_SP;
248250
P(ast::Item {
249251
ident: ctx.rust_ident(""),
250252
id: ast::DUMMY_NODE_ID,
@@ -2001,6 +2003,10 @@ enum EnumBuilder<'a> {
20012003
aster: P<ast::Item>,
20022004
},
20032005
Consts { aster: P<ast::Item> },
2006+
ModuleConsts {
2007+
module_name: &'a str,
2008+
module_items: Vec<P<ast::Item>>,
2009+
},
20042010
}
20052011

20062012
impl<'a> EnumBuilder<'a> {
@@ -2010,7 +2016,8 @@ impl<'a> EnumBuilder<'a> {
20102016
name: &'a str,
20112017
repr: P<ast::Ty>,
20122018
bitfield_like: bool,
2013-
constify: bool)
2019+
constify: bool,
2020+
constify_module: bool)
20142021
-> Self {
20152022
if bitfield_like {
20162023
EnumBuilder::Bitfield {
@@ -2022,8 +2029,20 @@ impl<'a> EnumBuilder<'a> {
20222029
.build(),
20232030
}
20242031
} else if constify {
2025-
EnumBuilder::Consts {
2026-
aster: aster.type_(name).build_ty(repr),
2032+
if constify_module {
2033+
let type_definition = aster::item::ItemBuilder::new()
2034+
.pub_()
2035+
.type_(CONSTIFIED_ENUM_MODULE_REPR_NAME)
2036+
.build_ty(repr);
2037+
2038+
EnumBuilder::ModuleConsts {
2039+
module_name: name,
2040+
module_items: vec![type_definition],
2041+
}
2042+
} else {
2043+
EnumBuilder::Consts {
2044+
aster: aster.type_(name).build_ty(repr),
2045+
}
20272046
}
20282047
} else {
20292048
EnumBuilder::Rust(aster.enum_(name))
@@ -2095,6 +2114,27 @@ impl<'a> EnumBuilder<'a> {
20952114
result.push(constant);
20962115
self
20972116
}
2117+
EnumBuilder::ModuleConsts { module_name, module_items, .. } => {
2118+
// Variant type
2119+
let inside_module_type =
2120+
aster::AstBuilder::new().ty().id(CONSTIFIED_ENUM_MODULE_REPR_NAME);
2121+
2122+
let constant = aster::AstBuilder::new()
2123+
.item()
2124+
.pub_()
2125+
.const_(&*variant_name)
2126+
.expr()
2127+
.build(expr)
2128+
.build(inside_module_type.clone());
2129+
2130+
let mut module_items = module_items.clone();
2131+
module_items.push(constant);
2132+
2133+
EnumBuilder::ModuleConsts {
2134+
module_name,
2135+
module_items,
2136+
}
2137+
}
20982138
}
20992139
}
21002140

@@ -2160,6 +2200,22 @@ impl<'a> EnumBuilder<'a> {
21602200
aster
21612201
}
21622202
EnumBuilder::Consts { aster, .. } => aster,
2203+
EnumBuilder::ModuleConsts { module_items, module_name, .. } => {
2204+
// Create module item with type and variant definitions
2205+
let module_item = P(ast::Item {
2206+
ident: ast::Ident::from_str(module_name),
2207+
attrs: vec![],
2208+
id: ast::DUMMY_NODE_ID,
2209+
node: ast::ItemKind::Mod(ast::Mod {
2210+
inner: DUMMY_SP,
2211+
items: module_items,
2212+
}),
2213+
vis: ast::Visibility::Public,
2214+
span: DUMMY_SP,
2215+
});
2216+
2217+
module_item
2218+
}
21632219
}
21642220
}
21652221
}
@@ -2225,7 +2281,10 @@ impl CodeGenerator for Enum {
22252281
.any(|v| ctx.options().bitfield_enums.matches(&v.name())))
22262282
};
22272283

2228-
let is_constified_enum = {
2284+
let is_constified_enum_module = self.is_constified_enum_module(ctx, item);
2285+
2286+
let is_constified_enum = {
2287+
is_constified_enum_module ||
22292288
ctx.options().constified_enums.matches(&name) ||
22302289
(enum_ty.name().is_none() &&
22312290
self.variants()
@@ -2300,7 +2359,8 @@ impl CodeGenerator for Enum {
23002359
&name,
23012360
repr,
23022361
is_bitfield,
2303-
is_constified_enum);
2362+
is_constified_enum,
2363+
is_constified_enum_module);
23042364

23052365
// A map where we keep a value -> variant relation.
23062366
let mut seen_values = HashMap::<_, String>::new();

src/ir/enum_ty.rs

+15
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ use super::item::Item;
55
use super::ty::TypeKind;
66
use clang;
77
use ir::annotations::Annotations;
8+
use ir::item::ItemCanonicalName;
89
use parse::{ClangItemParser, ParseError};
910

1011
/// An enum representing custom handling that can be given to a variant.
1112
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1213
pub enum EnumVariantCustomBehavior {
14+
/// This variant will be a module containing constants.
15+
ModuleConstify,
1316
/// This variant will be constified, that is, forced to generate a constant.
1417
Constify,
1518
/// This variant will be hidden entirely from the resulting enum.
@@ -121,6 +124,18 @@ impl Enum {
121124
});
122125
Ok(Enum::new(repr, variants))
123126
}
127+
128+
// Whether the enum should be an constified enum module
129+
pub fn is_constified_enum_module(&self, ctx: &BindgenContext, item: &Item) -> bool {
130+
let name = item.canonical_name(ctx);
131+
let enum_ty = item.expect_type();
132+
133+
ctx.options().constified_enum_modules.matches(&name) ||
134+
(enum_ty.name().is_none() &&
135+
self.variants()
136+
.iter()
137+
.any(|v| ctx.options().constified_enum_modules.matches(&v.name())))
138+
}
124139
}
125140

126141
/// A single enum variant, to be contained only in an enum.

src/ir/item.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Bindgen's core intermediate representation type.
22
3+
use super::super::codegen::CONSTIFIED_ENUM_MODULE_REPR_NAME;
34
use super::annotations::Annotations;
45
use super::context::{BindgenContext, ItemId, PartialType};
56
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
@@ -1444,6 +1445,15 @@ impl ItemCanonicalPath for Item {
14441445
ctx: &BindgenContext)
14451446
-> Vec<String> {
14461447
let path = self.canonical_path(ctx);
1448+
if let super::item_kind::ItemKind::Type(ref type_) = self.kind {
1449+
if let &TypeKind::Enum(ref enum_) = type_.kind() {
1450+
if enum_.is_constified_enum_module(ctx, self) {
1451+
// Type alias is inside a module
1452+
return vec![path.last().unwrap().clone(),
1453+
CONSTIFIED_ENUM_MODULE_REPR_NAME.into()];
1454+
}
1455+
}
1456+
}
14471457
if ctx.options().enable_cxx_namespaces {
14481458
return path;
14491459
}

src/lib.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,16 @@ impl Builder {
205205
})
206206
.count();
207207

208+
self.options
209+
.constified_enum_modules
210+
.get_items()
211+
.iter()
212+
.map(|item| {
213+
output_vector.push("--constified-enum-module".into());
214+
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
215+
})
216+
.count();
217+
208218
self.options
209219
.hidden_types
210220
.get_items()
@@ -562,8 +572,8 @@ impl Builder {
562572
self
563573
}
564574

565-
/// Mark the given enum (or set of enums, if using a pattern) as being
566-
/// constant.
575+
/// Mark the given enum (or set of enums, if using a pattern) as a set of
576+
/// constants.
567577
///
568578
/// This makes bindgen generate constants instead of enums. Regular
569579
/// expressions are supported.
@@ -572,6 +582,16 @@ impl Builder {
572582
self
573583
}
574584

585+
/// Mark the given enum (or set of enums, if using a pattern) as a set of
586+
/// constants that should be put into a module.
587+
///
588+
/// This makes bindgen generate a modules containing constants instead of
589+
/// enums. Regular expressions are supported.
590+
pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
591+
self.options.constified_enum_modules.insert(arg);
592+
self
593+
}
594+
575595
/// Add a string to prepend to the generated bindings. The string is passed
576596
/// through without any modification.
577597
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
@@ -813,6 +833,9 @@ pub struct BindgenOptions {
813833
/// The enum patterns to mark an enum as constant.
814834
pub constified_enums: RegexSet,
815835

836+
/// The enum patterns to mark an enum as a module of constants.
837+
pub constified_enum_modules: RegexSet,
838+
816839
/// Whether we should generate builtins or not.
817840
pub builtins: bool,
818841

@@ -935,6 +958,7 @@ impl BindgenOptions {
935958
self.hidden_types.build();
936959
self.opaque_types.build();
937960
self.bitfield_enums.build();
961+
self.constified_enum_modules.build();
938962
self.constified_enums.build();
939963
}
940964
}
@@ -949,6 +973,7 @@ impl Default for BindgenOptions {
949973
whitelisted_vars: Default::default(),
950974
bitfield_enums: Default::default(),
951975
constified_enums: Default::default(),
976+
constified_enum_modules: Default::default(),
952977
builtins: false,
953978
links: vec![],
954979
emit_ast: false,

src/options.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ pub fn builder_from_flags<I>
3333
.takes_value(true)
3434
.multiple(true)
3535
.number_of_values(1),
36+
Arg::with_name("constified-enum-module")
37+
.long("constified-enum-module")
38+
.help("Mark any enum whose name matches <regex> as a module of \
39+
constants instead of an enumeration. This option \
40+
implies \"--constified-enum.\"")
41+
.value_name("regex")
42+
.takes_value(true)
43+
.multiple(true)
44+
.number_of_values(1),
3645
Arg::with_name("blacklist-type")
3746
.long("blacklist-type")
3847
.help("Mark <type> as hidden.")
@@ -222,12 +231,17 @@ pub fn builder_from_flags<I>
222231
}
223232
}
224233

225-
if let Some(bitfields) = matches.values_of("constified-enum") {
226-
for regex in bitfields {
234+
if let Some(constifieds) = matches.values_of("constified-enum") {
235+
for regex in constifieds {
227236
builder = builder.constified_enum(regex);
228237
}
229238
}
230239

240+
if let Some(constified_mods) = matches.values_of("constified-enum-module") {
241+
for regex in constified_mods {
242+
builder = builder.constified_enum_module(regex);
243+
}
244+
}
231245
if let Some(hidden_types) = matches.values_of("blacklist-type") {
232246
for ty in hidden_types {
233247
builder = builder.hide_type(ty);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
pub mod foo {
8+
pub type Type = ::std::os::raw::c_uint;
9+
pub const THIS: Type = 0;
10+
pub const SHOULD_BE: Type = 1;
11+
pub const A_CONSTANT: Type = 2;
12+
}
13+
#[repr(C)]
14+
#[derive(Debug, Copy)]
15+
pub struct bar {
16+
pub this_should_work: foo::Type,
17+
}
18+
#[test]
19+
fn bindgen_test_layout_bar() {
20+
assert_eq!(::std::mem::size_of::<bar>() , 4usize , concat ! (
21+
"Size of: " , stringify ! ( bar ) ));
22+
assert_eq! (::std::mem::align_of::<bar>() , 4usize , concat ! (
23+
"Alignment of " , stringify ! ( bar ) ));
24+
assert_eq! (unsafe {
25+
& ( * ( 0 as * const bar ) ) . this_should_work as * const _
26+
as usize } , 0usize , concat ! (
27+
"Alignment of field: " , stringify ! ( bar ) , "::" ,
28+
stringify ! ( this_should_work ) ));
29+
}
30+
impl Clone for bar {
31+
fn clone(&self) -> Self { *self }
32+
}
33+
impl Default for bar {
34+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
35+
}

tests/headers/constify-module-enums.h

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// bindgen-flags: --constified-enum-module foo
2+
3+
enum foo {
4+
THIS,
5+
SHOULD_BE,
6+
A_CONSTANT,
7+
};
8+
9+
struct bar {
10+
enum foo this_should_work;
11+
};

0 commit comments

Comments
 (0)