Class: FFI::VariadicInvoker
Relationships & Source Files | |
Inherits: | Object |
Defined in: | ext/ffi_c/Variadic.c, lib/ffi/variadic.rb |
Class Method Summary
Instance Method Summary
-
#attach(mod, mname)
Attach the invoker to module
mod
asmname
- #call(*args, &block)
- #invoke(parameterTypes, parameterValues)
-
#param_types ⇒ Array<FFI::Type>
Retrieve Array of parameter types.
- #return_type
Constructor Details
.new(rbFunction, rbParameterTypes, rbReturnType, options)
[ GitHub ]# File 'ext/ffi_c/Variadic.c', line 129
static VALUE variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE rbReturnType, VALUE options) { VariadicInvoker* invoker = NULL; VALUE retval = Qnil; VALUE convention = Qnil; VALUE fixed = Qnil; #if defined(X86_WIN32) VALUE rbConventionStr; #endif int i; Check_Type(options, T_HASH); convention = rb_hash_aref(options, ID2SYM(rb_intern("convention"))); TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); RB_OBJ_WRITE(self, &invoker->rbEnums, rb_hash_aref(options, ID2SYM(rb_intern("enums")))); RB_OBJ_WRITE(self, &invoker->rbAddress, rbFunction); invoker->function = rbffi_AbstractMemory_Cast(rbFunction, &rbffi_pointer_data_type)->address; invoker->blocking = RTEST(rb_hash_aref(options, ID2SYM(rb_intern("blocking")))); #if defined(X86_WIN32) rbConventionStr = rb_funcall2(convention, rb_intern("to_s"), 0, NULL); invoker->abi = (RTEST(convention) && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0) ? FFI_STDCALL : FFI_DEFAULT_ABI; #else invoker->abi = FFI_DEFAULT_ABI; #endif RB_OBJ_WRITE(self, &invoker->rbReturnType, rbffi_Type_Lookup(rbReturnType)); if (!RTEST(invoker->rbReturnType)) { VALUE typeName = rb_funcall2(rbReturnType, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid return type (%s)", RSTRING_PTR(typeName)); } TypedData_Get_Struct(rbReturnType, Type, &rbffi_type_data_type, invoker->returnType); invoker->paramCount = -1; fixed = rb_ary_new2(RARRAY_LEN(rbParameterTypes) - 1); for (i = 0; i < RARRAY_LEN(rbParameterTypes); ++i) { VALUE entry = rb_ary_entry(rbParameterTypes, i); VALUE rbType = rbffi_Type_Lookup(entry); Type* type; if (!RTEST(rbType)) { VALUE typeName = rb_funcall2(entry, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid parameter type (%s)", RSTRING_PTR(typeName)); } TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, type); if (type->nativeType != NATIVE_VARARGS) { rb_ary_push(fixed, entry); } } /* * @fixed and @type_map are used by the parameter mangling ruby code */ rb_iv_set(self, "@fixed", rb_obj_freeze(fixed)); rb_iv_set(self, "@type_map", rb_hash_aref(options, ID2SYM(rb_intern("type_map")))); return retval; }
Instance Method Details
#attach(mod, mname)
Attach the invoker to module mod
as mname
# File 'lib/ffi/variadic.rb', line 53
def attach(mod, mname) invoker = self params = "*args" call = "call" mname = mname.to_sym mod.module_eval <<-code, __FILE__, __LINE__ @ffi_functions = {} unless defined?(@ffi_functions) @ffi_functions[#{mname.inspect}] = invoker def self.#{mname}(#{params}) @ffi_functions[#{mname.inspect}].#{call}(#{params}) end define_method(#{mname.inspect}, &method(#{mname.inspect})) code invoker end
#call(*args, &block)
[ GitHub ]# File 'lib/ffi/variadic.rb', line 35
def call(*args, &block) param_types = Array.new(@fixed) param_values = Array.new @fixed.each_with_index do |t, i| param_values << args[i] end i = @fixed.length while i < args.length param_types << FFI.find_type(args[i], @type_map) param_values << args[i + 1] i += 2 end invoke(param_types, param_values, &block) end
#invoke(parameterTypes, parameterValues)
[ GitHub ]# File 'ext/ffi_c/Variadic.c', line 192
static VALUE variadic_invoke(VALUE self, VALUE parameterTypes, VALUE parameterValues) { VariadicInvoker* invoker; FFIStorage* params; void* retval; ffi_cif cif; void** ffiValues; ffi_type** ffiParamTypes; ffi_type* ffiReturnType; Type** paramTypes; VALUE* argv; VALUE* callbackParameters; VALUE callbackProc; int paramCount = 0, fixedCount = 0, callbackCount = 0, i; ffi_status ffiStatus; rbffi_frame_t frame = { 0 }; Check_Type(parameterTypes, T_ARRAY); Check_Type(parameterValues, T_ARRAY); TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); paramCount = RARRAY_LENINT(parameterTypes); paramTypes = ALLOCA_N(Type *, paramCount); ffiParamTypes = ALLOCA_N(ffi_type *, paramCount); params = ALLOCA_N(FFIStorage, paramCount); ffiValues = ALLOCA_N(void*, paramCount); argv = ALLOCA_N(VALUE, paramCount); callbackParameters = ALLOCA_N(VALUE, paramCount); retval = alloca(MAX(invoker->returnType->ffiType->size, FFI_SIZEOF_ARG)); for (i = 0; i < paramCount; ++i) { VALUE rbType = rb_ary_entry(parameterTypes, i); if (!rb_obj_is_kind_of(rbType, rbffi_TypeClass)) { rb_raise(rb_eTypeError, "wrong type. Expected (FFI::Type)"); } TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); switch (paramTypes[i]->nativeType) { case NATIVE_INT8: case NATIVE_INT16: case NATIVE_INT32: rbType = rb_const_get(rbffi_TypeClass, rb_intern("INT32")); TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); break; case NATIVE_UINT8: case NATIVE_UINT16: case NATIVE_UINT32: rbType = rb_const_get(rbffi_TypeClass, rb_intern("UINT32")); TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); break; case NATIVE_FLOAT32: rbType = rb_const_get(rbffi_TypeClass, rb_intern("DOUBLE")); TypedData_Get_Struct(rbType, Type, &rbffi_type_data_type, paramTypes[i]); break; case NATIVE_FUNCTION: if (!rb_obj_is_kind_of(rbType, rbffi_FunctionTypeClass)) { VALUE typeName = rb_funcall2(rbType, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Incorrect parameter type (%s)", RSTRING_PTR(typeName)); } callbackParameters[callbackCount++] = rbType; break; default: break; } ffiParamTypes[i] = paramTypes[i]->ffiType; if (ffiParamTypes[i] == NULL) { rb_raise(rb_eArgError, "Invalid parameter type #%x", paramTypes[i]->nativeType); } argv[i] = rb_ary_entry(parameterValues, i); } ffiReturnType = invoker->returnType->ffiType; if (ffiReturnType == NULL) { rb_raise(rb_eArgError, "Invalid return type"); } /*Get the number of fixed args from @fixed array*/ fixedCount = RARRAY_LEN(rb_iv_get(self, "@fixed")); #ifdef HAVE_FFI_PREP_CIF_VAR ffiStatus = ffi_prep_cif_var(&cif, invoker->abi, fixedCount, paramCount, ffiReturnType, ffiParamTypes); #else ffiStatus = ffi_prep_cif(&cif, invoker->abi, paramCount, ffiReturnType, ffiParamTypes); #endif switch (ffiStatus) { case FFI_BAD_ABI: rb_raise(rb_eArgError, "Invalid ABI specified"); case FFI_BAD_TYPEDEF: rb_raise(rb_eArgError, "Invalid argument type specified"); case FFI_OK: break; default: rb_raise(rb_eArgError, "Unknown FFI error"); } callbackProc = rbffi_SetupCallParams(paramCount, argv, -1, paramTypes, params, ffiValues, callbackParameters, callbackCount, invoker->rbEnums); rbffi_frame_push(&frame); if(unlikely(invoker->blocking)) { rbffi_blocking_call_t* bc; bc = ALLOCA_N(rbffi_blocking_call_t, 1); bc->retval = retval; bc->function = invoker->function; bc->ffiValues = ffiValues; bc->params = params; bc->frame = &frame; bc->cif = cif; rb_rescue2(rbffi_do_blocking_call, (VALUE) bc, rbffi_save_frame_exception, (VALUE) &frame, rb_eException, (VALUE) 0); } else { ffi_call(&cif, FFI_FN(invoker->function), retval, ffiValues); } RB_GC_GUARD(callbackProc); rbffi_frame_pop(&frame); rbffi_save_errno(); if (RTEST(frame.exc) && frame.exc != Qnil) { rb_exc_raise(frame.exc); } return rbffi_NativeValue_ToRuby(invoker->returnType, invoker->rbReturnType, retval); }
#param_types ⇒ Array
<FFI::Type>
Retrieve Array of parameter types
This method returns an Array of ::FFI
types accepted as function parameters.
#return_type
[ GitHub ]# File 'ext/ffi_c/Variadic.c', line 327
static VALUE variadic_return_type(VALUE self) { VariadicInvoker* invoker; TypedData_Get_Struct(self, VariadicInvoker, &variadic_data_type, invoker); return invoker->rbReturnType; }