summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <me@emiliocobos.me>2016-04-03 00:35:31 +0200
committerEmilio Cobos Álvarez <me@emiliocobos.me>2016-04-03 00:40:30 +0200
commite476eb500f7af3290d20175c34e9682d0c136fd0 (patch)
tree9cfa122dc029d031bd2b1d055e38c13a4b6f518d
parentb925d3ec6a5fc52dd8a00acef7a8062f346eed2d (diff)
gen: Make bitfields work for other types
-rw-r--r--src/gen.rs32
-rw-r--r--tests/headers/weird_bitfields.hpp2
2 files changed, 23 insertions, 11 deletions
diff --git a/src/gen.rs b/src/gen.rs
index 4869583f..017271d5 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -1,4 +1,5 @@
use std;
+use std::cmp;
use std::cell::RefCell;
use std::vec::Vec;
use std::rc::Rc;
@@ -1012,12 +1013,23 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
}
let (f_name, f_ty) = match f.bitfields {
- Some(_) => {
+ Some(ref v) => {
bitfields += 1;
- // XXX(emilio): This is probably wrong for most bitfields, where the with is
- // greater than 8. Should probably get the width of the bitfields and adjust
- // the generated type and layout based on that.
- (format!("_bitfield_{}", bitfields), TInt(IUChar, Layout::new(1, 1)))
+ // NOTE: We rely on the name of the type converted to rust types,
+ // and on the alignment.
+ let bits = v.iter().fold(0, |acc, &(_, w)| acc + w);
+
+ let layout_size = cmp::max(1, bits.next_power_of_two() / 8) as usize;
+ let name = match layout_size {
+ 1 => "uint8_t",
+ 2 => "uint16_t",
+ 4 => "uint32_t",
+ 8 => "uint64_t",
+ _ => panic!("bitfield width not supported: {}", layout_size),
+ };
+
+ let ty = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.to_owned(), ROOT_MODULE_ID, TVoid, Layout::new(layout_size, layout_size)))));
+ (format!("_bitfield_{}", bitfields), ty)
}
None => (rust_type_id(ctx, &f.name), f.ty.clone())
};
@@ -1619,19 +1631,18 @@ fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32, is_arg: bool) -> ast::T
}
fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str,
- field_name: &str, bitfield_type: &Type,
+ field_name: &str, field_type: &Type,
offset: usize, width: u32) -> ast::ImplItem {
let input_type = type_for_bitfield_width(ctx, width, true);
- let equivalent_field_type = type_for_bitfield_width(ctx, width, false);
- let field_type = cty_to_rs(ctx, &bitfield_type, false, true);
+ let field_type = cty_to_rs(ctx, &field_type, false, true);
let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", field_name));
let bindgen_ident = ctx.ext_cx.ident_of(bindgen_name);
let item = quote_item!(&ctx.ext_cx,
impl X {
pub fn $setter_name(&mut self, val: $input_type) {
- self.$bindgen_ident = ((self.$bindgen_ident as $equivalent_field_type) & !(((1 << $width) - 1) << $offset)) as $field_type;
- self.$bindgen_ident = ((self.$bindgen_ident as $equivalent_field_type) | ((val as $equivalent_field_type) << $offset)) as $field_type;
+ self.$bindgen_ident &= !(((1 << $width as $field_type) - 1) << $offset);
+ self.$bindgen_ident |= (val as $field_type) << $offset;
}
}
).unwrap();
@@ -1645,7 +1656,6 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &str,
fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
bitfield_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
let field_type = cty_to_rs(ctx, bitfield_type, false, true);
- let total_width = bitfields.iter().fold(0, |acc, &(_, w)| acc + w);
let mut args = vec!();
let mut unnamed: usize = 0;
for &(ref name, width) in bitfields.iter() {
diff --git a/tests/headers/weird_bitfields.hpp b/tests/headers/weird_bitfields.hpp
index 75024090..68cbf4a5 100644
--- a/tests/headers/weird_bitfields.hpp
+++ b/tests/headers/weird_bitfields.hpp
@@ -7,6 +7,8 @@ enum nsStyleSVGOpacitySource {
class Weird {
unsigned int mStrokeDasharrayLength;
+ unsigned int bitTest: 16;
+ unsigned int bitTest2: 15;
unsigned char mClipRule; // [inherited]
unsigned char mColorInterpolation; // [inherited] see nsStyleConsts.h
unsigned char mColorInterpolationFilters; // [inherited] see nsStyleConsts.h