diff options
author | Travis Finkenauer <tmfinken@gmail.com> | 2017-06-11 13:26:13 -0700 |
---|---|---|
committer | Travis Finkenauer <tmfinken@gmail.com> | 2017-06-11 13:26:13 -0700 |
commit | 57623393fd47179c736c4a4add48a85391dd6fae (patch) | |
tree | 355e966e3889fe787db202025b84342bb0662db5 | |
parent | 31c06fb53e350e9eae8c1cfaab90bf857b1cc29e (diff) |
Adds `--constified-enum-module` option per #699
-rw-r--r-- | src/codegen/mod.rs | 74 | ||||
-rw-r--r-- | src/ir/enum_ty.rs | 15 | ||||
-rw-r--r-- | src/ir/item.rs | 10 | ||||
-rw-r--r-- | src/lib.rs | 29 | ||||
-rw-r--r-- | src/options.rs | 18 | ||||
-rw-r--r-- | tests/expectations/tests/constify-module-enums.rs | 35 | ||||
-rw-r--r-- | tests/headers/constify-module-enums.h | 11 |
7 files changed, 181 insertions, 11 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 86aafa39..8f9f0ee7 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -36,9 +36,12 @@ use std::mem; use std::ops; use syntax::abi; use syntax::ast; -use syntax::codemap::{Span, respan}; +use syntax::codemap::{DUMMY_SP, Span, respan}; use syntax::ptr::P; +// Name of type defined in constified enum module +pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &'static str = "Type"; + fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize { if !ctx.options().enable_cxx_namespaces { return 0; @@ -244,7 +247,6 @@ impl ForeignModBuilder { } fn build(self, ctx: &BindgenContext) -> P<ast::Item> { - use syntax::codemap::DUMMY_SP; P(ast::Item { ident: ctx.rust_ident(""), id: ast::DUMMY_NODE_ID, @@ -2001,6 +2003,10 @@ enum EnumBuilder<'a> { aster: P<ast::Item>, }, Consts { aster: P<ast::Item> }, + ModuleConsts { + module_name: &'a str, + module_items: Vec<P<ast::Item>>, + }, } impl<'a> EnumBuilder<'a> { @@ -2010,7 +2016,8 @@ impl<'a> EnumBuilder<'a> { name: &'a str, repr: P<ast::Ty>, bitfield_like: bool, - constify: bool) + constify: bool, + constify_module: bool) -> Self { if bitfield_like { EnumBuilder::Bitfield { @@ -2022,8 +2029,20 @@ impl<'a> EnumBuilder<'a> { .build(), } } else if constify { - EnumBuilder::Consts { - aster: aster.type_(name).build_ty(repr), + if constify_module { + let type_definition = aster::item::ItemBuilder::new() + .pub_() + .type_(CONSTIFIED_ENUM_MODULE_REPR_NAME) + .build_ty(repr); + + EnumBuilder::ModuleConsts { + module_name: name, + module_items: vec![type_definition], + } + } else { + EnumBuilder::Consts { + aster: aster.type_(name).build_ty(repr), + } } } else { EnumBuilder::Rust(aster.enum_(name)) @@ -2095,6 +2114,27 @@ impl<'a> EnumBuilder<'a> { result.push(constant); self } + EnumBuilder::ModuleConsts { module_name, module_items, .. } => { + // Variant type + let inside_module_type = + aster::AstBuilder::new().ty().id(CONSTIFIED_ENUM_MODULE_REPR_NAME); + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(&*variant_name) + .expr() + .build(expr) + .build(inside_module_type.clone()); + + let mut module_items = module_items.clone(); + module_items.push(constant); + + EnumBuilder::ModuleConsts { + module_name, + module_items, + } + } } } @@ -2160,6 +2200,22 @@ impl<'a> EnumBuilder<'a> { aster } EnumBuilder::Consts { aster, .. } => aster, + EnumBuilder::ModuleConsts { module_items, module_name, .. } => { + // Create module item with type and variant definitions + let module_item = P(ast::Item { + ident: ast::Ident::from_str(module_name), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::Mod(ast::Mod { + inner: DUMMY_SP, + items: module_items, + }), + vis: ast::Visibility::Public, + span: DUMMY_SP, + }); + + module_item + } } } } @@ -2225,7 +2281,10 @@ impl CodeGenerator for Enum { .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) }; - let is_constified_enum = { + let is_constified_enum_module = self.is_constified_enum_module(ctx, item); + + let is_constified_enum = { + is_constified_enum_module || ctx.options().constified_enums.matches(&name) || (enum_ty.name().is_none() && self.variants() @@ -2300,7 +2359,8 @@ impl CodeGenerator for Enum { &name, repr, is_bitfield, - is_constified_enum); + is_constified_enum, + is_constified_enum_module); // A map where we keep a value -> variant relation. let mut seen_values = HashMap::<_, String>::new(); diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs index e64354fb..3d326771 100644 --- a/src/ir/enum_ty.rs +++ b/src/ir/enum_ty.rs @@ -5,11 +5,14 @@ use super::item::Item; use super::ty::TypeKind; use clang; use ir::annotations::Annotations; +use ir::item::ItemCanonicalName; use parse::{ClangItemParser, ParseError}; /// 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 a module containing constants. + ModuleConstify, /// This variant will be constified, that is, forced to generate a constant. Constify, /// This variant will be hidden entirely from the resulting enum. @@ -121,6 +124,18 @@ impl Enum { }); Ok(Enum::new(repr, variants)) } + + // Whether the enum should be an constified enum module + pub fn is_constified_enum_module(&self, ctx: &BindgenContext, item: &Item) -> bool { + let name = item.canonical_name(ctx); + let enum_ty = item.expect_type(); + + ctx.options().constified_enum_modules.matches(&name) || + (enum_ty.name().is_none() && + self.variants() + .iter() + .any(|v| ctx.options().constified_enum_modules.matches(&v.name()))) + } } /// A single enum variant, to be contained only in an enum. diff --git a/src/ir/item.rs b/src/ir/item.rs index 6c118f54..735b3390 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -1,5 +1,6 @@ //! Bindgen's core intermediate representation type. +use super::super::codegen::CONSTIFIED_ENUM_MODULE_REPR_NAME; use super::annotations::Annotations; use super::context::{BindgenContext, ItemId, PartialType}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; @@ -1444,6 +1445,15 @@ impl ItemCanonicalPath for Item { ctx: &BindgenContext) -> Vec<String> { let path = self.canonical_path(ctx); + if let super::item_kind::ItemKind::Type(ref type_) = self.kind { + if let &TypeKind::Enum(ref enum_) = type_.kind() { + if enum_.is_constified_enum_module(ctx, self) { + // Type alias is inside a module + return vec![path.last().unwrap().clone(), + CONSTIFIED_ENUM_MODULE_REPR_NAME.into()]; + } + } + } if ctx.options().enable_cxx_namespaces { return path; } @@ -206,6 +206,16 @@ impl Builder { .count(); self.options + .constified_enum_modules + .get_items() + .iter() + .map(|item| { + output_vector.push("--constified-enum-module".into()); + output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); + }) + .count(); + + self.options .hidden_types .get_items() .iter() @@ -562,8 +572,8 @@ impl Builder { self } - /// Mark the given enum (or set of enums, if using a pattern) as being - /// constant. + /// Mark the given enum (or set of enums, if using a pattern) as a set of + /// constants. /// /// This makes bindgen generate constants instead of enums. Regular /// expressions are supported. @@ -572,6 +582,16 @@ impl Builder { self } + /// Mark the given enum (or set of enums, if using a pattern) as a set of + /// constants that should be put into a module. + /// + /// This makes bindgen generate a modules containing constants instead of + /// enums. Regular expressions are supported. + pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.constified_enum_modules.insert(arg); + self + } + /// Add a string to prepend to the generated bindings. The string is passed /// through without any modification. pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder { @@ -813,6 +833,9 @@ pub struct BindgenOptions { /// The enum patterns to mark an enum as constant. pub constified_enums: RegexSet, + /// The enum patterns to mark an enum as a module of constants. + pub constified_enum_modules: RegexSet, + /// Whether we should generate builtins or not. pub builtins: bool, @@ -935,6 +958,7 @@ impl BindgenOptions { self.hidden_types.build(); self.opaque_types.build(); self.bitfield_enums.build(); + self.constified_enum_modules.build(); self.constified_enums.build(); } } @@ -949,6 +973,7 @@ impl Default for BindgenOptions { whitelisted_vars: Default::default(), bitfield_enums: Default::default(), constified_enums: Default::default(), + constified_enum_modules: Default::default(), builtins: false, links: vec![], emit_ast: false, diff --git a/src/options.rs b/src/options.rs index bbf9c0dd..96f49849 100644 --- a/src/options.rs +++ b/src/options.rs @@ -33,6 +33,15 @@ pub fn builder_from_flags<I> .takes_value(true) .multiple(true) .number_of_values(1), + Arg::with_name("constified-enum-module") + .long("constified-enum-module") + .help("Mark any enum whose name matches <regex> as a module of \ + constants instead of an enumeration. This option \ + implies \"--constified-enum.\"") + .value_name("regex") + .takes_value(true) + .multiple(true) + .number_of_values(1), Arg::with_name("blacklist-type") .long("blacklist-type") .help("Mark <type> as hidden.") @@ -222,12 +231,17 @@ pub fn builder_from_flags<I> } } - if let Some(bitfields) = matches.values_of("constified-enum") { - for regex in bitfields { + if let Some(constifieds) = matches.values_of("constified-enum") { + for regex in constifieds { builder = builder.constified_enum(regex); } } + if let Some(constified_mods) = matches.values_of("constified-enum-module") { + for regex in constified_mods { + builder = builder.constified_enum_module(regex); + } + } if let Some(hidden_types) = matches.values_of("blacklist-type") { for ty in hidden_types { builder = builder.hide_type(ty); diff --git a/tests/expectations/tests/constify-module-enums.rs b/tests/expectations/tests/constify-module-enums.rs new file mode 100644 index 00000000..ca59236e --- /dev/null +++ b/tests/expectations/tests/constify-module-enums.rs @@ -0,0 +1,35 @@ +/* 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 = ::std::os::raw::c_uint; + pub const THIS: Type = 0; + pub const SHOULD_BE: Type = 1; + pub const A_CONSTANT: Type = 2; +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct bar { + pub this_should_work: foo::Type, +} +#[test] +fn bindgen_test_layout_bar() { + assert_eq!(::std::mem::size_of::<bar>() , 4usize , concat ! ( + "Size of: " , stringify ! ( bar ) )); + assert_eq! (::std::mem::align_of::<bar>() , 4usize , concat ! ( + "Alignment of " , stringify ! ( bar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const bar ) ) . this_should_work as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( bar ) , "::" , + stringify ! ( this_should_work ) )); +} +impl Clone for bar { + fn clone(&self) -> Self { *self } +} +impl Default for bar { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/headers/constify-module-enums.h b/tests/headers/constify-module-enums.h new file mode 100644 index 00000000..eb86844f --- /dev/null +++ b/tests/headers/constify-module-enums.h @@ -0,0 +1,11 @@ +// bindgen-flags: --constified-enum-module foo + +enum foo { + THIS, + SHOULD_BE, + A_CONSTANT, +}; + +struct bar { + enum foo this_should_work; +}; |