[gjs/wip/carlosg/arrays-in-signals: 1/2] value: Introspect element-type in arrays




commit 6914e06dc7d7b404df449b76ddd8af1a1029a347
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Feb 15 23:51:53 2021 +0100

    value: Introspect element-type in arrays
    
    Expose a helper function to convert array types from a
    GValue in place of a GIArgument, and use it when converting
    types for signal handlers.
    
    This should handle all byte/ptr/regular arrays, and all
    possible element-types contained inside.
    
    Fixes: https://gitlab.gnome.org/GNOME/gjs/-/issues/377

 gi/arg.cpp   | 35 +++++++++++++++++++++++++++++++++++
 gi/arg.h     |  6 ++++++
 gi/value.cpp | 28 +++++++++++++++++++++++++---
 3 files changed, 66 insertions(+), 3 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index a1f393aa..60efca56 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -2160,6 +2160,41 @@ gjs_array_from_boxed_array (JSContext             *context,
                                           param_info, length, data);
 }
 
+GJS_JSAPI_RETURN_CONVENTION
+bool
+gjs_array_from_g_value_array (JSContext             *context,
+                              JS::MutableHandleValue value_p,
+                              GITypeInfo            *param_info,
+                              const GValue          *gvalue)
+{
+    GArray *array;
+    GPtrArray *ptr_array;
+    gpointer data = NULL;
+    gsize length = 0;
+    GIArrayType array_type;
+    GType value_gtype = G_VALUE_TYPE (gvalue);
+
+    /* GByteArray is just a typedef for GArray internally */
+    if (g_type_is_a(value_gtype, G_TYPE_BYTE_ARRAY) ||
+        g_type_is_a(value_gtype, G_TYPE_ARRAY)) {
+        array_type = g_type_is_a(value_gtype, G_TYPE_BYTE_ARRAY) ?
+            GI_ARRAY_TYPE_BYTE_ARRAY : GI_ARRAY_TYPE_ARRAY;
+        array = (GArray*) g_value_get_boxed(gvalue);
+        data = array->data;
+        length = array->len;
+    } else if (g_type_is_a(value_gtype, G_TYPE_PTR_ARRAY)) {
+        array_type = GI_ARRAY_TYPE_PTR_ARRAY;
+        ptr_array = (GPtrArray*) g_value_get_boxed(gvalue);
+        data = ptr_array->pdata;
+        length = ptr_array->len;
+    } else {
+        g_assert_not_reached();
+    }
+
+    return gjs_array_from_carray_internal(context, value_p, array_type,
+                                          param_info, length, data);
+}
+
 template <typename T>
 GJS_JSAPI_RETURN_CONVENTION static bool fill_vector_from_zero_terminated_carray(
     JSContext* cx, JS::RootedValueVector& elems,  // NOLINT(runtime/references)
diff --git a/gi/arg.h b/gi/arg.h
index 90ea60fb..72a69c0a 100644
--- a/gi/arg.h
+++ b/gi/arg.h
@@ -123,4 +123,10 @@ bool gjs_array_to_strv (JSContext   *context,
                         unsigned int length,
                         void       **arr_p);
 
+GJS_JSAPI_RETURN_CONVENTION
+bool gjs_array_from_g_value_array (JSContext             *context,
+                                   JS::MutableHandleValue value_p,
+                                   GITypeInfo            *param_info,
+                                   const GValue          *gvalue);
+
 #endif  // GI_ARG_H_
diff --git a/gi/value.cpp b/gi/value.cpp
index 26a679f3..b83276c4 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -11,6 +11,7 @@
 #include <glib-object.h>
 #include <glib.h>
 
+#include <js/Array.h>
 #include <js/CharacterEncoding.h>
 #include <js/Conversions.h>
 #include <js/GCVector.h>  // for RootedVector
@@ -840,10 +841,31 @@ gjs_value_from_g_value_internal(JSContext             *context,
             gjs_throw(context, "Failed to convert strv to array");
             return false;
         }
-    } else if (g_type_is_a(gtype, G_TYPE_HASH_TABLE) ||
+    } else if (g_type_is_a(gtype, G_TYPE_PTR_ARRAY) ||
                g_type_is_a(gtype, G_TYPE_ARRAY) ||
-               g_type_is_a(gtype, G_TYPE_BYTE_ARRAY) ||
-               g_type_is_a(gtype, G_TYPE_PTR_ARRAY)) {
+               g_type_is_a(gtype, G_TYPE_BYTE_ARRAY)) {
+
+        GISignalInfo *signal_info;
+        signal_info = get_signal_info_if_available(signal_query);
+        if (!signal_info) {
+            gjs_throw(context, "Unknown signal.");
+            return false;
+        }
+
+        /* Look for element-type */
+        GITypeInfo type_info;
+        GIArgInfo *arg_info = g_callable_info_get_arg(signal_info, arg_n - 1);
+        g_arg_info_load_type(arg_info, &type_info);
+        GITypeInfo *element_info = g_type_info_get_param_type (&type_info, 0);
+
+        if (!gjs_array_from_g_value_array(context,
+                                          value_p,
+                                          element_info,
+                                          gvalue)) {
+            gjs_throw(context, "Failed to convert array");
+            return false;
+        }
+    } else if (g_type_is_a(gtype, G_TYPE_HASH_TABLE)) {
         gjs_throw(context,
                   "Unable to introspect element-type of container in GValue");
         return false;


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