[gjs/wip/carlosg/arrays-in-signals: 40/41] value: Introspect element-type in arrays




commit 386f19d6841bde9af0acfff5933c857b33ea19d6
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   | 32 ++++++++++++++++++++++++++++++++
 gi/arg.h     |  4 ++++
 gi/value.cpp | 26 ++++++++++++++++++++++++--
 3 files changed, 60 insertions(+), 2 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index a1f393aa..23620448 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -2160,6 +2160,38 @@ gjs_array_from_boxed_array (JSContext             *context,
                                           param_info, length, data);
 }
 
+GJS_JSAPI_RETURN_CONVENTION
+bool gjs_array_from_g_value_array(JSContext* cx, JS::MutableHandleValue value_p,
+                                  GITypeInfo* param_info,
+                                  const GValue* gvalue) {
+    void* data = nullptr;
+    size_t 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;
+        auto* array = reinterpret_cast<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;
+        auto* ptr_array =
+            reinterpret_cast<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(cx, 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..c81c2979 100644
--- a/gi/arg.h
+++ b/gi/arg.h
@@ -123,4 +123,8 @@ 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* cx, 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 67e8f85c..fea7f9da 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -847,10 +847,32 @@ 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) ||
-               g_type_is_a(gtype, G_TYPE_ARRAY) ||
+    } else if (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)) {
+        if (!signal_query) {
+            gjs_throw(context, "Can't convert untyped array to JS value");
+            return false;
+        }
+
+        GISignalInfo* 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]