123456789_123456789_123456789_123456789_123456789_

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

Type - Inherited

Struct

Class Method Summary

Type - Inherited

Instance Method Summary

Type - Inherited

Constructor Details

.new(fields, size, align) .new(StructLayout)

[ GitHub ]

  
# 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)

[ GitHub ]

  
# File 'ext/ffi_c/StructLayout.c', line 591

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);
}

#[](field) #a(field)

[ GitHub ]

  
# File 'ext/ffi_c/StructLayout.c', line 557

static VALUE
struct_layout_union_bang(VALUE self)
{
    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;

    TypedData_Get_Struct(self, StructLayout, &rbffi_struct_layout_data_type, layout);

    for (i = 0; alignment_types[i] != NULL; ++i) {
        if (alignment_types[i]->alignment == layout->align) {
            t = (ffi_type *) alignment_types[i];
            break;
        }
    }
    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)

[ GitHub ]

  
# File 'ext/ffi_c/StructLayout.c', line 606

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)

[ GitHub ]

  
# File 'ext/ffi_c/StructLayout.c', line 621

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.

[ GitHub ]

  
# File 'lib/ffi/struct_layout.rb', line 46

def offset_of(field_name)
  self[field_name].offset
end

#offsetsArray<Array(Symbol, Integer)>

Get an array of tuples (field name, offset of the field).

Returns:

  • (Array<Array(Symbol, Integer)>)

    Array<Array(Symbol, Integer)>

[ GitHub ]

  
# File 'lib/ffi/struct_layout.rb', line 40

def offsets
  members.map { |m| [ m, self[m].offset ] }
end

#to_a ⇒ ? #an(array)

[ GitHub ]

  
# File 'ext/ffi_c/StructLayout.c', line 636

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);
}