| /* |
| * Copyright (c) 2008, 2009, Wayne Meissner |
| * Copyright (c) 2009, Luc Heinrich <luc@honk-honk.com> |
| * |
| * Copyright (c) 2008-2013, Ruby FFI project contributors |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of the Ruby FFI project nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <sys/types.h> |
| |
| #ifndef _MSC_VER |
| # include <sys/param.h> |
| # include <stdint.h> |
| # include <stdbool.h> |
| #else |
| # include "win32/stdbool.h" |
| # include "win32/stdint.h" |
| #endif |
| #include <ruby.h> |
| #include "rbffi.h" |
| #include "compat.h" |
| #include "AbstractMemory.h" |
| #include "Pointer.h" |
| #include "MemoryPointer.h" |
| #include "Function.h" |
| #include "Types.h" |
| #include "StructByValue.h" |
| #include "ArrayType.h" |
| #include "Function.h" |
| #include "MappedType.h" |
| #include "Struct.h" |
| |
| #define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) |
| |
| static void struct_layout_mark(StructLayout *); |
| static void struct_layout_free(StructLayout *); |
| static void struct_field_mark(StructField* ); |
| |
| VALUE rbffi_StructLayoutFieldClass = Qnil; |
| VALUE rbffi_StructLayoutNumberFieldClass = Qnil, rbffi_StructLayoutPointerFieldClass = Qnil; |
| VALUE rbffi_StructLayoutStringFieldClass = Qnil; |
| VALUE rbffi_StructLayoutFunctionFieldClass = Qnil, rbffi_StructLayoutArrayFieldClass = Qnil; |
| |
| VALUE rbffi_StructLayoutClass = Qnil; |
| |
| |
| static VALUE |
| struct_field_allocate(VALUE klass) |
| { |
| StructField* field; |
| VALUE obj; |
| |
| obj = Data_Make_Struct(klass, StructField, struct_field_mark, -1, field); |
| field->rbType = Qnil; |
| field->rbName = Qnil; |
| |
| return obj; |
| } |
| |
| static void |
| struct_field_mark(StructField* f) |
| { |
| rb_gc_mark(f->rbType); |
| rb_gc_mark(f->rbName); |
| } |
| |
| /* |
| * call-seq: initialize(name, offset, type) |
| * @param [String,Symbol] name |
| * @param [Fixnum] offset |
| * @param [FFI::Type] type |
| * @return [self] |
| * A new FFI::StructLayout::Field instance. |
| */ |
| static VALUE |
| struct_field_initialize(int argc, VALUE* argv, VALUE self) |
| { |
| VALUE rbOffset = Qnil, rbName = Qnil, rbType = Qnil; |
| StructField* field; |
| int nargs; |
| |
| Data_Get_Struct(self, StructField, field); |
| |
| nargs = rb_scan_args(argc, argv, "3", &rbName, &rbOffset, &rbType); |
| |
| if (TYPE(rbName) != T_SYMBOL && TYPE(rbName) != T_STRING) { |
| rb_raise(rb_eTypeError, "wrong argument type %s (expected Symbol/String)", |
| rb_obj_classname(rbName)); |
| } |
| |
| Check_Type(rbOffset, T_FIXNUM); |
| |
| if (!rb_obj_is_kind_of(rbType, rbffi_TypeClass)) { |
| rb_raise(rb_eTypeError, "wrong argument type %s (expected FFI::Type)", |
| rb_obj_classname(rbType)); |
| } |
| |
| field->offset = NUM2UINT(rbOffset); |
| field->rbName = (TYPE(rbName) == T_SYMBOL) ? rbName : rb_str_intern(rbName); |
| field->rbType = rbType; |
| Data_Get_Struct(field->rbType, Type, field->type); |
| field->memoryOp = get_memory_op(field->type); |
| field->referenceIndex = -1; |
| |
| switch (field->type->nativeType == NATIVE_MAPPED ? ((MappedType *) field->type)->type->nativeType : field->type->nativeType) { |
| case NATIVE_FUNCTION: |
| case NATIVE_CALLBACK: |
| case NATIVE_POINTER: |
| field->referenceRequired = true; |
| break; |
| |
| default: |
| field->referenceRequired = (rb_respond_to(self, rb_intern("reference_required?")) |
| && RTEST(rb_funcall2(self, rb_intern("reference_required?"), 0, NULL))) |
| || (rb_respond_to(rbType, rb_intern("reference_required?")) |
| && RTEST(rb_funcall2(rbType, rb_intern("reference_required?"), 0, NULL))); |
| break; |
| } |
| |
| return self; |
| } |
| |
| /* |
| * call-seq: offset |
| * @return [Numeric] |
| * Get the field offset. |
| */ |
| static VALUE |
| struct_field_offset(VALUE self) |
| { |
| StructField* field; |
| Data_Get_Struct(self, StructField, field); |
| return UINT2NUM(field->offset); |
| } |
| |
| /* |
| * call-seq: size |
| * @return [Numeric] |
| * Get the field size. |
| */ |
| static VALUE |
| struct_field_size(VALUE self) |
| { |
| StructField* field; |
| Data_Get_Struct(self, StructField, field); |
| return UINT2NUM(field->type->ffiType->size); |
| } |
| |
| /* |
| * call-seq: alignment |
| * @return [Numeric] |
| * Get the field alignment. |
| */ |
| static VALUE |
| struct_field_alignment(VALUE self) |
| { |
| StructField* field; |
| Data_Get_Struct(self, StructField, field); |
| return UINT2NUM(field->type->ffiType->alignment); |
| } |
| |
| /* |
| * call-seq: type |
| * @return [Type] |
| * Get the field type. |
| */ |
| static VALUE |
| struct_field_type(VALUE self) |
| { |
| StructField* field; |
| Data_Get_Struct(self, StructField, field); |
| |
| return field->rbType; |
| } |
| |
| /* |
| * call-seq: name |
| * @return [Symbol] |
| * Get the field name. |
| */ |
| static VALUE |
| struct_field_name(VALUE self) |
| { |
| StructField* field; |
| Data_Get_Struct(self, StructField, field); |
| return field->rbName; |
| } |
| |
| /* |
| * call-seq: get(pointer) |
| * @param [AbstractMemory] pointer pointer on a {Struct} |
| * @return [Object] |
| * Get an object of type {#type} from memory pointed by +pointer+. |
| */ |
| static VALUE |
| struct_field_get(VALUE self, VALUE pointer) |
| { |
| StructField* f; |
| |
| Data_Get_Struct(self, StructField, f); |
| if (f->memoryOp == NULL) { |
| rb_raise(rb_eArgError, "get not supported for %s", rb_obj_classname(f->rbType)); |
| return Qnil; |
| } |
| |
| return (*f->memoryOp->get)(MEMORY(pointer), f->offset); |
| } |
| |
| /* |
| * call-seq: put(pointer, value) |
| * @param [AbstractMemory] pointer pointer on a {Struct} |
| * @param [Object] value this object must be a kind of {#type} |
| * @return [self] |
| * Put an object to memory pointed by +pointer+. |
| */ |
| static VALUE |
| struct_field_put(VALUE self, VALUE pointer, VALUE value) |
| { |
| StructField* f; |
| |
| Data_Get_Struct(self, StructField, f); |
| if (f->memoryOp == NULL) { |
| rb_raise(rb_eArgError, "put not supported for %s", rb_obj_classname(f->rbType)); |
| return self; |
| } |
| |
| (*f->memoryOp->put)(MEMORY(pointer), f->offset, value); |
| |
| return self; |
| } |
| |
| /* |
| * call-seq: get(pointer) |
| * @param [AbstractMemory] pointer pointer on a {Struct} |
| * @return [Function] |
| * Get a {Function} from memory pointed by +pointer+. |
| */ |
| static VALUE |
| function_field_get(VALUE self, VALUE pointer) |
| { |
| StructField* f; |
| |
| Data_Get_Struct(self, StructField, f); |
| |
| return rbffi_Function_NewInstance(f->rbType, (*rbffi_AbstractMemoryOps.pointer->get)(MEMORY(pointer), f->offset)); |
| } |
| |
| /* |
| * call-seq: put(pointer, proc) |
| * @param [AbstractMemory] pointer pointer to a {Struct} |
| * @param [Function, Proc] proc |
| * @return [Function] |
| * Set a {Function} to memory pointed by +pointer+ as a function. |
| * |
| * If a Proc is submitted as +proc+, it is automatically transformed to a {Function}. |
| */ |
| static VALUE |
| function_field_put(VALUE self, VALUE pointer, VALUE proc) |
| { |
| StructField* f; |
| VALUE value = Qnil; |
| |
| Data_Get_Struct(self, StructField, f); |
| |
| if (NIL_P(proc) || rb_obj_is_kind_of(proc, rbffi_FunctionClass)) { |
| value = proc; |
| } else if (rb_obj_is_kind_of(proc, rb_cProc) || rb_respond_to(proc, rb_intern("call"))) { |
| value = rbffi_Function_ForProc(f->rbType, proc); |
| } else { |
| rb_raise(rb_eTypeError, "wrong type (expected Proc or Function)"); |
| } |
| |
| (*rbffi_AbstractMemoryOps.pointer->put)(MEMORY(pointer), f->offset, value); |
| |
| return self; |
| } |
| |
| static inline bool |
| isCharArray(ArrayType* arrayType) |
| { |
| return arrayType->componentType->nativeType == NATIVE_INT8 |
| || arrayType->componentType->nativeType == NATIVE_UINT8; |
| } |
| |
| /* |
| * call-seq: get(pointer) |
| * @param [AbstractMemory] pointer pointer on a {Struct} |
| * @return [FFI::StructLayout::CharArray, FFI::Struct::InlineArray] |
| * Get an array from a {Struct}. |
| */ |
| static VALUE |
| array_field_get(VALUE self, VALUE pointer) |
| { |
| StructField* f; |
| ArrayType* array; |
| VALUE argv[2]; |
| |
| Data_Get_Struct(self, StructField, f); |
| Data_Get_Struct(f->rbType, ArrayType, array); |
| |
| argv[0] = pointer; |
| argv[1] = self; |
| |
| return rb_class_new_instance(2, argv, isCharArray(array) |
| ? rbffi_StructLayoutCharArrayClass : rbffi_StructInlineArrayClass); |
| } |
| |
| /* |
| * call-seq: put(pointer, value) |
| * @param [AbstractMemory] pointer pointer on a {Struct} |
| * @param [String, Array] value +value+ may be a String only if array's type is a kind of +int8+ |
| * @return [value] |
| * Set an array in a {Struct}. |
| */ |
| static VALUE |
| array_field_put(VALUE self, VALUE pointer, VALUE value) |
| { |
| StructField* f; |
| ArrayType* array; |
| |
| |
| Data_Get_Struct(self, StructField, f); |
| Data_Get_Struct(f->rbType, ArrayType, array); |
| |
| if (isCharArray(array) && rb_obj_is_instance_of(value, rb_cString)) { |
| VALUE argv[2]; |
| |
| argv[0] = INT2FIX(f->offset); |
| argv[1] = value; |
| |
| rb_funcall2(pointer, rb_intern("put_string"), 2, argv); |
| |
| } else { |
| #ifdef notyet |
| MemoryOp* op; |
| int count = RARRAY_LEN(value); |
| int i; |
| AbstractMemory* memory = MEMORY(pointer); |
| |
| if (count > array->length) { |
| rb_raise(rb_eIndexError, "array too large"); |
| } |
| |
| /* clear the contents in case of a short write */ |
| checkWrite(memory); |
| checkBounds(memory, f->offset, f->type->ffiType->size); |
| if (count < array->length) { |
| memset(memory->address + f->offset + (count * array->componentType->ffiType->size), |
| 0, (array->length - count) * array->componentType->ffiType->size); |
| } |
| |
| /* now copy each element in */ |
| if ((op = get_memory_op(array->componentType)) != NULL) { |
| |
| for (i = 0; i < count; ++i) { |
| (*op->put)(memory, f->offset + (i * array->componentType->ffiType->size), rb_ary_entry(value, i)); |
| } |
| |
| } else if (array->componentType->nativeType == NATIVE_STRUCT) { |
| |
| for (i = 0; i < count; ++i) { |
| VALUE entry = rb_ary_entry(value, i); |
| Struct* s; |
| |
| if (!rb_obj_is_kind_of(entry, rbffi_StructClass)) { |
| rb_raise(rb_eTypeError, "array element not an instance of FFI::Struct"); |
| break; |
| } |
| |
| Data_Get_Struct(entry, Struct, s); |
| checkRead(s->pointer); |
| checkBounds(s->pointer, 0, array->componentType->ffiType->size); |
| |
| memcpy(memory->address + f->offset + (i * array->componentType->ffiType->size), |
| s->pointer->address, array->componentType->ffiType->size); |
| } |
| |
| } else { |
| rb_raise(rb_eNotImpError, "put not supported for arrays of type %s", rb_obj_classname(array->rbComponentType)); |
| } |
| #else |
| rb_raise(rb_eNotImpError, "cannot set array field"); |
| #endif |
| } |
| |
| return value; |
| } |
| |
| |
| static VALUE |
| struct_layout_allocate(VALUE klass) |
| { |
| StructLayout* layout; |
| VALUE obj; |
| |
| obj = Data_Make_Struct(klass, StructLayout, struct_layout_mark, struct_layout_free, layout); |
| layout->rbFieldMap = Qnil; |
| layout->rbFieldNames = Qnil; |
| layout->rbFields = Qnil; |
| layout->fieldSymbolTable = st_init_numtable(); |
| layout->base.ffiType = xcalloc(1, sizeof(*layout->base.ffiType)); |
| layout->base.ffiType->size = 0; |
| layout->base.ffiType->alignment = 0; |
| layout->base.ffiType->type = FFI_TYPE_STRUCT; |
| |
| return obj; |
| } |
| |
| /* |
| * call-seq: initialize(fields, size, align) |
| * @param [Array<StructLayout::Field>] fields |
| * @param [Numeric] size |
| * @param [Numeric] align |
| * @return [self] |
| * A new StructLayout instance. |
| */ |
| static VALUE |
| struct_layout_initialize(VALUE self, VALUE fields, VALUE size, VALUE align) |
| { |
| StructLayout* layout; |
| ffi_type* ltype; |
| int i; |
| |
| Data_Get_Struct(self, StructLayout, layout); |
| layout->fieldCount = (int) RARRAY_LEN(fields); |
| layout->rbFieldMap = rb_hash_new(); |
| 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 *)); |
| 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); |
| |
| Data_Get_Struct(rbField, StructField, 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; |
| st_insert(layout->fieldSymbolTable, rbName, rbField); |
| 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"); |
| } |
| |
| return self; |
| } |
| |
| /* |
| * call-seq: [](field) |
| * @param [Symbol] field |
| * @return [StructLayout::Field] |
| * Get a field from the layout. |
| */ |
| 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; |
| |
| Data_Get_Struct(self, StructLayout, 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; |
| } |
| |
| static VALUE |
| struct_layout_aref(VALUE self, VALUE field) |
| { |
| StructLayout* layout; |
| |
| Data_Get_Struct(self, StructLayout, layout); |
| |
| return rb_hash_aref(layout->rbFieldMap, field); |
| } |
| |
| /* |
| * call-seq: fields |
| * @return [Array<StructLayout::Field>] |
| * Get fields list. |
| */ |
| static VALUE |
| struct_layout_fields(VALUE self) |
| { |
| StructLayout* layout; |
| |
| Data_Get_Struct(self, StructLayout, layout); |
| |
| return rb_ary_dup(layout->rbFields); |
| } |
| |
| /* |
| * call-seq: members |
| * @return [Array<Symbol>] |
| * Get list of field names. |
| */ |
| static VALUE |
| struct_layout_members(VALUE self) |
| { |
| StructLayout* layout; |
| |
| Data_Get_Struct(self, StructLayout, layout); |
| |
| return rb_ary_dup(layout->rbFieldNames); |
| } |
| |
| /* |
| * call-seq: to_a |
| * @return [Array<StructLayout::Field>] |
| * Get an array of fields. |
| */ |
| static VALUE |
| struct_layout_to_a(VALUE self) |
| { |
| StructLayout* layout; |
| |
| Data_Get_Struct(self, StructLayout, layout); |
| |
| return rb_ary_dup(layout->rbFields); |
| } |
| |
| static void |
| struct_layout_mark(StructLayout *layout) |
| { |
| rb_gc_mark(layout->rbFieldMap); |
| rb_gc_mark(layout->rbFieldNames); |
| rb_gc_mark(layout->rbFields); |
| } |
| |
| static void |
| struct_layout_free(StructLayout *layout) |
| { |
| xfree(layout->ffiTypes); |
| xfree(layout->base.ffiType); |
| xfree(layout->fields); |
| st_free_table(layout->fieldSymbolTable); |
| xfree(layout); |
| } |
| |
| |
| void |
| rbffi_StructLayout_Init(VALUE moduleFFI) |
| { |
| VALUE ffi_Type = rbffi_TypeClass; |
| |
| /* |
| * Document-class: FFI::StructLayout < FFI::Type |
| * |
| * This class aims at defining a struct layout. |
| */ |
| rbffi_StructLayoutClass = rb_define_class_under(moduleFFI, "StructLayout", ffi_Type); |
| rb_global_variable(&rbffi_StructLayoutClass); |
| |
| /* |
| * Document-class: FFI::StructLayout::Field |
| * A field in a {StructLayout}. |
| */ |
| rbffi_StructLayoutFieldClass = rb_define_class_under(rbffi_StructLayoutClass, "Field", rb_cObject); |
| rb_global_variable(&rbffi_StructLayoutFieldClass); |
| |
| /* |
| * Document-class: FFI::StructLayout::Number |
| * A numeric {Field} in a {StructLayout}. |
| */ |
| rbffi_StructLayoutNumberFieldClass = rb_define_class_under(rbffi_StructLayoutClass, "Number", rbffi_StructLayoutFieldClass); |
| rb_global_variable(&rbffi_StructLayoutNumberFieldClass); |
| |
| /* |
| * Document-class: FFI::StructLayout::String |
| * A string {Field} in a {StructLayout}. |
| */ |
| rbffi_StructLayoutStringFieldClass = rb_define_class_under(rbffi_StructLayoutClass, "String", rbffi_StructLayoutFieldClass); |
| rb_global_variable(&rbffi_StructLayoutStringFieldClass); |
| |
| /* |
| * Document-class: FFI::StructLayout::Pointer |
| * A pointer {Field} in a {StructLayout}. |
| */ |
| rbffi_StructLayoutPointerFieldClass = rb_define_class_under(rbffi_StructLayoutClass, "Pointer", rbffi_StructLayoutFieldClass); |
| rb_global_variable(&rbffi_StructLayoutPointerFieldClass); |
| |
| /* |
| * Document-class: FFI::StructLayout::Function |
| * A function pointer {Field} in a {StructLayout}. |
| */ |
| rbffi_StructLayoutFunctionFieldClass = rb_define_class_under(rbffi_StructLayoutClass, "Function", rbffi_StructLayoutFieldClass); |
| rb_global_variable(&rbffi_StructLayoutFunctionFieldClass); |
| |
| /* |
| * Document-class: FFI::StructLayout::Array |
| * An array {Field} in a {StructLayout}. |
| */ |
| rbffi_StructLayoutArrayFieldClass = rb_define_class_under(rbffi_StructLayoutClass, "Array", rbffi_StructLayoutFieldClass); |
| rb_global_variable(&rbffi_StructLayoutArrayFieldClass); |
| |
| rb_define_alloc_func(rbffi_StructLayoutFieldClass, struct_field_allocate); |
| rb_define_method(rbffi_StructLayoutFieldClass, "initialize", struct_field_initialize, -1); |
| rb_define_method(rbffi_StructLayoutFieldClass, "offset", struct_field_offset, 0); |
| rb_define_method(rbffi_StructLayoutFieldClass, "size", struct_field_size, 0); |
| rb_define_method(rbffi_StructLayoutFieldClass, "alignment", struct_field_alignment, 0); |
| rb_define_method(rbffi_StructLayoutFieldClass, "name", struct_field_name, 0); |
| rb_define_method(rbffi_StructLayoutFieldClass, "type", struct_field_type, 0); |
| rb_define_method(rbffi_StructLayoutFieldClass, "put", struct_field_put, 2); |
| rb_define_method(rbffi_StructLayoutFieldClass, "get", struct_field_get, 1); |
| |
| rb_define_method(rbffi_StructLayoutFunctionFieldClass, "put", function_field_put, 2); |
| rb_define_method(rbffi_StructLayoutFunctionFieldClass, "get", function_field_get, 1); |
| |
| rb_define_method(rbffi_StructLayoutArrayFieldClass, "get", array_field_get, 1); |
| rb_define_method(rbffi_StructLayoutArrayFieldClass, "put", array_field_put, 2); |
| |
| rb_define_alloc_func(rbffi_StructLayoutClass, struct_layout_allocate); |
| rb_define_method(rbffi_StructLayoutClass, "initialize", struct_layout_initialize, 3); |
| rb_define_method(rbffi_StructLayoutClass, "[]", struct_layout_aref, 1); |
| 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); |
| |
| } |
| |