static void struct_malloc(Struct* s) { if (s->rbPointer == Qnil) { s->rbPointer = rbffi_MemoryPointer_NewInstance(s->layout->size, 1, true); } else if (!rb_obj_is_kind_of(s->rbPointer, rbffi_AbstractMemoryClass)) { rb_raise(rb_eRuntimeError, "invalid pointer in struct"); } s->pointer = (AbstractMemory *) DATA_PTR(s->rbPointer); }
/* * call-seq: initialize_copy(other) * @return [nil] * DO NOT CALL THIS METHOD */ static VALUE struct_initialize_copy(VALUE self, VALUE other) { Struct* src; Struct* dst; Data_Get_Struct(self, Struct, dst); Data_Get_Struct(other, Struct, src); if (dst == src) { return self; } dst->rbLayout = src->rbLayout; dst->layout = src->layout; /* * A new MemoryPointer instance is allocated here instead of just calling * #dup on rbPointer, since the Pointer may not know its length, or may * be longer than just this struct. */ if (src->pointer->address != NULL) { dst->rbPointer = rbffi_MemoryPointer_NewInstance(1, src->layout->size, false); dst->pointer = MEMORY(dst->rbPointer); memcpy(dst->pointer->address, src->pointer->address, src->layout->size); } else { dst->rbPointer = src->rbPointer; dst->pointer = src->pointer; } if (src->layout->referenceFieldCount > 0) { dst->rbReferences = ALLOC_N(VALUE, dst->layout->referenceFieldCount); memcpy(dst->rbReferences, src->rbReferences, dst->layout->referenceFieldCount * sizeof(VALUE)); } return self; }
VALUE rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr) { switch (type->nativeType) { case NATIVE_VOID: return Qnil; case NATIVE_INT8: return INT2NUM((signed char) *(ffi_sarg *) ptr); case NATIVE_INT16: return INT2NUM((signed short) *(ffi_sarg *) ptr); case NATIVE_INT32: return INT2NUM((signed int) *(ffi_sarg *) ptr); case NATIVE_LONG: return LONG2NUM((signed long) *(ffi_sarg *) ptr); case NATIVE_INT64: return LL2NUM(*(signed long long *) ptr); case NATIVE_UINT8: return UINT2NUM((unsigned char) *(ffi_arg *) ptr); case NATIVE_UINT16: return UINT2NUM((unsigned short) *(ffi_arg *) ptr); case NATIVE_UINT32: return UINT2NUM((unsigned int) *(ffi_arg *) ptr); case NATIVE_ULONG: return ULONG2NUM((unsigned long) *(ffi_arg *) ptr); case NATIVE_UINT64: return ULL2NUM(*(unsigned long long *) ptr); case NATIVE_FLOAT32: return rb_float_new(*(float *) ptr); case NATIVE_FLOAT64: return rb_float_new(*(double *) ptr); case NATIVE_LONGDOUBLE: return rbffi_longdouble_new(*(long double *) ptr); case NATIVE_STRING: return (*(void **) ptr != NULL) ? rb_tainted_str_new2(*(char **) ptr) : Qnil; case NATIVE_POINTER: return rbffi_Pointer_NewInstance(*(void **) ptr); case NATIVE_BOOL: return ((unsigned char) *(ffi_arg *) ptr) ? Qtrue : Qfalse; case NATIVE_FUNCTION: case NATIVE_CALLBACK: { return *(void **) ptr != NULL ? rbffi_Function_NewInstance(rbType, rbffi_Pointer_NewInstance(*(void **) ptr)) : Qnil; } case NATIVE_STRUCT: { StructByValue* sbv = (StructByValue *)type; AbstractMemory* mem; VALUE rbMemory = rbffi_MemoryPointer_NewInstance(1, sbv->base.ffiType->size, false); Data_Get_Struct(rbMemory, AbstractMemory, mem); memcpy(mem->address, ptr, sbv->base.ffiType->size); RB_GC_GUARD(rbMemory); RB_GC_GUARD(rbType); return rb_class_new_instance(1, &rbMemory, sbv->rbStructClass); } case NATIVE_MAPPED: { /* * For mapped types, first convert to the real native type, then upcall to * ruby to convert to the expected return type */ MappedType* m = (MappedType *) type; VALUE values[2], rbReturnValue; values[0] = rbffi_NativeValue_ToRuby(m->type, m->rbType, ptr); values[1] = Qnil; rbReturnValue = rb_funcall2(m->rbConverter, id_from_native, 2, values); RB_GC_GUARD(values[0]); RB_GC_GUARD(rbType); return rbReturnValue; } default: rb_raise(rb_eRuntimeError, "Unknown type: %d", type->nativeType); return Qnil; } }