summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Chambers <chris.chambers@peanutcode.com>2014-12-31 16:25:15 -0600
committerChristopher Chambers <chris.chambers@peanutcode.com>2014-12-31 16:43:04 -0600
commitfc0a9ab26a32344308d92407ec28ef43d155dc85 (patch)
tree192d0f36ccfa39ec0ba6c90bd624181bc66331d7
parent7fd76345505adde2eee8d63a92190f38d2a7c792 (diff)
Adds Default impls for generated composites.
gen.rs - Structs and unions now emit an implementation of the Default trait using std::mem::zeroed to create a zeroed instance. tests/support.rs - AST comparisons are now done on the pretty-printed version of the ASTs. Differences in AttrIds and some identifiers (generated with gensym to ensure uniqueness) made it unreliable to compare the ASTs directly. This way should work, even if it doesn't score many points for style. tests/* - Updated to use Default::default() where appropriate. - Eliminated a few warnings.
-rw-r--r--src/gen.rs16
-rw-r--r--tests/support.rs171
-rw-r--r--tests/test_builtins.rs8
-rw-r--r--tests/test_func.rs5
-rw-r--r--tests/test_struct.rs66
-rw-r--r--tests/test_union.rs27
6 files changed, 116 insertions, 177 deletions
diff --git a/src/gen.rs b/src/gen.rs
index 4d331c9e..0b2c7f5c 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -556,6 +556,8 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, members: Vec<CompMember>) -> Ve
vis: ast::Inherited,
span: ctx.span}));
}
+
+ items.push(mk_default_impl(ctx, name.as_slice()));
items.extend(extra.into_iter());
items
}
@@ -609,7 +611,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);
+ let union_id = rust_type_id(ctx, name.clone());
let union_attrs = vec!(mk_repr_attr(ctx), mk_deriving_copy_attr(ctx));
let union_def = mk_item(ctx, union_id, def, ast::Public, union_attrs);
@@ -625,6 +627,8 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec<Com
union_def,
mk_item(ctx, "".to_string(), union_impl, ast::Inherited, Vec::new())
);
+
+ items.push(mk_default_impl(ctx, name.as_slice()));
items.extend(extra.into_iter());
items
}
@@ -729,6 +733,16 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: uint,
methods
}
+// Implements std::default::Default using std::mem::zeroed.
+fn mk_default_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> {
+ let name_ident = ctx.ext_cx.ident_of(ty_name);
+ quote_item!(&ctx.ext_cx,
+ impl ::std::default::Default for $name_ident {
+ fn default() -> $name_ident { unsafe { ::std::mem::zeroed() } }
+ }
+ ).unwrap()
+}
+
fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::StructField_> {
let ty_name = match layout.align {
1 => "u8",
diff --git a/tests/support.rs b/tests/support.rs
index a9b6dc4d..d837786a 100644
--- a/tests/support.rs
+++ b/tests/support.rs
@@ -1,15 +1,15 @@
use bindgen;
use bindgen::{Logger, BindgenOptions};
+
use std::default::Default;
-use std::fmt;
-use syntax::ast;
-use syntax::print::pprust;
-use syntax::ptr::P;
+use syntax::ast;
use syntax::codemap;
use syntax::codemap::{Span, DUMMY_SP};
use syntax::parse;
use syntax::parse::token;
+use syntax::print::pprust;
+use syntax::ptr::P;
struct TestLogger;
@@ -33,10 +33,13 @@ pub fn generate_bindings(filename: &str) -> Result<Vec<P<ast::Item>>, ()> {
pub fn test_bind_eq(filename: &str, f:|ext_cx: DummyExtCtxt| -> Vec<Option<P<ast::Item>>>) {
let ext_cx = mk_dummy_ext_ctxt();
- let items = normalize_attr_ids(generate_bindings(filename).unwrap());
- let quoted = normalize_attr_ids(f(ext_cx).into_iter().map(|x| x.unwrap()).collect());
- assert_eq!(PrettyItems { items: items },
- PrettyItems { items: quoted });
+ let items = generate_bindings(filename).unwrap();
+ let quoted =f(ext_cx).into_iter().map(|x| x.unwrap()).collect();
+
+ // The ast::Items themselves have insignificant (for our purposes)
+ // differences that make them difficult to compare directly. So, compare
+ // rendered versions, which is not beautiful, but should work.
+ assert_eq!(render_items(&quoted), render_items(&items));
}
macro_rules! assert_bind_eq {
@@ -48,6 +51,17 @@ macro_rules! assert_bind_eq {
}
}
+fn render_items(items: &Vec<P<ast::Item>>) -> String {
+ pprust::to_string(|s| {
+ let module = ast::Mod {
+ inner: DUMMY_SP,
+ view_items: Vec::new(),
+ items: items.clone(),
+ };
+ s.print_mod(&module, &[])
+ })
+}
+
pub struct DummyExtCtxt {
sess: parse::ParseSess,
}
@@ -77,144 +91,3 @@ impl DummyExtCtxt {
fn mk_dummy_ext_ctxt<'a>() -> DummyExtCtxt {
DummyExtCtxt { sess: parse::new_parse_sess() }
}
-
-#[deriving(PartialEq)]
-struct PrettyItems {
- pub items: Vec<P<ast::Item>>,
-}
-
-impl fmt::Show for PrettyItems {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let output = pprust::to_string(|s| {
- let module = ast::Mod {
- inner: DUMMY_SP,
- view_items: Vec::new(),
- items: self.items.clone(),
- };
- s.print_mod(&module, &[])
- });
- write!(f, "\n{}\n", output)
- }
-}
-
-// libsyntax uses a thread-local variable to create unique AttrId values during
-// parsing and quoting. normalize_attr_ids makes sure that all AttrId values
-// for the passed `items` start at zero and proceed upward. This is necessary
-// to correctly compare otherwise-identical ASTs.
-fn normalize_attr_ids(items: Vec<P<ast::Item>>) -> Vec<P<ast::Item>> {
- use std::mem;
- use syntax::visit::*;
-
- struct Vis<'a> {
- attr_id: uint,
- items: Vec<P<ast::Item>>,
- }
-
- impl<'a> Vis<'a> {
- // TODO: visit_crate? ast::visit::Visitor does not deal with them directly,
- // but concievably, it could eventually come up.
-
- fn rewrite_attrs(&mut self, attrs: Vec<ast::Attribute>) -> Vec<ast::Attribute> {
- attrs.into_iter().map(|mut attr| {
- attr.node.id = ast::AttrId(self.attr_id);
- self.attr_id += 1;
- attr
- }).collect()
- }
- }
-
- unsafe fn force_mutable<T>(x: &T) -> &mut T {
- mem::transmute(x)
- }
-
- macro_rules! rewrite_attrs {
- ($self_:ident, $item:expr) => {
- unsafe {
- let unsafe_item = force_mutable($item);
- let new_attrs = mem::replace(&mut unsafe_item.attrs, vec!());
- let new_attrs = $self_.rewrite_attrs(new_attrs);
- mem::replace(&mut unsafe_item.attrs, new_attrs);
- }
- }
- }
-
- impl<'a, 'v> Visitor<'v> for Vis<'a> {
- fn visit_item(&mut self, i: &ast::Item) {
- rewrite_attrs!(self, i);
-
- match i.node {
- ast::ItemImpl(_, _, _, _, ref impl_items) => {
- for impl_item in impl_items.iter() {
- match *impl_item {
- ast::ImplItem::MethodImplItem(_) => { }
- ast::ImplItem::TypeImplItem(ref typedef) => {
- rewrite_attrs!(self, typedef.deref());
- }
- }
- }
- }
- _ => { }
- }
-
- walk_item(self, i);
- }
-
- fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
- rewrite_attrs!(self, i);
- walk_foreign_item(self, i);
- }
-
- fn visit_fn(&mut self, fk: FnKind, fd: &ast::FnDecl, b: &ast::Block, s: Span, _: ast::NodeId) {
- match fk {
- FkItemFn(_, _, _, _) | FkFnBlock => { }
- FkMethod(_, _, method) => {
- rewrite_attrs!(self, method);
- }
- }
- walk_fn(self, fk, fd, b, s);
- }
-
- fn visit_arm(&mut self, a: &ast::Arm) {
- rewrite_attrs!(self, a);
- walk_arm(self, a);
- }
-
- fn visit_ty_method(&mut self, t: &ast::TypeMethod) {
- rewrite_attrs!(self, t);
- walk_ty_method(self, t);
- }
-
- fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) {
- rewrite_attrs!(self, &v.node);
- walk_variant(self, v, g);
- }
-
- fn visit_view_item(&mut self, i: &ast::ViewItem) {
- rewrite_attrs!(self, i);
- walk_view_item(self, i);
- }
-
- fn visit_struct_field(&mut self, s: &ast::StructField) {
- rewrite_attrs!(self, &s.node);
- walk_struct_field(self, s);
- }
-
- fn visit_trait_item(&mut self, t: &ast::TraitItem) {
- match *t {
- ast::TraitItem::RequiredMethod(_) |
- ast::TraitItem::ProvidedMethod(_) => { }
- ast::TraitItem::TypeTraitItem(ref assoc_ty) => {
- rewrite_attrs!(self, assoc_ty.deref());
- }
- }
- walk_trait_item(self, t);
- }
- }
-
- let mut visitor = Vis { attr_id: 0, items: vec!() };
- for item in items.into_iter() {
- visitor.visit_item(item.deref());
- visitor.items.push(item);
- }
- visitor.items
-}
diff --git a/tests/test_builtins.rs b/tests/test_builtins.rs
index 35cd573c..1df562c8 100644
--- a/tests/test_builtins.rs
+++ b/tests/test_builtins.rs
@@ -1,12 +1,6 @@
-#![feature(phase)]
-
-#[phase(plugin)]
-extern crate bindgen;
-
-extern crate libc;
-
#[test]
fn test_builtin_va_list() {
+ #[allow(dead_code, non_camel_case_types, raw_pointer_deriving)]
mod ffi { bindgen!("headers/builtin_va_list.h", emit_builtins = true); }
// Should test for more than compilation.
}
diff --git a/tests/test_func.rs b/tests/test_func.rs
index 83bc2696..8a0f2584 100644
--- a/tests/test_func.rs
+++ b/tests/test_func.rs
@@ -22,6 +22,11 @@ fn func_ptr_in_struct() {
extern "C" fn(x: ::libc::c_int,
y: ::libc::c_int) -> Enum_baz>,
}
+ ),
+ quote_item!(cx,
+ impl ::std::default::Default for Struct_Foo {
+ fn default() -> Struct_Foo { unsafe { ::std::mem::zeroed() } }
+ }
)
);
}
diff --git a/tests/test_struct.rs b/tests/test_struct.rs
index 2d30174c..c6f6836f 100644
--- a/tests/test_struct.rs
+++ b/tests/test_struct.rs
@@ -1,7 +1,9 @@
+use std::default::Default;
+
#[test]
fn with_anon_struct() {
mod ffi { bindgen!("headers/struct_with_anon_struct.h"); }
- let mut x = ffi::Struct_foo { bar: ffi::Struct_Unnamed1 { a: 0, b: 0 } };
+ let mut x: ffi::Struct_foo = Default::default();
x.bar.a = 1;
x.bar.b = 2;
@@ -13,10 +15,7 @@ fn with_anon_struct() {
#[test]
fn with_anon_struct_array() {
mod ffi { bindgen!("headers/struct_with_anon_struct_array.h"); }
- let mut x = ffi::Struct_foo { bar: [
- ffi::Struct_Unnamed1 { a: 0, b: 0 },
- ffi::Struct_Unnamed1 { a: 1, b: 1 } ]
- };
+ let mut x: ffi::Struct_foo = Default::default();
x.bar[1].a = 1;
x.bar[1].b = 2;
@@ -27,11 +26,13 @@ fn with_anon_struct_array() {
#[test]
fn with_anon_struct_pointer() {
+ #[allow(raw_pointer_deriving)]
mod ffi { bindgen!("headers/struct_with_anon_struct_pointer.h"); }
- let mut unnamed = box ffi::Struct_Unnamed1 { a: 0, b: 0 };
+ let mut x: ffi::Struct_foo = Default::default();
+ let mut unnamed: ffi::Struct_Unnamed1 = Default::default();
unsafe {
- let mut x = ffi::Struct_foo { bar: ::std::mem::transmute(unnamed) };
+ x.bar = &mut unnamed;
(*x.bar).a = 1;
(*x.bar).b = 2;
@@ -46,7 +47,7 @@ fn with_anon_struct_pointer() {
#[test]
fn with_anon_union() {
mod ffi { bindgen!("headers/struct_with_anon_union.h"); }
- let mut x = ffi::Struct_foo { bar: ffi::Union_Unnamed1 { _bindgen_data_: [0] } };
+ let mut x: ffi::Struct_foo = Default::default();
unsafe {
*x.bar.a() = 0x12345678;
@@ -58,7 +59,7 @@ fn with_anon_union() {
#[test]
fn with_anon_unnamed_struct() {
mod ffi { bindgen!("headers/struct_with_anon_unnamed_struct.h"); }
- let mut x = ffi::Struct_foo { _bindgen_data_1_: [0, 0] };
+ let mut x: ffi::Struct_foo = Default::default();
unsafe {
*x.a() = 0x12345678;
@@ -71,7 +72,7 @@ fn with_anon_unnamed_struct() {
#[test]
fn with_anon_unnamed_union() {
mod ffi { bindgen!("headers/struct_with_anon_unnamed_union.h"); }
- let mut x = ffi::Struct_foo { _bindgen_data_1_: [0] };
+ let mut x: ffi::Struct_foo = Default::default();
unsafe {
*x.a() = 0x12345678;
@@ -83,7 +84,7 @@ fn with_anon_unnamed_union() {
#[test]
fn with_nesting() {
mod ffi { bindgen!("headers/struct_with_nesting.h"); }
- let mut x = ffi::Struct_foo { a: 0, _bindgen_data_1_: [0] };
+ let mut x: ffi::Struct_foo = Default::default();
unsafe {
x.a = 0x12345678;
@@ -111,12 +112,23 @@ fn containing_fwd_decl_struct() {
}
),
quote_item!(cx,
+ impl ::std::default::Default for Struct_a {
+ fn default() -> Struct_a { unsafe { ::std::mem::zeroed() } }
+ }
+ ),
+ quote_item!(cx,
#[repr(C)]
#[deriving(Copy)]
pub struct Struct_b {
pub val_b: ::libc::c_int,
}
- ));
+ ),
+ quote_item!(cx,
+ impl ::std::default::Default for Struct_b {
+ fn default() -> Struct_b { unsafe { ::std::mem::zeroed() } }
+ }
+ )
+ );
}
#[test]
@@ -133,7 +145,13 @@ fn with_unnamed_bitfields() {
pub unnamed_field2: ::libc::c_ushort,
pub d: ::libc::c_ushort,
}
- ));
+ ),
+ quote_item!(cx,
+ impl ::std::default::Default for Struct_bitfield {
+ fn default() -> Struct_bitfield { unsafe { ::std::mem::zeroed() } }
+ }
+ )
+ );
}
#[test]
@@ -143,6 +161,24 @@ fn with_fwd_decl_struct() {
let a = ffi::Struct_a { b: 1 };
let c = ffi::Struct_c { d: 1 };
- a.b;
- c.d;
+ assert_eq!(a.b, 1);
+ assert_eq!(c.d, 1);
+}
+
+#[test]
+fn default_impl() {
+ mod ffi { bindgen!("headers/struct_with_nesting.h"); }
+
+ let mut x: ffi::Struct_foo = Default::default();
+
+ unsafe {
+ assert_eq!(x.a, 0);
+ assert_eq!(*x.b(), 0);
+ assert_eq!(*x.c1(), 0);
+ assert_eq!(*x.c2(), 0);
+ assert_eq!(*x.d1(), 0);
+ assert_eq!(*x.d2(), 0);
+ assert_eq!(*x.d3(), 0);
+ assert_eq!(*x.d4(), 0);
+ }
}
diff --git a/tests/test_union.rs b/tests/test_union.rs
index 33a3713d..15759e7f 100644
--- a/tests/test_union.rs
+++ b/tests/test_union.rs
@@ -1,9 +1,11 @@
+use std::default::Default;
+
#[test]
fn with_anon_struct() {
// XXX: Rustc thinks that the anonymous struct, bar, is unused.
#[allow(dead_code)]
mod ffi { bindgen!("headers/union_with_anon_struct.h"); }
- let mut x = ffi::Union_foo { _bindgen_data_: [0, 0] };
+ let mut x: ffi::Union_foo = Default::default();
unsafe {
(*x.bar()).a = 0x12345678;
@@ -17,7 +19,7 @@ fn with_anon_struct() {
#[test]
fn with_anon_union() {
mod ffi { bindgen!("headers/union_with_anon_union.h"); }
- let mut x = ffi::Union_foo { _bindgen_data_: [0] };
+ let mut x: ffi::Union_foo = Default::default();
unsafe {
*(*x.bar()).a() = 0x12345678;
@@ -30,7 +32,7 @@ fn with_anon_union() {
#[test]
fn with_anon_unnamed_struct() {
mod ffi { bindgen!("headers/union_with_anon_unnamed_struct.h"); }
- let mut x = ffi::Union_pixel { _bindgen_data_: [0] };
+ let mut x: ffi::Union_pixel = Default::default();
unsafe {
*x.r() = 0xca;
@@ -49,7 +51,7 @@ fn with_anon_unnamed_struct() {
#[test]
fn with_anon_unnamed_union() {
mod ffi { bindgen!("headers/union_with_anon_unnamed_union.h"); }
- let mut x = ffi::Union_foo { _bindgen_data_: [0] };
+ let mut x: ffi::Union_foo = Default::default();
unsafe {
*x.a() = 0x12345678;
@@ -63,7 +65,7 @@ fn with_anon_unnamed_union() {
#[test]
fn with_nesting() {
mod ffi { bindgen!("headers/union_with_nesting.h"); }
- let mut x = ffi::Union_foo { _bindgen_data_: [0] };
+ let mut x: ffi::Union_foo = Default::default();
unsafe {
*x.a() = 0x12345678;
@@ -75,3 +77,18 @@ fn with_nesting() {
assert_eq!(*x.c2(), 0x1234);
}
}
+
+#[test]
+fn default_impl() {
+ mod ffi { bindgen!("headers/Union_with_nesting.h"); }
+
+ let mut x: ffi::Union_foo = Default::default();
+
+ unsafe {
+ assert_eq!(*x.a(), 0);
+ assert_eq!(*x.b1(), 0);
+ assert_eq!(*x.b2(), 0);
+ assert_eq!(*x.c1(), 0);
+ assert_eq!(*x.c2(), 0);
+ }
+}