static VALUE
rg_invoke(VALUE self, VALUE rb_options)
{
    GIFunctionInfo *info;
    GICallableInfo *callable_info;
    GIArgument return_value;
    VALUE rb_out_args;
    VALUE rb_return_value;

    info = SELF(self);
    /* TODO: use rb_protect() */
    rb_out_args = rb_gi_function_info_invoke_raw(info,
                                                 rb_options,
                                                 &return_value);

    callable_info = (GICallableInfo *)info;
    rb_return_value = GI_RETURN_ARGUMENT2RVAL(&return_value, callable_info);

    if (NIL_P(rb_out_args)) {
        return rb_return_value;
    } else {
        GITypeInfo return_value_info;
        g_callable_info_load_return_type(callable_info, &return_value_info);
        if (g_type_info_get_tag(&return_value_info) != GI_TYPE_TAG_VOID) {
            rb_ary_unshift(rb_out_args, rb_return_value);
        }
        if (RARRAY_LEN(rb_out_args) == 1) {
            return RARRAY_PTR(rb_out_args)[0];
        } else {
            return rb_out_args;
        }
    }
}
Example #2
0
VALUE
rb_gi_function_info_invoke_raw(GIFunctionInfo *info,
                               VALUE rb_info,
                               VALUE rb_receiver,
                               VALUE rb_arguments,
                               GIArgument *return_value,
                               VALUE *rb_return_value)
{
    GICallableInfo *callable_info;
    GIArgument receiver;
    GArray *in_args, *out_args;
    GPtrArray *args_metadata;
    VALUE rb_out_args = Qnil;
    gboolean succeeded;
    GError *error = NULL;
    gboolean unlock_gvl = FALSE;
    gboolean rb_receiver_is_class = FALSE;

    unlock_gvl = RVAL2CBOOL(rb_funcall(rb_info, rb_intern("unlock_gvl?"), 0));
    if (NIL_P(rb_receiver)) {
        receiver.v_pointer = NULL;
    } else {
        if (gobject_based_p((GIBaseInfo *)info)) {
            receiver.v_pointer = RVAL2GOBJ(rb_receiver);
        } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_receiver, rb_cClass)) &&
                   rb_respond_to(rb_receiver, rb_intern("gtype"))) {
            GObjectClass *object_class;
            rb_receiver_is_class = TRUE;
            object_class = g_type_class_ref(CLASS2GTYPE(rb_receiver));
            receiver.v_pointer = object_class;
        } else {
            receiver.v_pointer = DATA_PTR(rb_receiver);
        }
    }
    rb_arguments = rbg_to_array(rb_arguments);

    callable_info = (GICallableInfo *)info;
    arguments_init(&in_args, &out_args, &args_metadata);
    if (receiver.v_pointer) {
        g_array_append_val(in_args, receiver);
    }
    arguments_from_ruby(callable_info, rb_receiver, rb_arguments,
                        in_args, out_args, args_metadata);
    {
        InvokeData data;
        data.info = info;
        data.in_args = in_args;
        data.out_args = out_args;
        data.error = &error;
        if (unlock_gvl) {
            rb_thread_call_without_gvl(
                rb_gi_function_info_invoke_raw_call_without_gvl_body, &data,
                NULL, NULL);
        } else {
            rb_gi_function_info_invoke_raw_call(&data);
        }
        succeeded = data.succeeded;

        if (rb_receiver_is_class) {
            g_type_class_unref(receiver.v_pointer);
        }

        if (return_value) {
            *return_value = data.return_value;
        }
        if (rb_return_value) {
            if (succeeded) {
                *rb_return_value = GI_RETURN_ARGUMENT2RVAL(callable_info,
                                                           &(data.return_value),
                                                           in_args,
                                                           out_args,
                                                           args_metadata);
            } else {
                *rb_return_value = Qnil;
            }
        }
    }

    if (succeeded) {
        rb_out_args = out_arguments_to_ruby(callable_info,
                                            in_args, out_args,
                                            args_metadata);
    }
    arguments_free(rb_arguments, in_args, out_args, args_metadata);
    if (!succeeded) {
        RG_RAISE_ERROR(error);
    }

    if (!NIL_P(rb_out_args) && RARRAY_LEN(rb_out_args) == 1) {
        VALUE rb_out_arg;
        rb_out_arg = RARRAY_PTR(rb_out_args)[0];
        if (rb_obj_is_kind_of(rb_out_arg, rb_eException)) {
            rb_exc_raise(rb_out_arg);
        }
    }

    return rb_out_args;
}