summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWayne Meissner <wmeissner@gmail.com>2012-05-09 14:25:28 +1000
committerWayne Meissner <wmeissner@gmail.com>2012-05-09 14:25:28 +1000
commit8e6dc8cddf21d6f9d0b680974aca086ae3b10368 (patch)
treee2be6ff5a752a6e271a7f2a83ef34bff01d76d08
parentded4bf6a4c687716cc6d928ac80f4dbebaa24533 (diff)
downloadffi-8e6dc8cddf21d6f9d0b680974aca086ae3b10368.tar.gz
Fix initialization of StructLayouts that are unions. Fixes #204.
-rw-r--r--ext/ffi_c/StructLayout.c37
-rw-r--r--lib/ffi/struct_layout_builder.rb4
2 files changed, 39 insertions, 2 deletions
diff --git a/ext/ffi_c/StructLayout.c b/ext/ffi_c/StructLayout.c
index e3e4abd..8b1299f 100644
--- a/ext/ffi_c/StructLayout.c
+++ b/ext/ffi_c/StructLayout.c
@@ -357,7 +357,7 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
layout->fieldCount = (int) RARRAY_LEN(fields);
layout->rbFieldMap = rb_hash_new();
layout->rbFieldNames = rb_ary_new2(layout->fieldCount);
- layout->size = NUM2INT(size);
+ layout->size = FFI_ALIGN(NUM2INT(size), NUM2INT(align));
layout->align = NUM2INT(align);
layout->fields = xcalloc(layout->fieldCount, sizeof(StructField *));
layout->ffiTypes = xcalloc(layout->fieldCount + 1, sizeof(ffi_type *));
@@ -411,6 +411,40 @@ struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
}
static VALUE
+struct_layout_union_bang(VALUE self)
+{
+ static const ffi_type *alignment_types[] = { &ffi_type_sint8, &ffi_type_sint16, &ffi_type_sint32, &ffi_type_sint64,
+ &ffi_type_float, &ffi_type_double, &ffi_type_longdouble, NULL };
+ StructLayout* layout;
+ ffi_type *t = NULL;
+ int count, i;
+
+ Data_Get_Struct(self, StructLayout, layout);
+
+ for (i = 0; alignment_types[i] != NULL; ++i) {
+ if (alignment_types[i]->alignment == layout->align) {
+ t = alignment_types[i];
+ break;
+ }
+ }
+ if (t == NULL) {
+ rb_raise(rb_eRuntimeError, "cannot create libffi union representation for alignment %d", layout->align);
+ return Qnil;
+ }
+
+ count = layout->size / t->size;
+ xfree(layout->ffiTypes);
+ layout->ffiTypes = xcalloc(count + 1, sizeof(ffi_type *));
+ layout->base.ffiType->elements = layout->ffiTypes;
+
+ for (i = 0; i < count; ++i) {
+ layout->ffiTypes[i] = t;
+ }
+
+ return self;
+}
+
+static VALUE
struct_layout_aref(VALUE self, VALUE field)
{
StructLayout* layout;
@@ -515,6 +549,7 @@ rbffi_StructLayout_Init(VALUE moduleFFI)
rb_define_method(rbffi_StructLayoutClass, "fields", struct_layout_fields, 0);
rb_define_method(rbffi_StructLayoutClass, "members", struct_layout_members, 0);
rb_define_method(rbffi_StructLayoutClass, "to_a", struct_layout_to_a, 0);
+ rb_define_method(rbffi_StructLayoutClass, "__union!", struct_layout_union_bang, 0);
}
diff --git a/lib/ffi/struct_layout_builder.rb b/lib/ffi/struct_layout_builder.rb
index 8b03384..4b942cc 100644
--- a/lib/ffi/struct_layout_builder.rb
+++ b/lib/ffi/struct_layout_builder.rb
@@ -108,7 +108,9 @@ module FFI
# Add tail padding if the struct is not packed
size = @packed ? @size : align(@size, @alignment)
- StructLayout.new(@fields, size, @alignment)
+ layout = StructLayout.new(@fields, size, @alignment)
+ layout.__union! if @union
+ layout
end
private