[gjs/wip/gobj-kitchen-sink: 3/21] function: Allow out parameters in callbacks and vfuncs



commit 6fd48fc376e6a6b19b1c7d7268ecbff9688e64cd
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Nov 28 07:40:28 2011 -0500

    function: Allow out parameters in callbacks and vfuncs
    
    If a callback needs an out parameter or return value to work,
    we need a way for vfunc implementation to take advantage of this.
    The pattern:
    
    If the callback takes a non-void return value and no out args:
      The callback should return the return value:
        return return_value;
    
    If the callback takes no return value and has one out arg:
      The callback should return the one out arg:
        return out_arg_1;
    
    If the callback takes no return value and has multiple out args:
      The callback should return an array containg the out args in sequence:
        return [out_arg_1, out_arg_2, ..., out_arg_N];
    
    If the callback takes a non-void return value and has multiple out args:
      The callback should return an array containing first the return value,
      then the out args in sequence:
        return [return_value, out_arg_1, out_arg_2, ..., out_arg_N];
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663492

 gi/function.c                |  119 +++++++++++++++++++++++++++++++++++++-----
 test/js/testGIMarshalling.js |   48 +++++++++++++++++
 2 files changed, 153 insertions(+), 14 deletions(-)
---
diff --git a/gi/function.c b/gi/function.c
index 1fe354d..4ce4780 100644
--- a/gi/function.c
+++ b/gi/function.c
@@ -208,11 +208,11 @@ gjs_callback_closure(ffi_cif *cif,
 {
     JSContext *context;
     GjsCallbackTrampoline *trampoline;
-    int i, n_args, n_jsargs;
+    int i, n_args, n_jsargs, n_outargs;
     jsval *jsargs, rval;
     GITypeInfo ret_type;
-    GArgument return_value;
     gboolean success = FALSE;
+    gboolean ret_type_is_void;
 
     trampoline = data;
     g_assert(trampoline);
@@ -224,6 +224,7 @@ gjs_callback_closure(ffi_cif *cif,
 
     g_assert(n_args >= 0);
 
+    n_outargs = 0;
     jsargs = (jsval*)g_newa(jsval, n_args);
     for (i = 0, n_jsargs = 0; i < n_args; i++) {
         GIArgInfo arg_info;
@@ -236,6 +237,14 @@ gjs_callback_closure(ffi_cif *cif,
         if (g_type_info_get_tag(&type_info) == GI_TYPE_TAG_VOID)
             continue;
 
+        if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_OUT) {
+            n_outargs++;
+            continue;
+        }
+
+        if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_INOUT)
+            n_outargs++;
+
         if (!gjs_value_from_g_argument(context,
                                        &jsargs[n_jsargs++],
                                        &type_info,
@@ -253,20 +262,102 @@ gjs_callback_closure(ffi_cif *cif,
     }
 
     g_callable_info_load_return_type(trampoline->info, &ret_type);
+    ret_type_is_void = g_type_info_get_tag (&ret_type) == GI_TYPE_TAG_VOID;
+
+    if (n_outargs == 0 && !ret_type_is_void) {
+        GIArgument argument;
+
+        /* non-void return value, no out args. Should
+         * be a single return value. */
+        if (!gjs_value_to_g_argument(context,
+                                     rval,
+                                     &ret_type,
+                                     "callback",
+                                     GJS_ARGUMENT_RETURN_VALUE,
+                                     GI_TRANSFER_NOTHING,
+                                     TRUE,
+                                     &argument))
+            goto out;
 
-    if (!gjs_value_to_g_argument(context,
-                                 rval,
-                                 &ret_type,
-                                 "callback",
-                                 GJS_ARGUMENT_RETURN_VALUE,
-                                 FALSE,
-                                 TRUE,
-                                 &return_value)) {
-        goto out;
-    }
+        set_return_ffi_arg_from_giargument(&ret_type,
+                                           result,
+                                           &argument);
+    } else if (n_outargs == 1 && ret_type_is_void) {
+        /* void return value, one out args. Should
+         * be a single return value. */
+        for (i = 0; i < n_args; i++) {
+            GIArgInfo arg_info;
+            GITypeInfo type_info;
+            g_callable_info_load_arg(trampoline->info, i, &arg_info);
+            if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_IN)
+                continue;
+
+            g_arg_info_load_type(&arg_info, &type_info);
+            if (!gjs_value_to_g_argument(context,
+                                         rval,
+                                         &type_info,
+                                         "callback",
+                                         GJS_ARGUMENT_ARGUMENT,
+                                         GI_TRANSFER_NOTHING,
+                                         TRUE,
+                                         *(gpointer *)args[i]))
+                goto out;
 
-    
-    set_return_ffi_arg_from_giargument(&ret_type, result, &return_value);
+            break;
+        }
+    } else {
+        jsval elem;
+        gsize elem_idx = 0;
+        /* more than one of a return value or an out argument.
+         * Should be an array of output values. */
+
+        if (!ret_type_is_void) {
+            GIArgument argument;
+
+            if (!JS_GetElement(context, JSVAL_TO_OBJECT(rval), elem_idx, &elem))
+                goto out;
+
+            if (!gjs_value_to_g_argument(context,
+                                         elem,
+                                         &ret_type,
+                                         "callback",
+                                         GJS_ARGUMENT_ARGUMENT,
+                                         GI_TRANSFER_NOTHING,
+                                         TRUE,
+                                         &argument))
+                goto out;
+
+            set_return_ffi_arg_from_giargument(&ret_type,
+                                               result,
+                                               &argument);
+
+            elem_idx++;
+        }
+
+        for (i = 0; i < n_args; i++) {
+            GIArgInfo arg_info;
+            GITypeInfo type_info;
+            g_callable_info_load_arg(trampoline->info, i, &arg_info);
+            if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_IN)
+                continue;
+
+            g_arg_info_load_type(&arg_info, &type_info);
+            if (!JS_GetElement(context, JSVAL_TO_OBJECT(rval), elem_idx, &elem))
+                goto out;
+
+            if (!gjs_value_to_g_argument(context,
+                                         elem,
+                                         &type_info,
+                                         "callback",
+                                         GJS_ARGUMENT_ARGUMENT,
+                                         GI_TRANSFER_NOTHING,
+                                         TRUE,
+                                         *(gpointer *)args[i]))
+                goto out;
+
+            elem_idx++;
+        }
+    }
 
     success = TRUE;
 
diff --git a/test/js/testGIMarshalling.js b/test/js/testGIMarshalling.js
index 57dcbfc..252c96b 100644
--- a/test/js/testGIMarshalling.js
+++ b/test/js/testGIMarshalling.js
@@ -230,4 +230,52 @@ function testGType() {
     assertEquals(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE));
 }
 
+const VFuncTester = new Lang.Class({
+    Name: 'VFuncTester',
+    Extends: GIMarshallingTests.Object,
+
+    do_vfunc_return_value_only: function(obj) {
+        return 42;
+    },
+
+    do_vfunc_one_out_parameter: function(obj) {
+        return 43;
+    },
+
+    do_vfunc_multiple_out_parameters: function(obj) {
+        return [44, 45];
+    },
+
+    do_vfunc_return_value_and_one_out_parameter: function(obj) {
+        return [46, 47];
+    },
+
+    do_vfunc_return_value_and_multiple_out_parameters: function(obj) {
+        return [48, 49, 50];
+    }
+});
+
+function testVFuncs() {
+    let tester = new VFuncTester();
+    let a, b, c;
+    a = tester.vfunc_return_value_only();
+    assertEquals(42, a);
+
+    a = tester.vfunc_one_out_parameter();
+    assertEquals(43, a);
+
+    [a, b] = tester.vfunc_multiple_out_parameters();
+    assertEquals(44, a);
+    assertEquals(45, b);
+
+    [a, b] = tester.vfunc_return_value_and_one_out_parameter();
+    assertEquals(46, a);
+    assertEquals(47, b);
+
+    [a, b, c] = tester.vfunc_return_value_and_multiple_out_parameters();
+    assertEquals(48, a);
+    assertEquals(49, b);
+    assertEquals(50, c);
+}
+
 gjstestRun();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]