Class: FFI::VariadicInvoker

### Home Classes Methods

### In Files

- lib/ffi/variadic.rb
- ext/ffi_c/ffi.c

### Parent

Object

### Methods

- ::new
- #attach
- #call
- #init
- #invoke

### Files

- Makefile
- LICENSE
- compile
- configure
- depcomp
- stamp-vti
- install-sh
- libtool-version
- mdate-sh
- missing

### Class/Module Index

Quicksearch

- FFI
- FFI::AutoPointer
- FFI::AutoPointer::CallableReleaser
- FFI::AutoPointer::DefaultReleaser
- FFI::AutoPointer::Releaser
- FFI::ConstGenerator
- FFI::ConstGenerator::Constant
- FFI::Enum
- FFI::Enums
- FFI::Function
- FFI::FunctionType
- FFI::Generator
- FFI::Generator::Task
- FFI::IO
- FFI::LastError
- FFI::ManagedStruct
- FFI::MemoryPointer
- FFI::NativeType
- FFI::Platform
- FFI::PlatformError
- FFI::Pointer
- FFI::StrPtrConverter
- FFI::Struct
- FFI::Struct::InlineArray
- FFI::Struct::ManagedStructConverter
- FFI::StructByReference
- FFI::StructByValue
- FFI::StructGenerator
- FFI::StructGenerator::Field
- FFI::StructLayout
- FFI::StructLayout::Array
- FFI::StructLayout::Enum
- FFI::StructLayout::Field
- FFI::StructLayout::Function
- FFI::StructLayout::InnerStruct
- FFI::StructLayout::Mapped
- FFI::StructLayout::Number
- FFI::StructLayout::Pointer
- FFI::StructLayout::String
- FFI::StructLayoutBuilder
- FFI::Type
- FFI::Type::Builtin
- FFI::TypesGenerator
- FFI::Union
- FFI::VariadicInvoker

No matching classes.

# FFI::VariadicInvoker

### Public Class Methods

new(p1, p2, p3, p4) click to toggle source

    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(_WIN32) || defined(__WIN32__)
        VALUE rbConventionStr;
    #endif
        int i;

        Check_Type(options, T_HASH);
        convention = rb_hash_aref(options, ID2SYM(rb_intern("convention")));

        Data_Get_Struct(self, VariadicInvoker, invoker);
        invoker->rbEnums = rb_hash_aref(options, ID2SYM(rb_intern("enums")));
        invoker->rbAddress = rbFunction;
        invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address;

    #if (defined(_WIN32) || defined(__WIN32__)) && defined(FFI_STDCALL)
        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

        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));
        }

        Data_Get_Struct(rbReturnType, 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));
            }
            Data_Get_Struct(rbType, 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", fixed);
        rb_iv_set(self, "@type_map", rb_hash_aref(options, ID2SYM(rb_intern("type_map"))));

        return retval;
    }

### Public Instance Methods

attach(mod, mname) click to toggle source

Attach the invoker to module `mod` as `mname`

    # File lib/ffi/variadic.rb, line 49
    def attach(mod, mname)
      invoker = self
      params = "*args"
      call = "call"
      mod.module_eval       @@#{mname} = invoker      def self.#{mname}(#{params})        @@#{mname}.#{call}(#{params})      end      def #{mname}(#{params})        @@#{mname}.#{call}(#{params})      end
      invoker
    end

call(*args, &block) click to toggle source

    # File lib/ffi/variadic.rb, line 31
    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

init(arg_types, type_map) click to toggle source

    # File lib/ffi/variadic.rb, line 22
    def init(arg_types, type_map)
      @fixed = Array.new
      @type_map = type_map
      arg_types.each_with_index do |type, i|
        @fixed << type unless type == Type::VARARGS
      end
    end

invoke(p1, p2) click to toggle source

    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;
        int paramCount = 0, i;
        ffi_status ffiStatus;
        rbffi_frame_t frame = { 0 };

        Check_Type(parameterTypes, T_ARRAY);
        Check_Type(parameterValues, T_ARRAY);

        Data_Get_Struct(self, VariadicInvoker, invoker);
        paramCount = (int) RARRAY_LEN(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);
        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)");
            }
            Data_Get_Struct(rbType, 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"));
                    Data_Get_Struct(rbType, Type, paramTypes[i]);
                    break;
                case NATIVE_UINT8:
                case NATIVE_UINT16:
                case NATIVE_UINT32:
                    rbType = rb_const_get(rbffi_TypeClass, rb_intern("UINT32"));
                    Data_Get_Struct(rbType, Type, paramTypes[i]);
                    break;

                case NATIVE_FLOAT32:
                    rbType = rb_const_get(rbffi_TypeClass, rb_intern("DOUBLE"));
                    Data_Get_Struct(rbType, Type, paramTypes[i]);
                    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");
        }
    #ifdef HAVE_FFI_PREP_CIF_VAR
        ffiStatus = ffi_prep_cif_var(&cif, invoker->abi, paramCount, 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");
        }

        rbffi_SetupCallParams(paramCount, argv, -1, paramTypes, params,
            ffiValues, NULL, 0, invoker->rbEnums);

        rbffi_frame_push(&frame);
        ffi_call(&cif, FFI_FN(invoker->function), retval, ffiValues);
        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);
    }

[Validate]

Generated with the Darkfish Rdoc Generator 2.