[gjs/5-replace-bytearray-with-native-es6-typedarray] byteArray: Add backwards-compatible ByteArray class



commit 7029ef2a45561db649f5c519e1a0e4dbca126733
Author: Philip Chimento <philip chimento gmail com>
Date:   Mon Oct 30 11:09:04 2017 -0700

    byteArray: Add backwards-compatible ByteArray class
    
    This should make it easier to keep old code working. It adds a legacy
    ByteArray.ByteArray class that works just like the old ByteArray class
    but uses Uint8Array internally. However, it is not zero-copy.
    
    https://gitlab.gnome.org/GNOME/gjs/issues/5

 Makefile-test.am                          |   1 +
 NEWS                                      |  14 +++-
 installed-tests/js/testByteArray.js       |   6 --
 installed-tests/js/testLegacyByteArray.js | 115 ++++++++++++++++++++++++++++++
 modules/byteArray.js                      |  57 +++++++++++++--
 modules/overrides/GLib.js                 |   4 +-
 6 files changed, 182 insertions(+), 15 deletions(-)
---
diff --git a/Makefile-test.am b/Makefile-test.am
index 5ea78ad..4315b42 100644
--- a/Makefile-test.am
+++ b/Makefile-test.am
@@ -204,6 +204,7 @@ common_jstests_files =                                              \
        installed-tests/js/testGio.js                           \
        installed-tests/js/testImporter.js                      \
        installed-tests/js/testLang.js                          \
+       installed-tests/js/testLegacyByteArray.js               \
        installed-tests/js/testLegacyClass.js                   \
        installed-tests/js/testLegacyGObject.js                 \
        installed-tests/js/testLocale.js                        \
diff --git a/NEWS b/NEWS
index 810e7e5..ba156cc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,7 +4,19 @@ NEXT
 - Deprecation: the custom ByteArray is now discouraged. Instead of ByteArray,
   use Javascript's native Uint8Array. The ByteArray module still contains
   functions for converting between byte arrays, strings, and GLib.Bytes
-  instances. With a few exceptions, old code will continue to work.
+  instances.
+
+  The old ByteArray will continue to work as before, except that Uint8Array
+  will now be returned from introspected functions that previously returned a
+  ByteArray. To keep your old code working, change this:
+
+      let byteArray = functionThatReturnsByteArray();
+
+  to this:
+
+      let byteArray = new ByteArray.ByteArray(functionThatReturnsByteArray());
+
+  To port to the new code:
 
   * ByteArray.ByteArray -> Uint8Array
   * ByteArray.fromArray() -> Uint8Array.from()
diff --git a/installed-tests/js/testByteArray.js b/installed-tests/js/testByteArray.js
index 3e1ea2c..6746df4 100644
--- a/installed-tests/js/testByteArray.js
+++ b/installed-tests/js/testByteArray.js
@@ -25,12 +25,6 @@ describe('Byte array', function () {
         [0xe2, 0x85, 0x9c].forEach((val, ix) => expect(a[ix]).toEqual(val));
     });
 
-    it('can be created from an array', function () {
-        let a = ByteArray.fromArray([ 1, 2, 3, 4 ]);
-        expect(a.length).toEqual(4);
-        [1, 2, 3, 4].forEach((val, ix) => expect(a[ix]).toEqual(val));
-    });
-
     it('can be converted to a string of ASCII characters', function () {
         let a = new Uint8Array(4);
         a[0] = 97;
diff --git a/installed-tests/js/testLegacyByteArray.js b/installed-tests/js/testLegacyByteArray.js
new file mode 100644
index 0000000..ed1b8c3
--- /dev/null
+++ b/installed-tests/js/testLegacyByteArray.js
@@ -0,0 +1,115 @@
+const ByteArray = imports.byteArray;
+const GIMarshallingTests = imports.gi.GIMarshallingTests;
+
+describe('Legacy byte array', function () {
+    it('has length 0 for empty array', function () {
+        let a = new ByteArray.ByteArray();
+        expect(a.length).toEqual(0);
+    });
+
+    describe('initially sized to 10', function () {
+        let a;
+        beforeEach(function () {
+            a = new ByteArray.ByteArray(10);
+        });
+
+        it('has length 10', function () {
+            expect(a.length).toEqual(10);
+        });
+
+        it('is initialized to zeroes', function () {
+            for (let i = 0; i < a.length; ++i) {
+                expect(a[i]).toEqual(0);
+            }
+        });
+    });
+
+    it('assigns values correctly', function () {
+        let a = new ByteArray.ByteArray(256);
+
+        for (let i = 0; i < a.length; ++i) {
+            a[i] = 255 - i;
+        }
+
+        for (let i = 0; i < a.length; ++i) {
+            expect(a[i]).toEqual(255 - i);
+        }
+    });
+
+    describe('assignment past end', function () {
+        let a;
+        beforeEach(function () {
+            a = new ByteArray.ByteArray();
+            a[2] = 5;
+        });
+
+        it('implicitly lengthens the array', function () {
+            expect(a.length).toEqual(3);
+            expect(a[2]).toEqual(5);
+        });
+
+        it('implicitly creates zero bytes', function () {
+            expect(a[0]).toEqual(0);
+            expect(a[1]).toEqual(0);
+        });
+    });
+
+    it('changes the length when assigning to length property', function () {
+        let a = new ByteArray.ByteArray(20);
+        expect(a.length).toEqual(20);
+        a.length = 5;
+        expect(a.length).toEqual(5);
+    });
+
+
+    describe('conversions', function () {
+        let a;
+        beforeEach(function () {
+            a = new ByteArray.ByteArray();
+            a[0] = 255;
+        });
+
+        it('gives a byte 5 when assigning 5', function () {
+            a[0] = 5;
+            expect(a[0]).toEqual(5);
+        });
+
+        it('gives a byte 0 when assigning null', function () {
+            a[0] = null;
+            expect(a[0]).toEqual(0);
+        });
+
+        it('gives a byte 0 when assigning undefined', function () {
+            a[0] = undefined;
+            expect(a[0]).toEqual(0);
+        });
+
+        it('rounds off when assigning a double', function () {
+            a[0] = 3.14;
+            expect(a[0]).toEqual(3);
+        });
+    });
+
+    it('can be created from an array', function () {
+        let a = ByteArray.fromArray([ 1, 2, 3, 4 ]);
+        expect(a.length).toEqual(4);
+        [1, 2, 3, 4].forEach((val, ix) => expect(a[ix]).toEqual(val));
+    });
+
+    it('can be converted to a string of ASCII characters', function () {
+        let a = new ByteArray.ByteArray(4);
+        a[0] = 97;
+        a[1] = 98;
+        a[2] = 99;
+        a[3] = 100;
+        let s = a.toString();
+        expect(s.length).toEqual(4);
+        expect(s).toEqual('abcd');
+    });
+
+    it('can be passed in with transfer none', function () {
+        const refByteArray = ByteArray.fromArray([0, 49, 0xFF, 51]);
+        expect(() => GIMarshallingTests.bytearray_none_in(refByteArray))
+            .not.toThrow();
+    });
+});
diff --git a/modules/byteArray.js b/modules/byteArray.js
index b12a001..dcd8e2e 100644
--- a/modules/byteArray.js
+++ b/modules/byteArray.js
@@ -5,15 +5,58 @@ var {fromGBytes, fromString, toGBytes, toString} = imports._byteArrayNative;
 // For backwards compatibility
 
 function fromArray(a) {
-    return Uint8Array.from(a);
+    return new ByteArray(Uint8Array.from(a));
 }
 
-var ByteArray = Uint8Array;
+var ByteArray = class ByteArray {
+    constructor(arg=0) {
+        if (arg instanceof Uint8Array)
+            this._array = arg;
+        else
+            this._array = new Uint8Array(arg);
+        return new Proxy(this, ByteArray);
+    }
 
-Uint8Array.prototype.toString = function (encoding='UTF-8') {
-    return toString(this, encoding);
-};
+    static get(target, prop, receiver) {
+        if (!Number.isNaN(Number.parseInt(prop)))
+            return Reflect.get(target._array, prop);
+        return Reflect.get(target, prop, receiver);
+    }
+
+    static set(target, prop, val, receiver) {
+        let ix = Number.parseInt(prop);
+        if (!Number.isNaN(ix)) {
+            if (ix >= target._array.length) {
+                let newArray = new Uint8Array(ix + 1);
+                newArray.set(target._array);
+                target._array = newArray;
+            }
+            return Reflect.set(target._array, prop, val);
+        }
+        return Reflect.set(target, prop, val, receiver);
+    }
+
+    get length() {
+        return this._array.length;
+    }
+
+    set length(newLength) {
+        if (newLength === this._array.length)
+            return;
+        if (newLength < this._array.length) {
+            this._array = new Uint8Array(this._array.buffer, 0, newLength);
+            return;
+        }
+        let newArray = new Uint8Array(newLength);
+        newArray.set(this._array);
+        this._array = newArray;
+    }
+
+    toString(encoding='UTF-8') {
+        return toString(this._array, encoding);
+    }
 
-Uint8Array.prototype.toGBytes = function () {
-    return toGBytes(this);
+    toGBytes() {
+        return toGBytes(this._array);
+    }
 };
diff --git a/modules/overrides/GLib.js b/modules/overrides/GLib.js
index ee50560..0fdaf3d 100644
--- a/modules/overrides/GLib.js
+++ b/modules/overrides/GLib.js
@@ -18,6 +18,8 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
+const ByteArray = imports.byteArray;
+
 let GLib;
 let originalVariantClass;
 
@@ -66,7 +68,7 @@ function _read_single_type(signature, forceSimple) {
 }
 
 function _makeBytes(byteArray) {
-    if (byteArray instanceof Uint8Array)
+    if (byteArray instanceof Uint8Array || byteArray instanceof ByteArray.ByteArray)
         return byteArray.toGBytes();
     else
         return new GLib.Bytes(byteArray);


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