[geary/mjog/558-webkit-shared-process-redux: 92/102] Util.Js: Improve JSC Value to GLib.Variant conversion




commit 89453931bf6743049644274fc730a10e7bd2a53d
Author: Michael Gratton <mike vee net>
Date:   Fri Aug 28 11:20:27 2020 +1000

    Util.Js: Improve JSC Value to GLib.Variant conversion
    
    Stop needlessly wrapping object members and array elements in
    variant variants.
    
    Don't wrap object values in variants since the code is already using
    vardicts for these. Return a variant array if a JS array contains values
    of all the same type and don't wrap these in variants, else return
    a tuple, which don't need to be wrapped either.

 src/client/util/util-js.vala       | 160 +++++++++++++++++++++++++++----------
 test/client/util/util-js-test.vala |  28 ++++++-
 2 files changed, 143 insertions(+), 45 deletions(-)
---
diff --git a/src/client/util/util-js.vala b/src/client/util/util-js.vala
index d2ce9f2ef..095f9da41 100644
--- a/src/client/util/util-js.vala
+++ b/src/client/util/util-js.vala
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017,2019 Michael James Gratton <mike vee net>
+ * Copyright © 2017-2020 Michael Gratton <mike vee net>
  *
  * This software is licensed under the GNU Lesser General Public License
  * (version 2.1 or later). See the COPYING file in this distribution.
@@ -25,6 +25,64 @@ namespace Util.JS {
         TYPE
     }
 
+    /** Supported types of JSC values. */
+    public enum JscType {
+
+        /** Specifies an unsupported value type. */
+        UNKNOWN,
+
+        /** Specifies a JavaScript `undefined` value. */
+        UNDEFINED,
+
+        /** Specifies a JavaScript `null` value. */
+        NULL,
+        FUNCTION,
+        STRING,
+        NUMBER,
+        BOOLEAN,
+        ARRAY,
+        CONSTRUCTOR,
+        OBJECT;
+
+        /**
+         * Determines the type of a JSC value.
+         *
+         * Returns the type of the given value, or {@link UNKNOWN} if
+         * it could not be determined.
+         */
+        public static JscType to_type(JSC.Value value) {
+            if (value.is_undefined()) {
+                return UNDEFINED;
+            }
+            if (value.is_null()) {
+                return NULL;
+            }
+            if (value.is_string()) {
+                return STRING;
+            }
+            if (value.is_number()) {
+                return NUMBER;
+            }
+            if (value.is_boolean()) {
+                return BOOLEAN;
+            }
+            if (value.is_array()) {
+                return ARRAY;
+            }
+            if (value.is_object()) {
+                return OBJECT;
+            }
+            if (value.is_function()) {
+                return FUNCTION;
+            }
+            if (value.is_constructor()) {
+                return CONSTRUCTOR;
+            }
+            return UNKNOWN;
+        }
+
+    }
+
     /**
      * Returns a JSC Value as a bool.
      *
@@ -132,60 +190,80 @@ namespace Util.JS {
      *
      * Simple value objects (string, number, and Boolean values),
      * arrays of these, and objects with these types as properties are
-     * supported. Arrays are converted to arrays of variants, and
-     * objects to dictionaries containing string keys and variant
-     * values. Null or undefined values are returned as an empty maybe
-     * variant type, since it is not possible to determine the actual
-     * type.
+     * supported. Arrays containing objects of the same type are
+     * converted to arrays, otherwise they are converted to tuples,
+     * empty arrays are converted to the unit tuple, and objects are
+     * converted to vardict containing property names as keys and
+     * values. Null and undefined values are returned as an empty
+     * maybe variant type, since it is not possible to determine the
+     * actual type.
      *
      * Throws a type error if the given value's type is not supported.
      */
     public inline GLib.Variant value_to_variant(JSC.Value value)
         throws Error {
-        if (value.is_null() || value.is_undefined()) {
-            return new GLib.Variant.maybe(GLib.VariantType.VARIANT, null);
-        }
-        if (value.is_boolean()) {
-            return new GLib.Variant.boolean(value.to_boolean());
-        }
-        if (value.is_number()) {
-            return new GLib.Variant.double(value.to_double());
-        }
-        if (value.is_string()) {
-            return new GLib.Variant.string(value.to_string());
-        }
-        if (value.is_array()) {
+        GLib.Variant? variant = null;
+        switch (JscType.to_type(value)) {
+        case UNDEFINED:
+        case NULL:
+            variant = new GLib.Variant.maybe(GLib.VariantType.VARIANT, null);
+            break;
+
+        case STRING:
+            variant = new GLib.Variant.string(value.to_string());
+            break;
+
+        case NUMBER:
+            variant = new GLib.Variant.double(value.to_double());
+            break;
+
+        case BOOLEAN:
+            variant = new GLib.Variant.boolean(value.to_boolean());
+            break;
+
+        case ARRAY:
             int len = to_int32(value.object_get_property("length"));
-            GLib.Variant[] values = new GLib.Variant[len];
-            for (int i = 0; i < len; i++) {
-                values[i] = new GLib.Variant.variant(
-                    value_to_variant(value.object_get_property_at_index(i))
-                );
+            if (len == 0) {
+                variant = new GLib.Variant.tuple({});
+            } else {
+                JSC.Value element = value.object_get_property_at_index(0);
+                var first_type = JscType.to_type(element);
+                var all_same_type = true;
+                var values = new GLib.Variant[len];
+                values[0] = value_to_variant(element);
+                for (int i = 1; i < len; i++) {
+                    element = value.object_get_property_at_index(i);
+                    values[i] = value_to_variant(element);
+                    all_same_type &= (first_type == JscType.to_type(element));
+                }
+                if (!all_same_type) {
+                    variant = new GLib.Variant.tuple(values);
+                } else {
+                    variant = new GLib.Variant.array(
+                        values[0].get_type(), values
+                    );
+                }
             }
-            return new GLib.Variant.array(GLib.VariantType.VARIANT, values);
-        }
-        if (value.is_object()) {
+            break;
+
+        case OBJECT:
             GLib.VariantDict dict = new GLib.VariantDict();
             string[] names = value.object_enumerate_properties();
             if (names != null) {
                 foreach (var name in names) {
-                    try {
-                        dict.insert_value(
-                            name,
-                            new GLib.Variant.variant(
-                                value_to_variant(
-                                    value.object_get_property(name)
-                                )
-                            )
-                        );
-                    } catch (Error.TYPE err) {
-                        // ignored
-                    }
+                    dict.insert_value(
+                        name,
+                        value_to_variant(value.object_get_property(name))
+                    );
                 }
             }
-            return dict.end();
+            variant = dict.end();
+            break;
+
+        default:
+            throw new Error.TYPE("Unsupported JS type: %s", value.to_string());
         }
-        throw new Error.TYPE("Unsupported JS type: %s", value.to_string());
+        return variant;
     }
 
     /**
diff --git a/test/client/util/util-js-test.vala b/test/client/util/util-js-test.vala
index 16a01d83d..f1da043d7 100644
--- a/test/client/util/util-js-test.vala
+++ b/test/client/util/util-js-test.vala
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Michael Gratton <mike vee net>
+ * Copyright © 2017-2020 Michael Gratton <mike vee net>
  *
  * This software is licensed under the GNU Lesser General Public License
  * (version 2.1 or later). See the COPYING file in this distribution.
@@ -61,15 +61,35 @@ public class Util.JS.Test : TestCase {
         var value = new JSC.Value.array_from_garray(this.context, null);
         assert_equal(
             value_to_variant(value).print(true),
-            "@av []"
+            "()"
         );
+
         var array = new GLib.GenericArray<JSC.Value>();
         array.add(new JSC.Value.string(this.context, "test"));
         value = new JSC.Value.array_from_garray(this.context, array);
         assert_equal(
             value_to_variant(value).print(true),
-            "[<'test'>]"
+            "['test']"
         );
+
+        array = new GLib.GenericArray<JSC.Value>();
+        array.add(new JSC.Value.string(this.context, "test1"));
+        array.add(new JSC.Value.string(this.context, "test2"));
+        value = new JSC.Value.array_from_garray(this.context, array);
+        assert_equal(
+            value_to_variant(value).print(true),
+            "['test1', 'test2']"
+        );
+
+        array = new GLib.GenericArray<JSC.Value>();
+        array.add(new JSC.Value.string(this.context, "test"));
+        array.add(new JSC.Value.boolean(this.context, true));
+        value = new JSC.Value.array_from_garray(this.context, array);
+        assert_equal(
+            value_to_variant(value).print(true),
+            "('test', true)"
+        );
+
         value = new JSC.Value.object(this.context, null, null);
         assert_equal(
             value_to_variant(value).print(true),
@@ -80,7 +100,7 @@ public class Util.JS.Test : TestCase {
         );
         assert_equal(
             value_to_variant(value).print(true),
-            "{'test': <<true>>}"
+            "{'test': <true>}"
         );
     }
 


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