diff options
author | Wayne Meissner <wmeissner@gmail.com> | 2012-05-09 14:25:28 +1000 |
---|---|---|
committer | Wayne Meissner <wmeissner@gmail.com> | 2012-05-09 14:25:28 +1000 |
commit | 8e6dc8cddf21d6f9d0b680974aca086ae3b10368 (patch) | |
tree | e2be6ff5a752a6e271a7f2a83ef34bff01d76d08 | |
parent | ded4bf6a4c687716cc6d928ac80f4dbebaa24533 (diff) | |
download | ffi-8e6dc8cddf21d6f9d0b680974aca086ae3b10368.tar.gz |
Fix initialization of StructLayouts that are unions. Fixes #204.
-rw-r--r-- | ext/ffi_c/StructLayout.c | 37 | ||||
-rw-r--r-- | lib/ffi/struct_layout_builder.rb | 4 |
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 |