summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2011-09-01 14:52:20 -0400
committerJasper St. Pierre <jstpierre@mecheye.net>2012-01-06 15:26:47 -0500
commit0688f72307596cd86e1f47a21a4ce73a865987f1 (patch)
treecc11624f2390f76d87e9b6817742e2e0ae91ad14
parentdc69b12d5e44f9d3b209759082f721237a8c9a06 (diff)
downloadgjs-0688f72307596cd86e1f47a21a4ce73a865987f1.tar.gz
Add support for flat GValue arrays
https://bugzilla.gnome.org/show_bug.cgi?id=657767
-rw-r--r--gi/arg.c128
-rw-r--r--test/js/testGIMarshalling.js45
2 files changed, 161 insertions, 12 deletions
diff --git a/gi/arg.c b/gi/arg.c
index 631c4165..a653d791 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 4a7c355f..5b10c3c6 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();