[gjs: 1/3] GLib: add GLib.Variant.recursiveUnpack()



commit 979e28ddbdad8e5eea803c099d16a022fe36457f
Author: Philip Chimento <philip chimento gmail com>
Date:   Fri Aug 2 17:45:31 2019 -0700

    GLib: add GLib.Variant.recursiveUnpack()
    
    This function is useful if you want to entirely unpack a GVariant into
    a JS object, and you don't care about any type information contained in
    any 'v' elements. (This is a common case when unpacking 'a{sv}'
    dictionaries from DBus.)
    
    Based on code by Fabian Orccon <cfoch fabian gmail com>
    
    Closes: GNOME/gjs#225

 installed-tests/js/testGLib.js | 16 ++++++++++++++++
 modules/overrides/GLib.js      | 23 +++++++++++++++++------
 2 files changed, 33 insertions(+), 6 deletions(-)
---
diff --git a/installed-tests/js/testGLib.js b/installed-tests/js/testGLib.js
index 66b7afb9..cd7f6ec0 100644
--- a/installed-tests/js/testGLib.js
+++ b/installed-tests/js/testGLib.js
@@ -71,6 +71,22 @@ describe('GVariant constructor', function () {
     });
 });
 
+describe('GVariant unpack', function () {
+    let v;
+    beforeEach(function () {
+        v = new GLib.Variant('a{sv}', {foo: new GLib.Variant('s', 'bar')});
+    });
+
+    it('preserves type information if the unpacked object contains variants', function () {
+        expect(v.deep_unpack().foo instanceof GLib.Variant).toBeTruthy();
+    });
+
+    it('recursive leaves no variants in the unpacked object', function () {
+        expect(v.recursiveUnpack().foo instanceof GLib.Variant).toBeFalsy();
+        expect(v.recursiveUnpack().foo).toEqual('bar');
+    });
+});
+
 describe('GVariantDict lookup', function () {
     let variantDict;
     beforeEach(function () {
diff --git a/modules/overrides/GLib.js b/modules/overrides/GLib.js
index e57555da..5b46bf12 100644
--- a/modules/overrides/GLib.js
+++ b/modules/overrides/GLib.js
@@ -178,7 +178,7 @@ function _pack_variant(signature, value) {
     }
 }
 
-function _unpack_variant(variant, deep) {
+function _unpack_variant(variant, deep, recursive = false) {
     switch (String.fromCharCode(variant.classify())) {
     case 'b':
        return variant.get_boolean();
@@ -205,12 +205,16 @@ function _unpack_variant(variant, deep) {
     case 's':
        // g_variant_get_string has length as out argument
        return variant.get_string()[0];
-    case 'v':
-       return variant.get_variant();
+    case 'v': {
+        const ret = variant.get_variant();
+        if (deep && recursive && ret instanceof GLib.Variant)
+            return _unpack_variant(ret, deep, recursive);
+        return ret;
+    }
     case 'm':
        let val = variant.get_maybe();
        if (deep && val)
-           return _unpack_variant(val, deep);
+            return _unpack_variant(val, deep, recursive);
        else
            return val;
     case 'a':
@@ -221,7 +225,8 @@ function _unpack_variant(variant, deep) {
            for (let i = 0; i < nElements; i++) {
                // always unpack the dictionary entry, and always unpack
                // the key (or it cannot be added as a key)
-               let val = _unpack_variant(variant.get_child_value(i), deep);
+                let val = _unpack_variant(variant.get_child_value(i), deep,
+                    recursive);
                let key;
                if (!deep)
                    key = _unpack_variant(val[0], true);
@@ -244,7 +249,7 @@ function _unpack_variant(variant, deep) {
        for (let i = 0; i < nElements; i++) {
            let val = variant.get_child_value(i);
            if (deep)
-               ret.push(_unpack_variant(val, deep));
+                ret.push(_unpack_variant(val, deep, recursive));
            else
                ret.push(val);
        }
@@ -284,6 +289,12 @@ function _init() {
     this.Variant.prototype.deep_unpack = function() {
        return _unpack_variant(this, true);
     };
+
+    // Note: discards type information, if the variant contains any 'v' types
+    this.Variant.prototype.recursiveUnpack = function () {
+        return _unpack_variant(this, true, true);
+    };
+
     this.Variant.prototype.toString = function() {
        return '[object variant of type "' + this.get_type_string() + '"]';
     };


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