[gjs] Add support for flat GValue arrays



commit 0688f72307596cd86e1f47a21a4ce73a865987f1
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu Sep 1 14:52:20 2011 -0400

    Add support for flat GValue arrays
    
    https://bugzilla.gnome.org/show_bug.cgi?id=657767

 gi/arg.c                     |  128 +++++++++++++++++++++++++++++++++++++++++-
 test/js/testGIMarshalling.js |   45 +++++++++++----
 2 files changed, 161 insertions(+), 12 deletions(-)
---
diff --git a/gi/arg.c b/gi/arg.c
index 631c416..a653d79 100644
--- a/gi/arg.c
+++ b/gi/arg.c
@@ -221,8 +221,10 @@ type_needs_release (GITypeInfo *type_info,
             break;
         }
 
-        if (g_type_is_a(gtype, G_TYPE_CLOSURE) || g_type_is_a(gtype, G_TYPE_VALUE))
+        if (g_type_is_a(gtype, G_TYPE_CLOSURE))
             needs_release = TRUE;
+        else if (g_type_is_a(gtype, G_TYPE_VALUE))
+            needs_release = g_type_info_is_pointer(type_info);
         else
             needs_release = FALSE;
 
@@ -729,6 +731,118 @@ gjs_array_to_ptrarray(JSContext   *context,
 }
 
 static JSBool
+gjs_array_to_flat_gvalue_array(JSContext   *context,
+                               jsval        array_value,
+                               unsigned int length,
+                               void       **arr_p)
+{
+    GValue *values = g_new0(GValue, length);
+    unsigned int i;
+    JSBool result = JS_TRUE;
+
+    for (i = 0; i < length; i ++) {
+        jsval elem;
+        elem = JSVAL_VOID;
+
+        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
+                           i, &elem)) {
+            g_free(values);
+            gjs_throw(context,
+                      "Missing array element %u",
+                      i);
+            return JS_FALSE;
+        }
+
+        result = gjs_value_to_g_value(context, elem, &values[i]);
+
+        if (!result)
+            break;
+    }
+
+    if (result)
+        *arr_p = values;
+
+    return result;
+}
+
+static JSBool
+gjs_array_from_flat_gvalue_array(JSContext   *context,
+                                 gpointer     array,
+                                 unsigned int length,
+                                 jsval       *value)
+{
+    GValue *values = (GValue *)array;
+    unsigned int i;
+    jsval *elems = g_newa(jsval, length);
+    JSBool result = JS_TRUE;
+
+    for (i = 0; i < length; i ++) {
+        GValue *value = &values[i];
+        result = gjs_value_from_g_value(context, &elems[i], value);
+        if (!result)
+            break;
+    }
+
+    if (result) {
+        JSObject *jsarray;
+        jsarray = JS_NewArrayObject(context, length, elems);
+        *value = OBJECT_TO_JSVAL(jsarray);
+    }
+
+    return result;
+}
+
+static gboolean
+is_gvalue(GIBaseInfo *info,
+          GIInfoType  info_type)
+{
+    gboolean result = FALSE;
+
+    switch(info_type) {
+    case GI_INFO_TYPE_VALUE:
+        result = TRUE;
+        break;
+    case GI_INFO_TYPE_STRUCT:
+    case GI_INFO_TYPE_OBJECT:
+    case GI_INFO_TYPE_INTERFACE:
+    case GI_INFO_TYPE_BOXED:
+        {
+            GType gtype;
+            gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *) info);
+
+            result = g_type_is_a(gtype, G_TYPE_VALUE);
+        }
+        break;
+    default:
+        break;
+    }
+
+    return result;
+}
+
+static gboolean
+is_gvalue_flat_array(GITypeInfo *param_info,
+                     GITypeTag   element_type)
+{
+    GIBaseInfo *interface_info;
+    GIInfoType info_type;
+    gboolean result;
+
+    if (element_type != GI_TYPE_TAG_INTERFACE)
+        return FALSE;
+
+    interface_info = g_type_info_get_interface(param_info);
+    info_type = g_base_info_get_type(interface_info);
+
+    /* Special case for GValue "flat arrays" */
+    result = (is_gvalue(interface_info, info_type) &&
+              !g_type_info_is_pointer(param_info));
+    g_base_info_unref(interface_info);
+
+    return result;
+}
+
+static JSBool
 gjs_array_to_array(JSContext   *context,
                    jsval        array_value,
                    gsize        length,
@@ -742,6 +856,10 @@ gjs_array_to_array(JSContext   *context,
     element_type = g_type_info_get_tag(param_info);
     element_type = replace_gtype(element_type);
 
+    /* Special case for GValue "flat arrays" */
+    if (is_gvalue_flat_array(param_info, element_type))
+        return gjs_array_to_flat_gvalue_array(context, array_value, length, arr_p);
+
     if (element_type == GI_TYPE_TAG_INTERFACE) {
         GIBaseInfo *interface_info = g_type_info_get_interface(param_info);
         GIInfoType info_type = g_base_info_get_type(interface_info);
@@ -1753,6 +1871,9 @@ gjs_array_from_carray_internal (JSContext  *context,
     element_type = g_type_info_get_tag(param_info);
     element_type = replace_gtype(element_type);
 
+    if (is_gvalue_flat_array(param_info, element_type))
+        return gjs_array_from_flat_gvalue_array(context, array, length, value_p);
+
     /* Special case array(guint8) */
     if (element_type == GI_TYPE_TAG_UINT8) {
         GByteArray gbytearray;
@@ -2603,6 +2724,11 @@ gjs_g_arg_release_internal(JSContext  *context,
             element_type = g_type_info_get_tag(param_info);
             element_type = replace_gtype(element_type);
 
+            if (transfer != GI_TRANSFER_CONTAINER && is_gvalue_flat_array(param_info, element_type)) {
+                g_free(arg->v_pointer);
+                return JS_TRUE;
+            }
+
             switch (element_type) {
             case GI_TYPE_TAG_UTF8:
             case GI_TYPE_TAG_FILENAME:
diff --git a/test/js/testGIMarshalling.js b/test/js/testGIMarshalling.js
index 4a7c355..5b10c3c 100644
--- a/test/js/testGIMarshalling.js
+++ b/test/js/testGIMarshalling.js
@@ -1,4 +1,17 @@
 // application/javascript;version=1.8
+
+if (!('assertEquals' in this)) { /* allow running this test standalone */
+    imports.lang.copyPublicProperties(imports.jsUnit, this);
+    gjstestRun = function() { return imports.jsUnit.gjstestRun(window); };
+}
+
+function assertArrayEquals(expected, got) {
+    assertEquals(expected.length, got.length);
+    for (let i = 0; i < expected.length; i ++) {
+        assertEquals(expected[i], got[i]);
+    }
+}
+
 const GIMarshallingTests = imports.gi.GIMarshallingTests;
 
 // We use Gio to have some objects that we know exist
@@ -158,24 +171,34 @@ function testByteArray() {
 }
 
 function testPtrArray() {
-    function arrayEqual(ref, val) {
-	assertEquals(ref.length, val.length);
-	for (i = 0; i < ref.length; i++)
-	    assertEquals(ref[i], val[i]);
-    }
     var array;
 
     GIMarshallingTests.gptrarray_utf8_none_in(["0", "1", "2"]);
 
     var refArray = ["0", "1", "2"];
 
-    arrayEqual(refArray, GIMarshallingTests.gptrarray_utf8_none_return());
-    arrayEqual(refArray, GIMarshallingTests.gptrarray_utf8_container_return());
-    arrayEqual(refArray, GIMarshallingTests.gptrarray_utf8_full_return());
+    assertArrayEquals(refArray, GIMarshallingTests.gptrarray_utf8_none_return());
+    assertArrayEquals(refArray, GIMarshallingTests.gptrarray_utf8_container_return());
+    assertArrayEquals(refArray, GIMarshallingTests.gptrarray_utf8_full_return());
+
+    assertArrayEquals(refArray, GIMarshallingTests.gptrarray_utf8_none_out());
+    assertArrayEquals(refArray, GIMarshallingTests.gptrarray_utf8_container_out());
+    assertArrayEquals(refArray, GIMarshallingTests.gptrarray_utf8_full_out());
+}
+
+function testGValue() {
+    assertEquals(42, GIMarshallingTests.gvalue_return());
+    assertEquals(42, GIMarshallingTests.gvalue_out());
+
+    GIMarshallingTests.gvalue_in(42);
+    GIMarshallingTests.gvalue_flat_array([42, "42", true]);
+
+    // gjs doesn't support native enum types
+    // GIMarshallingTests.gvalue_in_enum(GIMarshallingTests.Enum.VALUE_3);
 
-    arrayEqual(refArray, GIMarshallingTests.gptrarray_utf8_none_out());
-    arrayEqual(refArray, GIMarshallingTests.gptrarray_utf8_container_out());
-    arrayEqual(refArray, GIMarshallingTests.gptrarray_utf8_full_out());
+    // Test a flat GValue round-trip return
+    let thing = GIMarshallingTests.return_gvalue_flat_array();
+    assertArrayEquals([42, "42", true], thing);
 }
 
 gjstestRun();



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