msgpackr 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/test.js CHANGED
@@ -120,10 +120,10 @@
120
120
  let size = source.length;
121
121
  let value = this ? this.unpack(source, size) : defaultUnpackr.unpack(source, size);
122
122
  if (forEach) {
123
- if (forEach(value) === false) return;
123
+ if (forEach(value, lastPosition, position$1) === false) return;
124
124
  while(position$1 < size) {
125
125
  lastPosition = position$1;
126
- if (forEach(checkedRead()) === false) {
126
+ if (forEach(checkedRead(), lastPosition, position$1) === false) {
127
127
  return
128
128
  }
129
129
  }
@@ -197,6 +197,10 @@
197
197
  position$1 = bundledStrings$1.postBundlePosition;
198
198
  bundledStrings$1 = null;
199
199
  }
200
+ if (sequentialMode)
201
+ // we only need to restore the structures if there was an error, but if we completed a read,
202
+ // we can clear this out and keep the structures we read
203
+ currentStructures.restoreStructures = null;
200
204
 
201
205
  if (position$1 == srcEnd) {
202
206
  // finished reading this source, cleanup references
@@ -967,7 +971,10 @@
967
971
  structure.highByte = highByte;
968
972
  }
969
973
  let existingStructure = currentStructures[id];
970
- if (existingStructure && existingStructure.isShared) {
974
+ // If it is a shared structure, we need to restore any changes after reading.
975
+ // Also in sequential mode, we may get incomplete reads and thus errors, and we need to restore
976
+ // to the state prior to an incomplete read in order to properly resume.
977
+ if (existingStructure && (existingStructure.isShared || sequentialMode)) {
971
978
  (currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure;
972
979
  }
973
980
  currentStructures[id] = structure;
@@ -977,10 +984,10 @@
977
984
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
978
985
  currentExtensions[0].noBuffer = true;
979
986
 
980
- let glbl = typeof globalThis === 'object' ? globalThis : window;
987
+ let errors = { Error, TypeError, ReferenceError };
981
988
  currentExtensions[0x65] = () => {
982
989
  let data = read();
983
- return (glbl[data[0]] || Error)(data[1])
990
+ return (errors[data[0]] || Error)(data[1])
984
991
  };
985
992
 
986
993
  currentExtensions[0x69] = (data) => {
@@ -1018,6 +1025,7 @@
1018
1025
 
1019
1026
  const typedArrays = ['Int8','Uint8','Uint8Clamped','Int16','Uint16','Int32','Uint32','Float32','Float64','BigInt64','BigUint64'].map(type => type + 'Array');
1020
1027
 
1028
+ let glbl = typeof globalThis === 'object' ? globalThis : window;
1021
1029
  currentExtensions[0x74] = (data) => {
1022
1030
  let typeCode = data[0];
1023
1031
  let typedArrayName = typedArrays[typeCode];
@@ -1314,7 +1322,7 @@
1314
1322
  if (serializationsSinceTransitionRebuild < 10)
1315
1323
  serializationsSinceTransitionRebuild++;
1316
1324
  let sharedLength = structures.sharedLength || 0;
1317
- if (structures.length > sharedLength)
1325
+ if (structures.length > sharedLength && !isSequential)
1318
1326
  structures.length = sharedLength;
1319
1327
  if (transitionsCount > 10000) {
1320
1328
  // force a rebuild occasionally after a lot of transitions so it can get cleaned up
@@ -1522,7 +1530,7 @@
1522
1530
  targetView.setFloat64(position, value);
1523
1531
  position += 8;
1524
1532
  }
1525
- } else if (type === 'object') {
1533
+ } else if (type === 'object' || type === 'function') {
1526
1534
  if (!value)
1527
1535
  target[position++] = 0xc0;
1528
1536
  else {
@@ -1629,6 +1637,11 @@
1629
1637
  } else {
1630
1638
  if (value.toJSON) // use this as an alternate mechanism for expressing how to serialize
1631
1639
  return pack(value.toJSON());
1640
+
1641
+ // if there is a writeFunction, use it, otherwise just encode as undefined
1642
+ if (type === 'function')
1643
+ return pack(this.writeFunction && this.writeFunction(value));
1644
+
1632
1645
  // no extension found, write as object
1633
1646
  writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1634
1647
  }
@@ -1663,14 +1676,12 @@
1663
1676
  target[position++] = 0;
1664
1677
  target[position++] = 0;
1665
1678
  }
1666
- } else if (type === 'function') {
1667
- pack(this.writeFunction && this.writeFunction()); // if there is a writeFunction, use it, otherwise just encode as undefined
1668
1679
  } else {
1669
1680
  throw new Error('Unknown type: ' + type)
1670
1681
  }
1671
1682
  };
1672
1683
 
1673
- const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
1684
+ const writePlainObject = this.variableMapSize ? (object) => {
1674
1685
  // this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
1675
1686
  let keys = Object.keys(object);
1676
1687
  let length = keys.length;
@@ -1705,7 +1716,9 @@
1705
1716
  }
1706
1717
  target[objectOffset++ + start] = size >> 8;
1707
1718
  target[objectOffset + start] = size & 0xff;
1708
- } :
1719
+ };
1720
+
1721
+ const writeRecord = this.useRecords === false ? writePlainObject :
1709
1722
  (options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
1710
1723
  (object, safePrototype) => {
1711
1724
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
@@ -1777,6 +1790,14 @@
1777
1790
  if (safePrototype || object.hasOwnProperty(key))
1778
1791
  pack(object[key]);
1779
1792
  };
1793
+
1794
+ // craete reference to useRecords if useRecords is a function
1795
+ const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
1796
+
1797
+ const writeObject = checkUseRecords ? (object, safePrototype) => {
1798
+ checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
1799
+ } : writeRecord;
1800
+
1780
1801
  const makeRoom = (end) => {
1781
1802
  let newSize;
1782
1803
  if (end > 0x1000000) {
@@ -1949,7 +1970,10 @@
1949
1970
  }
1950
1971
  }, {
1951
1972
  pack(set, allocateForWrite, pack) {
1952
- if (this.setAsEmptyObject) return pack({})
1973
+ if (this.setAsEmptyObject) {
1974
+ allocateForWrite(0);
1975
+ return pack({})
1976
+ }
1953
1977
  let array = Array.from(set);
1954
1978
  let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
1955
1979
  if (this.moreTypes) {
@@ -3053,7 +3077,6 @@
3053
3077
  var deserialized = packr.unpack(serialized);
3054
3078
  assert.deepEqual(deserialized, data);
3055
3079
  });
3056
-
3057
3080
  test('255 chars', function () {
3058
3081
  const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W';
3059
3082
  var serialized = pack(data);
@@ -3152,6 +3175,44 @@
3152
3175
  });
3153
3176
  }
3154
3177
 
3178
+ test('pack/unpack sample data with useRecords function', function () {
3179
+ var data = [
3180
+ {id: 1, type: 1, labels: {a: 1, b: 2}},
3181
+ {id: 2, type: 1, labels: {b: 1, c: 2}},
3182
+ {id: 3, type: 1, labels: {d: 1, e: 2}}
3183
+ ];
3184
+
3185
+ var alternatives = [
3186
+ {useRecords: false}, // 88 bytes
3187
+ {useRecords: true}, // 58 bytes
3188
+ {mapsAsObjects: true, useRecords: (v)=>!!v.id}, // 55 bytes
3189
+ {mapsAsObjects: true, variableMapSize: true, useRecords: (v)=>!!v.id} // 49 bytes
3190
+ ];
3191
+
3192
+ for(let o of alternatives) {
3193
+ let packr = new Packr(o);
3194
+ var serialized = packr.pack(data);
3195
+ var deserialized = packr.unpack(serialized);
3196
+ assert.deepEqual(deserialized, data);
3197
+ }
3198
+ });
3199
+
3200
+ test('mapAsEmptyObject combination', function () {
3201
+ const msgpackr = new Packr({ useRecords: false, encodeUndefinedAsNil: true, variableMapSize: true, mapAsEmptyObject: true, setAsEmptyObject: true });
3202
+
3203
+ const map = new Map();
3204
+ map.set('a', 1);
3205
+ map.set('b', 2);
3206
+ const set = new Set();
3207
+ set.add('a');
3208
+ set.add('b');
3209
+ const input = { map, set };
3210
+
3211
+ const packed = msgpackr.pack(input);
3212
+ const unpacked = msgpackr.unpack(packed);
3213
+ assert.deepEqual(unpacked.map, {});
3214
+ assert.deepEqual(unpacked.set, {});
3215
+ });
3155
3216
  test('pack/unpack empty data with bundled strings', function () {
3156
3217
  var data = {};
3157
3218
  let packr = new Packr({bundleStrings: true});
@@ -3312,7 +3373,6 @@
3312
3373
  assert.deepEqual(data, deserialized);
3313
3374
  });
3314
3375
 
3315
-
3316
3376
  test('unregistered extended Array class read/write', function(){
3317
3377
  var instance = new ExtendArray2();
3318
3378
  instance.push(0);
@@ -3465,6 +3525,58 @@
3465
3525
  assert.equal(deserialized.extendedInstance[0], 0);
3466
3526
  });
3467
3527
 
3528
+ test('extended class pack/unpack proxied', function(){
3529
+ function Extended() {
3530
+
3531
+ }
3532
+ Extended.prototype.__call__ = function(){
3533
+ return this.value * 4
3534
+ };
3535
+ Extended.prototype.getDouble = function() {
3536
+ return this.value * 2
3537
+ };
3538
+
3539
+ var instance = function() { instance.__call__();/* callable stuff */ };
3540
+ Object.setPrototypeOf(instance,Extended.prototype);
3541
+
3542
+ instance.value = 4;
3543
+ var data = instance;
3544
+
3545
+ let packr = new Packr();
3546
+ addExtension({
3547
+ Class: Extended,
3548
+ type: 15,
3549
+ unpack: function(buffer) {
3550
+ var e = function() { e.__call__(); };
3551
+ Object.setPrototypeOf(e,Extended.prototype);
3552
+ e.value = packr.unpack(buffer);
3553
+ return e
3554
+ },
3555
+ pack: function(instance) {
3556
+ return packr.pack(instance.value)
3557
+ }
3558
+ });
3559
+ var serialized = pack(data);
3560
+ var deserialized = unpack(serialized);
3561
+ assert.equal(deserialized.getDouble(), 8);
3562
+ });
3563
+
3564
+ test.skip('convert Date to string', function(){
3565
+ var data = {
3566
+ aDate: new Date(),
3567
+ };
3568
+ new Packr();
3569
+ addExtension({
3570
+ Class: Date,
3571
+ write(date) {
3572
+ return date.toString()
3573
+ }
3574
+ });
3575
+ var serialized = pack(data);
3576
+ var deserialized = unpack(serialized);
3577
+ assert.equal(deserialized.aDate, data.aDate.toString());
3578
+ });
3579
+
3468
3580
  test('proto handling', function() {
3469
3581
  var objectWithProto = JSON.parse('{"__proto__":{"foo":3}}');
3470
3582
  var decoded = unpack(pack(objectWithProto));
@@ -3961,6 +4073,14 @@
3961
4073
  assert.deepEqual(values, [1, 2, 3, 4]);
3962
4074
  });
3963
4075
 
4076
+ test('unpackMultiple with positions', () => {
4077
+ let values = unpackMultiple(new Uint8Array([1, 2, 3, 4]));
4078
+ assert.deepEqual(values, [1, 2, 3, 4]);
4079
+ values = [];
4080
+ unpackMultiple(new Uint8Array([1, 2, 3, 4]), (value,start,end) => values.push([value,start,end]));
4081
+ assert.deepEqual(values, [[1,0,1], [2,1,2], [3,2,3], [4,3,4]]);
4082
+ });
4083
+
3964
4084
  });
3965
4085
  suite('msgpackr performance tests', function(){
3966
4086
  test('performance JSON.parse', function() {