summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJyun-Yan You <jyyou.tw@gmail.com>2016-01-13 19:02:07 +0800
committerJyun-Yan You <jyyou.tw@gmail.com>2016-01-13 19:02:07 +0800
commitb40786aadd73b291a059a77dbcd11f075eef91c0 (patch)
tree6914302a29d79532978006e0d3c67565820ffc2c
parent6e33fbe74de0c38c68658cc51c6d8fe584691367 (diff)
parent8bf4a40b4805a4743233855bad1d6506ce7d5492 (diff)
Merge pull request #247 from nox/proper-enum
Translate C enums to Rust enums
-rw-r--r--src/gen.rs106
-rw-r--r--tests/headers/enum.h9
-rw-r--r--tests/headers/enum_dupe.h4
-rw-r--r--tests/headers/enum_explicit_type.hpp14
-rw-r--r--tests/headers/enum_negative.h4
-rw-r--r--tests/headers/enum_packed.h14
-rw-r--r--tests/support.rs3
-rw-r--r--tests/test_enum.rs53
-rw-r--r--tests/tests.rs1
9 files changed, 188 insertions, 20 deletions
diff --git a/src/gen.rs b/src/gen.rs
index c49cd0d5..a6ba4a4d 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -14,6 +14,7 @@ use syntax::ext::quote::rt::ToTokens;
use syntax::feature_gate::Features;
use syntax::owned_slice::OwnedSlice;
use syntax::parse;
+use syntax::parse::token::InternedString;
use syntax::attr::mk_attr_id;
use syntax::ptr::P;
use syntax::print::pprust::tts_to_string;
@@ -211,8 +212,8 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) ->
let mut e = ei.borrow_mut();
e.name = unnamed_name(&mut ctx, e.name.clone());
}
- let e = ei.borrow().clone();
- defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, e.items).into_iter())
+ let e = ei.borrow();
+ defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, &e.items).into_iter())
},
GVar(vi) => {
let v = vi.borrow();
@@ -476,8 +477,8 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, ty: &Type) -> Vec<P<ast::Item>
let is_empty = ei.borrow().name.is_empty();
if is_empty {
ei.borrow_mut().name = name.clone();
- let e = ei.borrow().clone();
- cenum_to_rs(ctx, name, e.kind, e.items)
+ let e = ei.borrow();
+ cenum_to_rs(ctx, name, e.kind, &e.items)
} else {
vec!(mk_item(ctx, name, ty))
}
@@ -555,7 +556,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
let id = rust_type_id(ctx, name.clone());
let struct_def = P(ast::Item { ident: ctx.ext_cx.ident_of(&id[..]),
- attrs: vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx)),
+ attrs: vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false)),
id: ast::DUMMY_NODE_ID,
node: def,
vis: ast::Public,
@@ -637,7 +638,7 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec<Com
empty_generics()
);
let union_id = rust_type_id(ctx, name.clone());
- let union_attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx));
+ let union_attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false));
let union_def = mk_item(ctx, union_id, def, ast::Public, union_attrs);
let union_impl = ast::ItemImpl(
@@ -682,18 +683,80 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a
})
}
-fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, items: Vec<EnumItem>) -> Vec<P<ast::Item>> {
- let ty = TInt(kind, Layout::zero());
- let ty_id = rust_type_id(ctx, name);
- let ty_def = ctypedef_to_rs(ctx, ty_id, &ty);
- let val_ty = cty_to_rs(ctx, &ty);
- let mut def = ty_def;
+fn enum_kind_to_rust_type_name(kind: IKind) -> &'static str {
+ match kind {
+ ISChar => "i8",
+ IUChar => "u8",
+ IShort => "i16",
+ IUShort => "u16",
+ IInt => "i32",
+ IUInt => "u32",
+ ILong => "i64",
+ IULong => "u64",
+ _ => unreachable!(),
+ }
+}
+
+fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, enum_items: &[EnumItem])
+ -> Vec<P<ast::Item>> {
+ let enum_name = ctx.ext_cx.ident_of(&name);
+ let enum_ty = ctx.ext_cx.ty_ident(ctx.span, enum_name);
+
+ let mut variants = vec![];
+ let mut found_values = HashMap::new();
+ let mut items = vec![];
+
+ for item in enum_items {
+ let name = ctx.ext_cx.ident_of(&item.name);
+
+ if let Some(orig) = found_values.get(&item.val) {
+ let value = ctx.ext_cx.expr_path(
+ ctx.ext_cx.path(ctx.span, vec![enum_name, *orig]));
+ items.push(P(ast::Item {
+ ident: name,
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemConst(enum_ty.clone(), value),
+ vis: ast::Public,
+ span: ctx.span,
+ }));
+ continue;
+ }
+
+ found_values.insert(item.val, name);
+
+ let sign = ast::UnsuffixedIntLit(if item.val < 0 { ast::Minus } else { ast::Plus });
+ let value = ctx.ext_cx.expr_lit(ctx.span, ast::LitInt(item.val.abs() as u64, sign));
- for it in items.iter() {
- def.push(const_to_rs(ctx, it.name.clone(), it.val, val_ty.clone()));
+ variants.push(P(respan(ctx.span, ast::Variant_ {
+ name: name,
+ attrs: vec![],
+ data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
+ disr_expr: Some(value),
+ })));
}
- return def;
+ let enum_repr = InternedString::new(enum_kind_to_rust_type_name(kind));
+
+ let repr_arg = ctx.ext_cx.meta_word(ctx.span, enum_repr);
+ let repr_list = ctx.ext_cx.meta_list(ctx.span, InternedString::new("repr"), vec![repr_arg]);
+ let repr_attr = respan(ctx.span, ast::Attribute_ {
+ id: mk_attr_id(),
+ style: ast::AttrStyle::Outer,
+ value: repr_list,
+ is_sugared_doc: false,
+ });
+
+ items.push(P(ast::Item {
+ ident: enum_name,
+ attrs: vec![mk_deriving_copy_attr(ctx, true), repr_attr],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemEnum(ast::EnumDef { variants: variants }, empty_generics()),
+ vis: ast::Public,
+ span: ctx.span,
+ }));
+
+ items
}
/// Generates accessors for fields in nested structs and unions which must be
@@ -848,11 +911,14 @@ fn mk_repr_attr(ctx: &mut GenCtx, layout: Layout) -> ast::Attribute {
})
}
-fn mk_deriving_copy_attr(ctx: &mut GenCtx) -> ast::Attribute {
- let attr_val = P(respan(ctx.span, ast::MetaList(
- to_intern_str(ctx, "derive".to_string()),
- vec!(P(respan(ctx.span, ast::MetaWord(to_intern_str(ctx, "Copy".to_string())))))
- )));
+fn mk_deriving_copy_attr(ctx: &mut GenCtx, clone: bool) -> ast::Attribute {
+ let mut words = vec!();
+ if clone {
+ words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Clone")));
+ }
+ words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Copy")));
+
+ let attr_val = ctx.ext_cx.meta_list(ctx.span, InternedString::new("derive"), words);
respan(ctx.span, ast::Attribute_ {
id: mk_attr_id(),
diff --git a/tests/headers/enum.h b/tests/headers/enum.h
new file mode 100644
index 00000000..f2d301e7
--- /dev/null
+++ b/tests/headers/enum.h
@@ -0,0 +1,9 @@
+enum Foo {
+ Bar = 0,
+ Qux
+};
+
+enum Neg {
+ MinusOne = -1,
+ One = 1,
+};
diff --git a/tests/headers/enum_dupe.h b/tests/headers/enum_dupe.h
new file mode 100644
index 00000000..6d3591d5
--- /dev/null
+++ b/tests/headers/enum_dupe.h
@@ -0,0 +1,4 @@
+enum Foo {
+ Bar = 1,
+ Dupe = 1
+};
diff --git a/tests/headers/enum_explicit_type.hpp b/tests/headers/enum_explicit_type.hpp
new file mode 100644
index 00000000..6aa5103d
--- /dev/null
+++ b/tests/headers/enum_explicit_type.hpp
@@ -0,0 +1,14 @@
+enum Foo: unsigned char {
+ Bar = 0,
+ Qux
+};
+
+enum Neg: char {
+ MinusOne = -1,
+ One = 1,
+};
+
+enum Bigger: unsigned short {
+ Much = 255,
+ Larger
+};
diff --git a/tests/headers/enum_negative.h b/tests/headers/enum_negative.h
new file mode 100644
index 00000000..6cbdfe04
--- /dev/null
+++ b/tests/headers/enum_negative.h
@@ -0,0 +1,4 @@
+enum Foo {
+ Bar = -2,
+ Qux = 1,
+};
diff --git a/tests/headers/enum_packed.h b/tests/headers/enum_packed.h
new file mode 100644
index 00000000..8654d110
--- /dev/null
+++ b/tests/headers/enum_packed.h
@@ -0,0 +1,14 @@
+enum __attribute__((packed)) Foo {
+ Bar = 0,
+ Qux
+};
+
+enum __attribute__((packed)) Neg {
+ MinusOne = -1,
+ One = 1,
+};
+
+enum __attribute__((packed)) Bigger {
+ Much = 255,
+ Larger
+};
diff --git a/tests/support.rs b/tests/support.rs
index dd414649..94cdf952 100644
--- a/tests/support.rs
+++ b/tests/support.rs
@@ -25,6 +25,9 @@ impl Logger for TestLogger {
pub fn generate_bindings(filename: &str) -> Result<Vec<P<ast::Item>>, ()> {
let mut options:BindgenOptions = Default::default();
+ if filename.ends_with("hpp") {
+ options.clang_args.push("-std=c++11".to_string());
+ }
options.clang_args.push(filename.to_string());
let logger = TestLogger;
diff --git a/tests/test_enum.rs b/tests/test_enum.rs
new file mode 100644
index 00000000..2b94f3b4
--- /dev/null
+++ b/tests/test_enum.rs
@@ -0,0 +1,53 @@
+use support::assert_bind_eq;
+
+#[test]
+fn with_simple_enum() {
+ assert_bind_eq("headers/enum.h", "
+ #[derive(Clone, Copy)]
+ #[repr(u32)]
+ pub enum Enum_Foo { Bar = 0, Qux = 1, }
+ #[derive(Clone, Copy)]
+ #[repr(i32)]
+ pub enum Enum_Neg { MinusOne = -1, One = 1, }
+ ");
+}
+
+#[test]
+fn with_packed_enums() {
+ assert_bind_eq("headers/enum_packed.h", "
+ #[derive(Clone, Copy)]
+ #[repr(u8)]
+ pub enum Enum_Foo { Bar = 0, Qux = 1, }
+ #[derive(Clone, Copy)]
+ #[repr(i8)]
+ pub enum Enum_Neg { MinusOne = -1, One = 1, }
+ #[derive(Clone, Copy)]
+ #[repr(u16)]
+ pub enum Enum_Bigger { Much = 255, Larger = 256, }
+ ");
+}
+
+#[test]
+fn with_duplicate_enum_value() {
+ assert_bind_eq("headers/enum_dupe.h", "
+ pub const Dupe: Enum_Foo = Enum_Foo::Bar;
+ #[derive(Clone, Copy)]
+ #[repr(u32)]
+ pub enum Enum_Foo { Bar = 1, }
+ ");
+}
+
+#[test]
+fn with_explicitly_typed_cxx_enum() {
+ assert_bind_eq("headers/enum_explicit_type.hpp", "
+ #[derive(Clone, Copy)]
+ #[repr(u8)]
+ pub enum Enum_Foo { Bar = 0, Qux = 1, }
+ #[derive(Clone, Copy)]
+ #[repr(i8)]
+ pub enum Enum_Neg { MinusOne = -1, One = 1, }
+ #[derive(Clone, Copy)]
+ #[repr(u16)]
+ pub enum Enum_Bigger { Much = 255, Larger = 256, }
+ ");
+}
diff --git a/tests/tests.rs b/tests/tests.rs
index b9a4f61c..ea9350f9 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -8,6 +8,7 @@ mod support;
// Unused until we can generate code for tests
//mod test_cmath;
+mod test_enum;
mod test_decl;
mod test_func;
mod test_struct;