VALUE rbffi_Function_ForProc(VALUE rbFunctionInfo, VALUE proc) { VALUE callback, cbref, cbTable; Function* fp; cbref = RTEST(rb_ivar_defined(proc, id_cb_ref)) ? rb_ivar_get(proc, id_cb_ref) : Qnil; /* If the first callback reference has the same function function signature, use it */ if (cbref != Qnil && CLASS_OF(cbref) == rbffi_FunctionClass) { Data_Get_Struct(cbref, Function, fp); if (fp->rbFunctionInfo == rbFunctionInfo) { return cbref; } } cbTable = RTEST(rb_ivar_defined(proc, id_cbtable)) ? rb_ivar_get(proc, id_cbtable) : Qnil; if (cbTable != Qnil && (callback = rb_hash_aref(cbTable, rbFunctionInfo)) != Qnil) { return callback; } /* No existing function for the proc with that signature, create a new one and cache it */ callback = rbffi_Function_NewInstance(rbFunctionInfo, proc); if (cbref == Qnil) { /* If there is no other cb already cached for this proc, we can use the ivar slot */ rb_ivar_set(proc, id_cb_ref, callback); } else { /* The proc instance has been used as more than one type of callback, store extras in a hash */ cbTable = rb_hash_new(); rb_ivar_set(proc, id_cbtable, cbTable); rb_hash_aset(cbTable, rbFunctionInfo, callback); } return callback; }
/* * 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)); }
VALUE rbffi_Function_ForProc(VALUE rbFunctionInfo, VALUE proc) { VALUE callback; VALUE cbTable = RTEST(rb_ivar_defined(proc, id_cbtable)) ? rb_ivar_get(proc, id_cbtable) : Qnil; if (cbTable == Qnil) { cbTable = rb_hash_new(); rb_ivar_set(proc, id_cbtable, cbTable); } callback = rb_hash_aref(cbTable, rbFunctionInfo); if (callback != Qnil) { return callback; } callback = rbffi_Function_NewInstance(rbFunctionInfo, proc); rb_hash_aset(cbTable, rbFunctionInfo, callback); return callback; }
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; } }