[gjs] gi: implement array+length for return value, out, and inout



commit 0cd4538efcc0e39005c7921181c8e3687911255c
Author: Dan Winship <danw gnome org>
Date:   Thu Jun 2 10:39:02 2011 -0400

    gi: implement array+length for return value, out, and inout
    
    https://bugzilla.gnome.org/show_bug.cgi?id=651558

 gi/arg.c                     |   63 +++++++++++++++++
 gi/arg.h                     |   11 +++
 gi/function.c                |  155 ++++++++++++++++++++++++++++++-----------
 test/js/testGIMarshalling.js |   50 +++++++++++++-
 4 files changed, 236 insertions(+), 43 deletions(-)
---
diff --git a/gi/arg.c b/gi/arg.c
index cf20fe7..c5145ae 100644
--- a/gi/arg.c
+++ b/gi/arg.c
@@ -1806,6 +1806,25 @@ gjs_array_from_carray (JSContext  *context,
     return res;
 }
 
+JSBool
+gjs_value_from_explicit_array(JSContext  *context,
+                              jsval      *value_p,
+                              GITypeInfo *type_info,
+                              GArgument  *arg,
+                              int         length)
+{
+    GITypeInfo *param_info;
+    JSBool res;
+
+    param_info = g_type_info_get_param_type(type_info, 0);
+
+    res = gjs_array_from_carray_internal(context, value_p, param_info, length, arg->v_pointer);
+
+    g_base_info_unref((GIBaseInfo*)param_info);
+
+    return res;
+}
+
 static JSBool
 gjs_array_from_g_array (JSContext  *context,
                         jsval      *value_p,
@@ -2839,3 +2858,47 @@ gjs_g_argument_release_in_array (JSContext  *context,
 
     return ret;
 }
+
+JSBool
+gjs_g_argument_release_out_array (JSContext  *context,
+                                  GITransfer  transfer,
+                                  GITypeInfo *type_info,
+                                  guint       length,
+                                  GArgument  *arg)
+{
+    GITypeInfo *param_type;
+    gpointer *array;
+    GArgument elem;
+    guint i;
+    JSBool ret = JS_TRUE;
+    GITypeTag type_tag;
+
+    if (transfer == GI_TRANSFER_NOTHING)
+        return JS_TRUE;
+
+    gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
+                      "Releasing GArgument array out param");
+
+    array = arg->v_pointer;
+
+    param_type = g_type_info_get_param_type(type_info, 0);
+    type_tag = g_type_info_get_tag(param_type);
+
+    if (transfer != GI_TRANSFER_CONTAINER) {
+        for (i = 0; i < length; i++) {
+            elem.v_pointer = array[i];
+            if (!gjs_g_arg_release_internal(context,
+                                            GI_TRANSFER_EVERYTHING,
+                                            param_type,
+                                            type_tag,
+                                            &elem)) {
+                ret = JS_FALSE;
+            }
+        }
+    }
+
+    g_base_info_unref(param_type);
+    g_free(array);
+
+    return ret;
+}
diff --git a/gi/arg.h b/gi/arg.h
index a5e2aa8..363e32b 100644
--- a/gi/arg.h
+++ b/gi/arg.h
@@ -70,10 +70,21 @@ JSBool gjs_value_from_g_argument (JSContext  *context,
                                   jsval      *value_p,
                                   GITypeInfo *type_info,
                                   GArgument  *arg);
+JSBool gjs_value_from_explicit_array (JSContext  *context,
+                                      jsval      *value_p,
+                                      GITypeInfo *type_info,
+                                      GArgument  *arg,
+                                      int         length);
+
 JSBool gjs_g_argument_release    (JSContext  *context,
                                   GITransfer  transfer,
                                   GITypeInfo *type_info,
                                   GArgument  *arg);
+JSBool gjs_g_argument_release_out_array (JSContext  *context,
+                                         GITransfer  transfer,
+                                         GITypeInfo *type_info,
+                                         guint       length,
+                                         GArgument  *arg);
 JSBool gjs_g_argument_release_in_array (JSContext  *context,
                                         GITransfer  transfer,
                                         GITypeInfo *type_info,
diff --git a/gi/function.c b/gi/function.c
index 25f52e7..156607f 100644
--- a/gi/function.c
+++ b/gi/function.c
@@ -651,20 +651,50 @@ gjs_invoke_c_function(JSContext      *context,
         gjs_root_value_locations(context, return_values, function->js_out_argc);
 
         if (return_tag != GI_TYPE_TAG_VOID) {
+            GITransfer transfer = g_callable_info_get_caller_owns((GICallableInfo*) function->info);
             gboolean arg_failed;
+            gint array_length_pos;
 
             g_assert_cmpuint(next_rval, <, function->js_out_argc);
-            arg_failed = !gjs_value_from_g_argument(context, &return_values[next_rval],
-                                                    &return_info, (GArgument*)&return_value);
-            if (arg_failed)
-                failed = TRUE;
 
-            /* Free GArgument, the jsval should have ref'd or copied it */
-            if (!arg_failed &&
-                !gjs_g_argument_release(context,
-                                        g_callable_info_get_caller_owns((GICallableInfo*) function->info),
-                                        &return_info,
-                                        (GArgument*)&return_value))
+            array_length_pos = g_type_info_get_array_length(&return_info);
+            if (array_length_pos >= 0) {
+                GIArgInfo array_length_arg;
+                GITypeInfo arg_type_info;
+                jsval length;
+
+                g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
+                g_arg_info_load_type(&array_length_arg, &arg_type_info);
+                array_length_pos += is_method ? 1 : 0;
+                arg_failed = !gjs_value_from_g_argument(context, &length,
+                                                        &arg_type_info,
+                                                        &out_arg_cvalues[array_length_pos]);
+                if (!arg_failed) {
+                    arg_failed = !gjs_value_from_explicit_array(context,
+                                                                &return_values[next_rval],
+                                                                &return_info,
+                                                                &return_value,
+                                                                JSVAL_TO_INT(length));
+                }
+                if (!arg_failed &&
+                    !gjs_g_argument_release_out_array(context,
+                                                      transfer,
+                                                      &return_info,
+                                                      JSVAL_TO_INT(length),
+                                                      &return_value))
+                    failed = TRUE;
+            } else {
+                arg_failed = !gjs_value_from_g_argument(context, &return_values[next_rval],
+                                                        &return_info, &return_value);
+                /* Free GArgument, the jsval should have ref'd or copied it */
+                if (!arg_failed &&
+                    !gjs_g_argument_release(context,
+                                            transfer,
+                                            &return_info,
+                                            &return_value))
+                    failed = TRUE;
+            }
+            if (arg_failed)
                 failed = TRUE;
 
             ++next_rval;
@@ -681,21 +711,21 @@ release:
         GIDirection direction;
         GIArgInfo arg_info;
         GITypeInfo arg_type_info;
+        ParamType param_type;
 
         g_callable_info_load_arg( (GICallableInfo*) function->info, gi_arg_pos, &arg_info);
         direction = g_arg_info_get_direction(&arg_info);
 
         g_arg_info_load_type(&arg_info, &arg_type_info);
+        param_type = function->param_types[gi_arg_pos];
 
         if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
             GArgument *arg;
             GITransfer transfer;
-            ParamType param_type = PARAM_NORMAL;
 
             if (direction == GI_DIRECTION_IN) {
                 arg = &in_arg_cvalues[c_arg_pos];
                 transfer = g_arg_info_get_ownership_transfer(&arg_info);
-                param_type = function->param_types[gi_arg_pos];
             } else {
                 arg = &inout_original_arg_cvalues[c_arg_pos];
                 /* For inout, transfer refers to what we get back from the function; for
@@ -754,23 +784,45 @@ release:
         if (did_throw_gerror || failed)
             continue;
 
-        if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+        if ((direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) && param_type != PARAM_SKIPPED) {
             GArgument *arg;
             gboolean arg_failed;
+            gint array_length_pos;
+            jsval array_length;
+            GITransfer transfer;
 
             g_assert(next_rval < function->js_out_argc);
 
             arg = &out_arg_cvalues[c_arg_pos];
 
-            arg_failed = FALSE;
-            if (!gjs_value_from_g_argument(context,
-                                           &return_values[next_rval],
-                                           &arg_type_info,
-                                           arg)) {
-                arg_failed = TRUE;
-                postinvoke_release_failed = TRUE;
+            array_length_pos = g_type_info_get_array_length(&arg_type_info);
+            if (array_length_pos >= 0) {
+                GIArgInfo array_length_arg;
+                GITypeInfo array_length_type_info;
+
+                g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
+                g_arg_info_load_type(&array_length_arg, &array_length_type_info);
+                array_length_pos += is_method ? 1 : 0;
+                arg_failed = !gjs_value_from_g_argument(context, &array_length,
+                                                        &array_length_type_info,
+                                                        &out_arg_cvalues[array_length_pos]);
+                if (!arg_failed) {
+                    arg_failed = !gjs_value_from_explicit_array(context,
+                                                                &return_values[next_rval],
+                                                                &arg_type_info,
+                                                                arg,
+                                                                JSVAL_TO_INT(array_length));
+                }
+            } else {
+                arg_failed = !gjs_value_from_g_argument(context,
+                                                        &return_values[next_rval],
+                                                        &arg_type_info,
+                                                        arg);
             }
 
+            if (arg_failed)
+                postinvoke_release_failed = TRUE;
+
             /* For caller-allocates, what happens here is we allocate
              * a structure above, then gjs_value_from_g_argument calls
              * g_boxed_copy on it, and takes ownership of that.  So
@@ -803,11 +855,21 @@ release:
             }
 
             /* Free GArgument, the jsval should have ref'd or copied it */
-            if (!arg_failed)
-                gjs_g_argument_release(context,
-                                       g_arg_info_get_ownership_transfer(&arg_info),
-                                       &arg_type_info,
-                                       arg);
+            transfer = g_arg_info_get_ownership_transfer(&arg_info);
+            if (!arg_failed) {
+                if (array_length_pos >= 0) {
+                    gjs_g_argument_release_out_array(context,
+                                                     transfer,
+                                                     &arg_type_info,
+                                                     JSVAL_TO_INT(array_length),
+                                                     arg);
+                } else {
+                    gjs_g_argument_release(context,
+                                           transfer,
+                                           &arg_type_info,
+                                           arg);
+                }
+            }
 
             ++next_rval;
         }
@@ -1062,7 +1124,7 @@ init_cached_function_data (JSContext      *context,
                            Function       *function,
                            GIFunctionInfo *info)
 {
-    guint8 i, n_args;
+    guint8 i, n_args, array_length_pos;
     GError *error = NULL;
     GITypeInfo return_type;
 
@@ -1073,12 +1135,15 @@ init_cached_function_data (JSContext      *context,
 
     g_callable_info_load_return_type((GICallableInfo*)info, &return_type);
     if (g_type_info_get_tag(&return_type) != GI_TYPE_TAG_VOID)
-      function->js_out_argc += 1;
+        function->js_out_argc += 1;
 
     n_args = g_callable_info_get_n_args((GICallableInfo*) info);
-
     function->param_types = g_new0(ParamType, n_args);
 
+    array_length_pos = g_type_info_get_array_length(&return_type);
+    if (array_length_pos >= 0 && array_length_pos < n_args)
+        function->param_types[array_length_pos] = PARAM_SKIPPED;
+
     for (i = 0; i < n_args; i++) {
         GIDirection direction;
         GIArgInfo arg_info;
@@ -1131,28 +1196,34 @@ init_cached_function_data (JSContext      *context,
             g_base_info_unref(interface_info);
         } else if (type_tag == GI_TYPE_TAG_ARRAY) {
             if (g_type_info_get_array_type(&type_info) == GI_ARRAY_TYPE_C) {
-                gint array_length_pos = g_type_info_get_array_length(&type_info);
+                array_length_pos = g_type_info_get_array_length(&type_info);
 
-                if (array_length_pos >= 0) {
-                    if (direction == GI_DIRECTION_IN) {
-                        function->param_types[array_length_pos] = PARAM_SKIPPED;
-                        function->param_types[i] = PARAM_ARRAY;
-                        function->expected_js_argc += 1;
-
-                        if (array_length_pos < i) {
-                            /* we already collected array_length_pos, remove it */
-                            function->expected_js_argc -= 1;
-                        }
-                    } else {
-                        gjs_throw(context, "Function %s.%s has a (out) or (inout) array with explicit length, not supported",
+                if (array_length_pos >= 0 && array_length_pos < n_args) {
+                    GIArgInfo length_arg_info;
+
+                    g_callable_info_load_arg((GICallableInfo*) info, array_length_pos, &length_arg_info);
+                    if (g_arg_info_get_direction(&length_arg_info) != direction) {
+                        gjs_throw(context, "Function %s.%s has an array with different-direction length arg, not supported",
                                   g_base_info_get_namespace( (GIBaseInfo*) info),
                                   g_base_info_get_name( (GIBaseInfo*) info));
+                        return JS_FALSE;
+                    }
+
+                    function->param_types[array_length_pos] = PARAM_SKIPPED;
+                    function->param_types[i] = PARAM_ARRAY;
+
+                    if (array_length_pos < i) {
+                        /* we already collected array_length_pos, remove it */
+                        function->expected_js_argc -= 1;
+                        if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+                            function->js_out_argc--;
                     }
                 }
             }
         }
 
-        if (function->param_types[i] == PARAM_NORMAL) {
+        if (function->param_types[i] == PARAM_NORMAL ||
+            function->param_types[i] == PARAM_ARRAY) {
             if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
                 function->expected_js_argc += 1;
             if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
diff --git a/test/js/testGIMarshalling.js b/test/js/testGIMarshalling.js
index 745273f..858b9b3 100644
--- a/test/js/testGIMarshalling.js
+++ b/test/js/testGIMarshalling.js
@@ -6,7 +6,8 @@ const Gio = imports.gi.Gio;
 const Lang = imports.lang;
 
 function testCArray() {
-    var array;
+    var array, sum;
+
     array = GIMarshallingTests.array_zero_terminated_return();
     assertEquals("0", array[0]);
     assertEquals("1", array[1]);
@@ -19,6 +20,53 @@ function testCArray() {
     assertEquals(43, array[1].long_);
     assertEquals(44, array[2].long_);
 
+    array = GIMarshallingTests.array_return();
+    assertEquals(4, array.length);
+    assertEquals(-1, array[0]);
+    assertEquals(0, array[1]);
+    assertEquals(1, array[2]);
+    assertEquals(2, array[3]);
+
+    [array, sum] = GIMarshallingTests.array_return_etc(9, 5);
+    assertEquals(14, sum);
+    assertEquals(4, array.length);
+    assertEquals(9, array[0]);
+    assertEquals(0, array[1]);
+    assertEquals(1, array[2]);
+    assertEquals(5, array[3]);
+
+    array = GIMarshallingTests.array_out();
+    assertEquals(4, array.length);
+    assertEquals(-1, array[0]);
+    assertEquals(0, array[1]);
+    assertEquals(1, array[2]);
+    assertEquals(2, array[3]);
+
+    [array, sum] = GIMarshallingTests.array_out_etc(9, 5);
+    assertEquals(14, sum);
+    assertEquals(4, array.length);
+    assertEquals(9, array[0]);
+    assertEquals(0, array[1]);
+    assertEquals(1, array[2]);
+    assertEquals(5, array[3]);
+
+    array = GIMarshallingTests.array_inout([-1, 0, 1, 2]);
+    assertEquals(5, array.length);
+    assertEquals(-2, array[0]);
+    assertEquals(-1, array[1]);
+    assertEquals(0, array[2]);
+    assertEquals(1, array[3]);
+    assertEquals(2, array[4]);
+
+    [array, sum] = GIMarshallingTests.array_inout_etc(9, [-1, 0, 1, 2], 5);
+    assertEquals(14, sum);
+    assertEquals(5, array.length);
+    assertEquals(9, array[0]);
+    assertEquals(-1, array[1]);
+    assertEquals(0, array[2]);
+    assertEquals(1, array[3]);
+    assertEquals(5, array[4]);
+
     GIMarshallingTests.array_string_in(["foo", "bar"]);
 
     array = [];



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