Class: FFI::StructLayout
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
Type
|
|
|
Instance Chain:
self,
Type
|
|
| Inherits: | FFI::Type |
| Defined in: | ext/ffi_c/StructLayout.c, lib/ffi/struct_layout.rb |
Overview
This class aims at defining a struct layout.
Constant Summary
Class Method Summary
Instance Method Summary
- #[](field)
- #__union!
- #fields
- #members
-
#offset_of(field_name) ⇒ Integer
Get the offset of a field.
-
#offsets ⇒ Array<Array(Symbol, Integer)>
Get an array of tuples (field name, offset of the field).
- #to_a ⇒ ?
Type - Inherited
Constructor Details
.new(fields, size, align)
.new(StructLayout)
# File 'ext/ffi_c/StructLayout.c', line 482
static VALUE
struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align)
{
StructLayout* layout;
ffi_type* ltype;
int i;
TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
layout->fieldCount = RARRAY_LENINT(fields);
RB_OBJ_WRITE(self, &layout->rbFieldMap, rb_hash_new());
RB_OBJ_WRITE(self, &layout->rbFieldNames, rb_ary_new2(layout->fieldCount));
layout->size = (int) 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 *));
RB_OBJ_WRITE(self, &layout->rbFields, rb_ary_new2(layout->fieldCount));
layout->referenceFieldCount = 0;
layout->base.ffiType->elements = layout->ffiTypes;
layout->base.ffiType->size = layout->size;
layout->base.ffiType->alignment = layout->align;
ltype = layout->base.ffiType;
for (i = 0; i < (int) layout->fieldCount; ++i) {
VALUE rbField = rb_ary_entry(fields, i);
VALUE rbName;
StructField* field;
ffi_type* ftype;
if (!rb_obj_is_kind_of(rbField, rbffi_StructLayoutFieldClass)) {
rb_raise(rb_eTypeError, "wrong type for field %d.", i);
}
rbName = rb_funcall2(rbField, rb_intern("name"), 0, NULL);
TypedData_Get_Struct(rbField, StructField, &rbffi_struct_field_data_type, field);
layout->fields[i] = field;
if (field->type == NULL || field->type->ffiType == NULL) {
rb_raise(rb_eRuntimeError, "type of field %d not supported", i);
}
ftype = field->type->ffiType;
if (ftype->size == 0 && i < ((int) layout->fieldCount - 1)) {
rb_raise(rb_eTypeError, "type of field %d has zero size", i);
}
if (field->referenceRequired) {
field->referenceIndex = layout->referenceFieldCount++;
}
layout->ffiTypes[i] = ftype->size > 0 ? ftype : NULL;
rb_hash_aset(layout->rbFieldMap, rbName, rbField);
rb_ary_push(layout->rbFields, rbField);
rb_ary_push(layout->rbFieldNames, rbName);
}
if (ltype->size == 0) {
rb_raise(rb_eRuntimeError, "Struct size is zero");
}
rb_obj_freeze(layout->rbFieldMap);
rb_obj_freeze(layout->rbFields);
rb_obj_freeze(layout->rbFieldNames);
rb_obj_freeze(self);
return self;
}
Instance Method Details
#[](field)
#a(field)
# File 'ext/ffi_c/StructLayout.c', line 709
static VALUE
struct_layout_aref(VALUE self, VALUE field)
{
StructLayout* layout;
TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_hash_aref(layout->rbFieldMap, field);
}
#__union!
[ GitHub ]# File 'ext/ffi_c/StructLayout.c', line 632
static VALUE
struct_layout_union_bang(VALUE self)
{
StructLayout* layout;
ffi_type *t = NULL;
int count, i;
bool float_only = true;
const ffi_type *homogeneous = NULL;
TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
/*
* __union! replaces the real field types with a repeated filler type.
* The filler must be chosen so that libffi uses the same calling convention
* as the C compiler would for the real union.
*
* The rules vary by architecture:
*
* ARM64: A "Homogeneous Floating-point Aggregate" (HFA) is
* passed in floating-point registers (d0-d3). An HFA requires all members
* to be the *same* float type. {double, double} is an HFA; {float, double}
* is NOT. Non-HFAs use integer registers.
*
* x86_64 targets using the System V ABI (Linux/macOS/BSD, not Windows):
* an eightbyte containing only float/double fields is classified as SSE
* and passed in XMM registers, regardless of whether the float types are
* mixed. {float, double} is SSE; {int, double} is INTEGER.
*
* Strategy:
* 1. If all fields are the same float type, use that type directly.
* Correct on all platforms.
* 2. If fields are mixed float types (e.g. {float, double}):
* - On ARM64: not an HFA, use integer filler.
* - On x86_64 System V targets: still SSE class, use float filler.
* 3. Otherwise: use integer filler.
*/
homogeneous = find_homogeneous_leaf_type(layout->base.ffiType, &float_only);
if (homogeneous != NULL && float_only) {
/* Case 1: all fields are the same float type. */
t = (ffi_type *) homogeneous;
}
#if defined(__x86_64__) && !defined(_WIN32)
else if (float_only) {
/* Case 2: mixed float types use float filler on SysV x86_64. */
t = (ffi_type *) find_type_by_alignment(get_float_types(), layout->align);
}
#endif
if (t == NULL) {
/* Case 3: integer or mixed int/float — use integer filler */
t = (ffi_type *) find_type_by_alignment(get_int_types(), layout->align);
}
if (t == NULL) {
rb_raise(rb_eRuntimeError, "cannot create libffi union representation for alignment %d", layout->align);
return Qnil;
}
count = (int) layout->size / (int) 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;
}
#fields
#fields(list)
# File 'ext/ffi_c/StructLayout.c', line 724
static VALUE
struct_layout_fields(VALUE self)
{
StructLayout* layout;
TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_ary_dup(layout->rbFields);
}
#members
#list(of)
# File 'ext/ffi_c/StructLayout.c', line 739
static VALUE
struct_layout_members(VALUE self)
{
StructLayout* layout;
TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_ary_dup(layout->rbFieldNames);
}
#offset_of(field_name) ⇒ Integer
Get the offset of a field.
# File 'lib/ffi/struct_layout.rb', line 46
def offset_of(field_name) self[field_name].offset end
#offsets ⇒ Array<Array(Symbol, Integer)>
Get an array of tuples (field name, offset of the field).
# File 'lib/ffi/struct_layout.rb', line 40
def offsets members.map { |m| [ m, self[m].offset ] } end
#to_a ⇒ ?
#an(array)
# File 'ext/ffi_c/StructLayout.c', line 754
static VALUE
struct_layout_to_a(VALUE self)
{
StructLayout* layout;
TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);
return rb_ary_dup(layout->rbFields);
}