/* * 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 void* callback_param(VALUE proc, VALUE cbInfo) { VALUE callback ; if (unlikely(proc == Qnil)) { return NULL ; } // Handle Function pointers here if (rb_obj_is_kind_of(proc, rbffi_FunctionClass)) { AbstractMemory* ptr; Data_Get_Struct(proc, AbstractMemory, ptr); return ptr->address; } //callback = rbffi_NativeCallback_ForProc(proc, cbInfo); callback = rbffi_Function_ForProc(cbInfo, proc); return ((AbstractMemory *) DATA_PTR(callback))->address; }
static void callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data) { Closure* closure = (Closure *) user_data; Function* fn = (Function *) closure->info; FunctionType *cbInfo = fn->info; VALUE* rbParams; VALUE rbReturnValue; int i; rbParams = ALLOCA_N(VALUE, cbInfo->parameterCount); for (i = 0; i < cbInfo->parameterCount; ++i) { VALUE param; switch (cbInfo->parameterTypes[i]->nativeType) { case NATIVE_INT8: param = INT2NUM(*(int8_t *) parameters[i]); break; case NATIVE_UINT8: param = UINT2NUM(*(uint8_t *) parameters[i]); break; case NATIVE_INT16: param = INT2NUM(*(int16_t *) parameters[i]); break; case NATIVE_UINT16: param = UINT2NUM(*(uint16_t *) parameters[i]); break; case NATIVE_INT32: param = INT2NUM(*(int32_t *) parameters[i]); break; case NATIVE_UINT32: param = UINT2NUM(*(uint32_t *) parameters[i]); break; case NATIVE_INT64: param = LL2NUM(*(int64_t *) parameters[i]); break; case NATIVE_UINT64: param = ULL2NUM(*(uint64_t *) parameters[i]); break; case NATIVE_LONG: param = LONG2NUM(*(long *) parameters[i]); break; case NATIVE_ULONG: param = ULONG2NUM(*(unsigned long *) parameters[i]); break; case NATIVE_FLOAT32: param = rb_float_new(*(float *) parameters[i]); break; case NATIVE_FLOAT64: param = rb_float_new(*(double *) parameters[i]); break; case NATIVE_STRING: param = (*(void **) parameters[i] != NULL) ? rb_tainted_str_new2(*(char **) parameters[i]) : Qnil; break; case NATIVE_POINTER: param = rbffi_Pointer_NewInstance(*(void **) parameters[i]); break; case NATIVE_BOOL: param = (*(uint8_t *) parameters[i]) ? Qtrue : Qfalse; break; case NATIVE_FUNCTION: case NATIVE_CALLBACK: param = rbffi_NativeValue_ToRuby(cbInfo->parameterTypes[i], rb_ary_entry(cbInfo->rbParameterTypes, i), parameters[i], Qnil); break; default: param = Qnil; break; } rbParams[i] = param; } rbReturnValue = rb_funcall2(fn->rbProc, id_call, cbInfo->parameterCount, rbParams); if (rbReturnValue == Qnil || TYPE(rbReturnValue) == T_NIL) { memset(retval, 0, cbInfo->ffiReturnType->size); } else switch (cbInfo->returnType->nativeType) { case NATIVE_INT8: case NATIVE_INT16: case NATIVE_INT32: *((ffi_sarg *) retval) = NUM2INT(rbReturnValue); break; case NATIVE_UINT8: case NATIVE_UINT16: case NATIVE_UINT32: *((ffi_arg *) retval) = NUM2UINT(rbReturnValue); break; case NATIVE_INT64: *((int64_t *) retval) = NUM2LL(rbReturnValue); break; case NATIVE_UINT64: *((uint64_t *) retval) = NUM2ULL(rbReturnValue); break; case NATIVE_LONG: *((ffi_sarg *) retval) = NUM2LONG(rbReturnValue); break; case NATIVE_ULONG: *((ffi_arg *) retval) = NUM2ULONG(rbReturnValue); break; case NATIVE_FLOAT32: *((float *) retval) = (float) NUM2DBL(rbReturnValue); break; case NATIVE_FLOAT64: *((double *) retval) = NUM2DBL(rbReturnValue); break; case NATIVE_POINTER: if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue, rbffi_PointerClass)) { *((void **) retval) = ((AbstractMemory *) DATA_PTR(rbReturnValue))->address; } else { // Default to returning NULL if not a value pointer object. handles nil case as well *((void **) retval) = NULL; } break; case NATIVE_BOOL: *((ffi_arg *) retval) = rbReturnValue == Qtrue; break; case NATIVE_FUNCTION: case NATIVE_CALLBACK: if (TYPE(rbReturnValue) == T_DATA && rb_obj_is_kind_of(rbReturnValue, rbffi_PointerClass)) { *((void **) retval) = ((AbstractMemory *) DATA_PTR(rbReturnValue))->address; } else if (rb_obj_is_kind_of(rbReturnValue, rb_cProc) || rb_respond_to(rbReturnValue, id_call)) { VALUE function; function = rbffi_Function_ForProc(cbInfo->rbReturnType, rbReturnValue); *((void **) retval) = ((AbstractMemory *) DATA_PTR(function))->address; } else { *((void **) retval) = NULL; } break; default: *((ffi_arg *) retval) = 0; break; } }