[gjs: 2/3] arg: Support flat arrays of structs
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs: 2/3] arg: Support flat arrays of structs
- Date: Wed, 20 Nov 2019 01:51:43 +0000 (UTC)
commit faaa4221aaa15fb7542cd56c84b3b0187ea0bd88
Author: Philip Chimento <philip chimento gmail com>
Date: Sat Oct 26 15:57:34 2019 -0700
arg: Support flat arrays of structs
This is actually possible without a cleanup list, contrary to what was
previously asserted in #44.
It's possible to pass a flat array of C data if the array element type
is a struct or union not registered as a boxed type. In this case,
g_type_info_get_pointer() will be false for the GI info of the function
argument. We detect this case and create a flat array where the structs
are copied by value.
We preserve the existing special case for flat GValue arrays, since we
need to use gjs_value_to_g_value() there instead of
gjs_value_to_g_argument(), and doing both in the same function would
make the code less readable.
See #44.
gi/arg.cpp | 66 +++++++++++++++++++++++++++++++++++----
installed-tests/js/testRegress.js | 8 ++---
2 files changed, 64 insertions(+), 10 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index d5539d52..aa3efc41 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -930,6 +930,50 @@ gjs_array_to_ptrarray(JSContext *context,
return true;
}
+GJS_JSAPI_RETURN_CONVENTION
+static bool gjs_array_to_flat_struct_array(JSContext* cx,
+ JS::HandleValue array_value,
+ unsigned length,
+ GITypeInfo* param_info,
+ GIBaseInfo* interface_info,
+ GIInfoType info_type, void** arr_p) {
+ g_assert(
+ (info_type == GI_INFO_TYPE_STRUCT || info_type == GI_INFO_TYPE_UNION) &&
+ "Only flat arrays of unboxed structs or unions are supported");
+ size_t struct_size;
+ if (info_type == GI_INFO_TYPE_UNION)
+ struct_size = g_union_info_get_size(interface_info);
+ else
+ struct_size = g_struct_info_get_size(interface_info);
+
+ GjsAutoPointer<uint8_t, void, g_free> flat_array =
+ g_new0(uint8_t, struct_size * length);
+
+ JS::RootedObject array(cx, &array_value.toObject());
+ JS::RootedValue elem(cx);
+ for (unsigned i = 0; i < length; i++) {
+ elem = JS::UndefinedValue();
+
+ if (!JS_GetElement(cx, array, i, &elem)) {
+ gjs_throw(cx, "Missing array element %u", i);
+ return false;
+ }
+
+ GIArgument arg;
+ if (!gjs_value_to_g_argument(cx, elem, param_info,
+ /* arg_name = */ nullptr,
+ GJS_ARGUMENT_ARRAY_ELEMENT,
+ GI_TRANSFER_NOTHING,
+ /* may_be_null = */ false, &arg))
+ return false;
+
+ memcpy(&flat_array[struct_size * i], arg.v_pointer, struct_size);
+ }
+
+ *arr_p = flat_array.release();
+ return true;
+}
+
GJS_JSAPI_RETURN_CONVENTION
static bool
gjs_array_to_flat_gvalue_array(JSContext *context,
@@ -1116,18 +1160,17 @@ static bool gjs_array_to_array(JSContext* context, JS::HandleValue array_value,
/* Everything else is a pointer type */
case GI_TYPE_TAG_INTERFACE:
- // Flat arrays of structures are not supported yet; see
- // https://gitlab.gnome.org/GNOME/gjs/issues/44
if (!g_type_info_is_pointer(param_info)) {
GjsAutoBaseInfo interface_info =
g_type_info_get_interface(param_info);
GIInfoType info_type = g_base_info_get_type(interface_info);
if (info_type == GI_INFO_TYPE_STRUCT ||
info_type == GI_INFO_TYPE_UNION) {
- gjs_throw(context,
- "Flat array of type %s is not currently supported",
- interface_info.name());
- return false;
+ // Ignore transfer in the case of a flat struct array. Structs
+ // are copied by value.
+ return gjs_array_to_flat_struct_array(
+ context, array_value, length, param_info, interface_info,
+ info_type, arr_p);
}
}
/* fall through */
@@ -3352,6 +3395,17 @@ gjs_g_arg_release_internal(JSContext *context,
break;
case GI_TYPE_TAG_INTERFACE:
+ if (!g_type_info_is_pointer(param_info)) {
+ GjsAutoBaseInfo interface_info =
+ g_type_info_get_interface(param_info);
+ GIInfoType info_type = g_base_info_get_type(interface_info);
+ if (info_type == GI_INFO_TYPE_STRUCT ||
+ info_type == GI_INFO_TYPE_UNION) {
+ g_free(arg->v_pointer);
+ break;
+ }
+ }
+ /* fall through */
case GI_TYPE_TAG_GLIST:
case GI_TYPE_TAG_GSLIST:
case GI_TYPE_TAG_ARRAY:
diff --git a/installed-tests/js/testRegress.js b/installed-tests/js/testRegress.js
index f30539b2..1aa60e9b 100644
--- a/installed-tests/js/testRegress.js
+++ b/installed-tests/js/testRegress.js
@@ -1590,16 +1590,16 @@ describe('Life, the Universe and Everything', function () {
expect(Regress.test_array_struct_out_caller_alloc()).toEqual([]);
}).pend('Not supported');
- xit('transfer-full in parameter', function () {
+ it('transfer-full in parameter', function () {
const array = [201, 202].map(some_int =>
new Regress.TestStructA({some_int}));
expect(() => Regress.test_array_struct_in_full(array)).not.toThrow();
- }).pend('https://gitlab.gnome.org/GNOME/gjs/issues/44');
+ });
- xit('transfer-none in parameter', function () {
+ it('transfer-none in parameter', function () {
const array = [301, 302, 303].map(some_int =>
new Regress.TestStructA({some_int}));
expect(() => Regress.test_array_struct_in_none(array)).not.toThrow();
- }).pend('https://gitlab.gnome.org/GNOME/gjs/issues/44');
+ });
});
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]