276 lines
9.6 KiB
Diff
276 lines
9.6 KiB
Diff
|
From 89453931bf6743049644274fc730a10e7bd2a53d Mon Sep 17 00:00:00 2001
|
||
|
From: Michael Gratton <mike@vee.net>
|
||
|
Date: Fri, 28 Aug 2020 11:20:27 +1000
|
||
|
Subject: [PATCH 074/124] 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 d2ce9f2e..095f9da4 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 16a01d83..f1da043d 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>}"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.29.2
|
||
|
|